Search code examples
htmlcssalignmentcss-float

Inconsistent alignment of a Floating Element


SUMMARY

Floating element exhibits inconsistent vertical alignment with the adjacent non-floating element, this variability is subject to the border-top-width value and overflow value of the container or parent element. What gives?


Background

I ran into this situation while I was practising with a layout involving <img> elements. I just started learning HTML/CSS on my own last month, so do lecture me a little if this is due to something fundamental that I have glossed over.

Details

There is a floating element and a non-floating block element within a <div> container.

The floating element (p1) has a fixed width and a 0 margin. It is floating in either left/right direction. It is the starting floating element (i.e. first-in-line to float to the side of the containing box).

The adjacent element (p2) is a non-floating block that wraps around p1. Note that a non-zero margin value is purposely specified for p2 here in order to show that p1 and p2 are not aligned under one of the scenarios explained below.

The containing element <div> has 0 padding.

With this setup, I found that there are at least two ways the floating element (p1) may position itself with respect to border-top-width and overflow:

  1. The floating element (p1) aligns with the adjacent non-floating element (p2) (i.e. the top-border of p1 box lines up with the top-border of p2 box).

    CSS Rules:
    div {border-top-width: 0px;}
    and
    div {overflow: visible;}

  2. The floating element (p1) instead aligns with the top border of the containing box or parent element.

    CSS Rules:
    div {border-top-width: non-0px;}
    or
    div {overflow: auto/hidden/scroll/}

Note that in case 2, either rule on its own is enough to enable the alignment.

Code

The code, oversimplified, would look something like this:

HTML

<div>
    <img src="example.jpg">
    <p>Random text</p>
</div>


CSS

img {
    float: left;
}

/* floating element aligns with adjacent element */

div {
    border: none;
    overflow: visible;
}

or

/* floating element aligns with top border of container */

div {
    border-top-width: 1px;
    overflow: auto;
}


I have put up an example on jsfiddle: https://jsfiddle.net/tLumj9x7/

Or you may check it with snippet below:

/* <body>, <div> margin set to 0 to avoid interference  */
body {
  margin: 0px;
}

div {
  margin: 0px;
}

/* border drawn above the paragraphs to denote top border of 2nd <div> */
.div1 {
  border-bottom: 1px solid;
}

p {
  border: 1px solid;
}

/* floating paragraph: margin set to 0 to highlight unusual alignment */
.p1 {
  float: left;
  margin: 0px;
  width: 400px;
}

/* note that a <p> element has a default margin of 1em, so this declaration is just for demonstration */
.p2 {
  margin: 16px;
}

input#border:checked~div.div2 {
  border-top: 0.02px solid transparent;
}

input#overflow:checked~div.div2 {
  overflow: auto;
}
<form>
  <input type="checkbox" name="border" id="border" />container border-top-width: non-0<br />
  <input type="checkbox" name="overflow" id="overflow" />container overflow: auto / hidden/ scroll<br />
  <div class="div1">
  </div>
  <div class="div2">
    <p class="p1">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
    </p>
    <p class="p2">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
      dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </p>
  </div>
</form>


Questions

  1. How exactly is the position of a starting floating element determined in relation to its containing element (in our case the <div> block)?

  2. What does the border-top-width property have anything to do with the "anchoring" of the staring floating element?

  3. Ditto with the overflow property. In terms of properties, how does overflow influence the container box "structurally"?

  4. Of the two scenarios above, which shows a "default" positioning for the starting floating element, if at all?

  5. On a different but related note. If I place margin around the p1 floating element that floats left, its left margin collapses with the left margin of the adjacent p2 non-floating element. Is this standard behaviour? I read that the margin of floating elements do not collapse, so I am not sure if I have understood the concept correctly.

This is my first post on stackoverflow, so thank you for reading my question! I am quite new to web development and I look forward to reading your answers.


Solution

    1. A floating box will be placed vertically level with where the box would have been if it hadn't been floated. In the case here, where it is the first element in its container, its top edge is coincident with the top of the content box of its container. (The difference in effect you're seeing is the div container's content box moving up and down.)

    2. In the initial case, p1 is floated and therefore out of flow so there is nothing to stop the vertical margin of p2 from collapsing with its ancestors. The presence of a non-0 width border top means that the top margin of p2 is no longer adjacent to the top margin of the div element (i.e. they are separated by the border), so the margins can not collapse together.

    3. A side effect of the overflow:auto is that it causes the div to establish a block formatting context. The margins of descendants of a block formatting context won't collapse with the margins of the element that establishes the block formatting context. A more direct, but newer way to cause the div to establish a block formatting context is to give it a setting of display:flow-root.

    4. By default, adjacent vertical margins of in-flow block boxes collapse. So the default top margin of the p element (p2) collapses with the top margins of the div and body elements, increasing the margin above the top of the content box of the div element, and hence pushing the floated element lower.

    5. Collapsing Margins affects vertical margins. With horizontal margins, what you are seeing is not margin collapse, but a different effect. p1 and p2 overlap one another. p2 doesn't exactly wrap around p1, its content does. What happens is that p2 is made up of a stack of line boxes. The left edge of each line box which is alongside p1 is coincident with p1's right margin edge. p2's left margin still touches the left edge of the containing div's content box, exactly as it p1 wasn't there at all, so it won't affect the position of left edge of those line boxes unless p2's left margin, border and padding is greater than the width of p1's margin box.