1

I'm trying to learn div positioning and css my question is why does blue square appear on top of red one when it is written below it and how to move it below red while red and green stay where they are.

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
  margin: 50px;
}

#red {
  background-color: red;
  float: left;
}

#green {
  background-color: green;
  float: right;
}

#blue {
  background-color: blue;
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>
zgood
  • 12,181
  • 2
  • 25
  • 26
  • 1
    @mtr.web thats not correct. floating blue left will pull it up to the right of red. – bcr May 03 '18 at 20:19
  • Possible duplicate of [CSS Float Logic](https://stackoverflow.com/questions/30858717/css-float-logic) – TylerH May 03 '18 at 21:22
  • @TylerH I hope it won't get closed for this question as it's not only float logic but more than this ;) – Temani Afif May 03 '18 at 22:55
  • @TemaniAfif I don't follow; this question is answered by explaining how CSS Floats work. That's what the accepted answer does pretty spectacularly on the question I linked. – TylerH May 04 '18 at 14:34
  • @TylerH but the accepted answer (unfortunately) didn't explain everything ... as there is margin-collapsing involved which make the behavior different from simple float behiavior. check my answer to see what I mean (especially the last snippet code) – Temani Afif May 04 '18 at 14:37

3 Answers3

3

Let's start by adding the different properties one by one. Initially if we don't set margin and float we will have the 3 box below each other like this:

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
}

#red {
  background-color: red;
}

#green {
  background-color: green;
}

#blue {
  background-color: blue;
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>

Until now the result is logical. Now let's add float to our elements:

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
}

#red {
  background-color: red;
  float: left;
}

#green {
  background-color: green;
  float: right;
}

#blue {
  background-color: blue;
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>

The green box is floated on the right (logical result) and the red box is floated on the left AND above the blue box so this one is hidden. This behavior is because:

The float CSS property specifies that an element should be placed along the left or right side of its container, allowing text and inline elements to wrap around it. The element is removed from the normal flow of the web page, though still remaining a part of the flowref

Since the blue box is a block element and belong to the same container it won't wrap around the floated element; thus the floated element (red box) will go above it.


Now let's add margin to the blue box (non-floated element)

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
}

#red {
  background-color: red;
  float:left;
}

#green {
  background-color: green;
  float:right;
}

#blue {
  background-color: blue;
  margin:50px;
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>

We see that all the elements are pushed down by 50px and the blue box pushed to the left by 50px.

Why this?

Here we are facing a margin-collapsing behavior with the blue box and body. So the margin-top of the blue box is collpased with the margin-top of body because the blue box is the first inflow child of the body; thus all the elements are pushed down since all of them are contained in the body. The blue box is logiaclly pushed from the left with the margin-left.

Now we add the margin to our floated element and these ones will be pushed from their previous position from top and left (for the red)/right (for the green):

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
    margin:50px;
}

#red {
  background-color: red;
  float:left;
}

#green {
  background-color: green;
  float:right;
}

#blue {
  background-color: blue;
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>

Now in order to avoid the behavior explained above you need to clear float and avoid marign-collapsing:

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
  margin:50px;
}

#red {
  background-color: red;
  float:left;
}

#green {
  background-color: green;
  float:right;
}

#blue {
  background-color: blue;
  clear:both;/*clear float and this will also avoid margin collapsing with body*/
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>

And if you only avoid the margin-collapsing behavior you will have this output:

body {
  margin: 0;
  padding: 1px; /*avoid margin collapsing with body*/
}

.square {
  width: 50px;
  height: 50px;
  margin:50px;
}

#red {
  background-color: red;
  float:left;
}

#green {
  background-color: green;
  float:right;
}

#blue {
  background-color: blue;
}
<div class="square" id="red"></div>
<div class="square" id="green"></div>
<div class="square" id="blue"></div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
2

You need to clear your floated elements. There is a couple popular ways to do this for your situation.

you can add a <div style="clear: both"></div> after you last floated element, or you can create a clearfix class and wrap your floated elements in that.

.clearfix:after {
  content: '';
  display: block;
  clear: both;
}

body {
  margin: 0;
  padding: 0;
}

.square {
  width: 50px;
  height: 50px;
  margin: 50px;
}

#red {
  background-color: red;
  float: left;
}

#green {
  background-color: green;
  float: right;
}

#blue {
  background-color: blue;
}

.clearfix:after {
  content: '';
  display: block;
  clear: both;
}
<div class="clearfix">
  <div class="square" id="red"></div>
  <div class="square" id="green"></div>
</div>
<div class="square" id="blue"></div>
zgood
  • 12,181
  • 2
  • 25
  • 26
  • @TemaniAfif I was unaware that the OP was asking about collapsing margins... I thought it was just a question about clearing floats – zgood May 03 '18 at 20:49
  • he was not asking about collapsing margin or float :) he was asking why such behavior ... but I think he's more intrested by a fix than understanding what's happening (which more important for me) – Temani Afif May 03 '18 at 20:52
  • @TemaniAfif I agree... understanding is more important than a copy paste fix – zgood May 03 '18 at 21:03
  • and if you try his code by only removing margin-collapsing (like I did at the end of my asnwer) you will see a complete a new behavior which means that margin-collapsing is having an important impact here ;) – Temani Afif May 03 '18 at 21:05
1

Add the clear: both; in blue div like following:

#blue {
   background-color: blue;
   clear:both;
}

Explanation:

When we keep any element who have CSS property float: left/right; inside any container except IE all other modern browser not increase the container height based float element height until you not clear the float. And browser's treat container element have no content inside except non-float element and that's why browser your .blue div set at top position.

How can overcome clear float issue?

We can clear the float issue by two way. One is keep an element who have CSS property clear: both; in last position of container element like following:

<div class="float-left"></div>
<div class="float-right"></div>
<div class="clear"></div>

.float-left { float: left;}
.float-right { float: right;}
.clear { clear: both;}

Another modern way is use pseudo element. We know every element have two pseudo element :before and :after. We can apply clear: both; property on those like following way:

.clearfix::after {
    content: "";
    clear: both;
    display: table;
}
.float-left { float: left;}
.float-right { float: right;}

<div class="clearfix">
    <div class="float-left"></div>
    <div class="float-right"></div>
</div>
Hanif
  • 3,739
  • 1
  • 12
  • 18