-2

Any idea why negative margins don't work on containers with clearfix applied?

Example: https://jsfiddle.net/tuotckk4/

.cf:after {
  content:"";
  display:block;
  clear:both;
}
.col {
  float: left;
  width: 50%;
  margin-bottom: 50px;
}
.wrapper {
  margin-bottom: -50px;
}
.wrapper-alt {
  margin-bottom: -50px;
  overflow: hidden;
}
<div class="wrapper cf">
  <div class="col">column 1</div>
  <div class="col">column 2</div>
  <div class="col">column 3</div>
  <div class="col">column 4</div>
</div>
<p>Something at bottom</p>
<hr />
<div class="wrapper-alt">
  <div class="col">column 1</div>
  <div class="col">column 2</div>
  <div class="col">column 3</div>
  <div class="col">column 4</div>
</div>
<p>Something at bottom</p>

In first example, negative margins of -50px have no effect. In the second example, using overflow: hidden it works just fine.

I know I can use overflow: hidden but I would like to know why the bottom margin on clearfix isn't working. Is it possible to make it work without using additional wrapper element?

Oriol
  • 274,082
  • 63
  • 437
  • 513
Sam
  • 41
  • 2

2 Answers2

0

It's more clear if you add a border:

p {
  border: 1px solid;
}
.cf:after {
  content:"";
  display:block;
  clear:both;
}
.col {
  float: left;
  width: 50%;
  margin-bottom: 50px;
}
.wrapper {
  margin-bottom: -50px;
}
.wrapper-alt {
  margin-bottom: -50px;
  overflow: hidden;
}
<div class="wrapper cf">
  <div class="col">column 1</div>
  <div class="col">column 2</div>
  <div class="col">column 3</div>
  <div class="col">column 4</div>
</div>
<p>Something at bottom</p>
<hr />
<div class="wrapper-alt">
  <div class="col">column 1</div>
  <div class="col">column 2</div>
  <div class="col">column 3</div>
  <div class="col">column 4</div>
</div>
<p>Something at bottom</p>

The paragraph does indeed go up because of the negative margin, but the text inside the paragraph doesn't.

That's because text can't overlap the margin box of a float:

the current and subsequent line boxes created next to the float are shortened as necessary to make room for the margin box of the float.

If you use overflow: hidden, you establish a new block formatting context. Floats only have effects inside the block formatting context in which they participate, so the paragraph is not affected.

There are other ways to establish new block formatting contexts, see Floating elements within a div, floats outside of div. Why?

Community
  • 1
  • 1
Oriol
  • 274,082
  • 63
  • 437
  • 513
0

In the first example, the p element box is indeed affected by the negative margin on the wrapper, but the text inside it is being pushed down due to the floating .col elements being cleared by the clearfix just preceding it.

This clearfix is also preventing the negative margin of the wrapper from collapsing with the p element — if you remove it, the entire wrapper gets shifted up, along with the p, making it seem as though a single negative margin between two elements was causing both elements to be shifted.

overflow: hidden causes the wrapper to establish a block formatting context, which isolates the floats without the need for a clearfix hack. This allows the p element to be affected by the negative margin on the wrapper without the floats getting in the way.

You can't really do this without a wrapper. Without one, the only other element you can give a negative margin is a negative top margin to the p itself, and when you do, it'll just collapse with the margin of whichever element its own top margin happens to be adjoining with (the floats are taken out of flow so they will never interrupt margin collapse).

Your best bet is to stick with using a wrapper with overflow: hidden. Your floats are unlikely to overflow your wrapper anyway, and it is by far the cleanest way to prevent floats from interfering with the rest of your layout (even if it is just as much of a hack as clearfix).

If all this sounds complicated to you, that's because it is. Using floats and negative margins together means you're going to be in for a world of hurt. Throw in a clearfix hack and things get even messier.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356