Search code examples
htmlcssmargins

What is a top margin that has clearance?


According to the WC3 specification:

  • The bottom margin of an in-flow block box with a 'height' of 'auto' collapses with its last in-flow block-level child's bottom margin, if:

    • the box has no bottom padding, and

    • the box has no bottom border, and

    • the child's bottom margin neither collapses with a top margin that has clearance, nor (if the box's min-height is non-zero) with the box's top margin.

Could someone explain what the last paragraph implies with an example please?


Solution

  • OK, prepare yourself for a bit of a wild ride. IMHO, you're incredibly unlikely to encounter this in practice. I've certainly never yet found a use for it.

    What we need to know is that clearance is a state a box gets when it's moved down in order to clear a float in its block formatting context.

    This is done with clear:left or clear:right or clear:both. If the box would otherwise be alongside a float on the side on which it's cleared, the box is moved down until its border-box is fully below the margin box of the float.

    Now consider this example:

    body {
      border: 1px solid red;
    }
    main {
      padding-top:1px;
      margin-bottom:100px;
    }
    aside {
      background-color: tan;
      height: 100px;
      width: 200px;
      float: left;
    }
    header {
      margin-top:90px;
    }
    footer {
      margin-bottom:100px;
    }
    <body>
      <main>
        <aside>The aside</aside>
        <header></header>
        <footer></footer>
      </main> 
    </body>

    The aside element is the float. The top padding on the main element is to ensure that nothing can collapse with the top margin of the main or body elements.

    Because the header and footer elements have no content, the margin-bottom on the main element, the margin-top on the header element and the margin-bottom on the footer element are all adjacent and collapse together, making a total vertical margin of 100px. The body element content box contains them, making its height 101px. (1px padding + 100px margin)

    Now, let's add clear:left to the header element.

    body {
      border: 1px solid red;
    }
    main {
      padding-top:1px;
      margin-bottom:100px;
    }
    aside {
      background-color: tan;
      height: 100px;
      width: 200px;
      float: left;
    }
    header {
      margin-top:90px;
      clear:left;
    }
    footer {
      margin-bottom:100px;
    }
    <body>
      <main>
        <aside>The aside</aside>
        <header></header>
        <footer></footer>
      </main> 
    </body>

    Now the height of the body element is 211px!.

    The border box of the header element is moved down 10px so that it clears the float. That is the header element has clearance. Since the top margin of the header element is attached to the border box, it too is moved down 10px. Then the bottom margin of the footer collapses with the top margin of the header and pushes the border box of the header down another 10px (100px - 90px).

    We've now reached the conditions of your question. The footer element is the last in-flow block-level child of it's parent - the main element. The footer element has no bottom padding or border. Its bottom margin collapses with the top margin of an element that has clearance.

    So the result is that the footer's bottom margin cannot collapse with the bottom margin of the main element, and so the total height of the content box of the body element is 1px + 100px + 10px + 100px.

    Finally, consider what happens when the header's top margin is set to 101px instead of 90px.

    body {
      border: 1px solid red;
    }
    main {
      padding-top:1px;
      margin-bottom:100px;
    }
    aside {
      background-color: tan;
      height: 100px;
      width: 200px;
      float: left;
    }
    header {
      margin-top:101px;
      clear:left;
    }
    footer {
      margin-bottom:100px;
    }
    <body>
      <main>
        <aside>The aside</aside>
        <header></header>
        <footer></footer>
      </main> 
    </body>

    Notice that now the bottom margin of the main element collapses with the other margins again. That's because although the header element still has clear:left, its margin top is greater than the height of the float, so its border box is already below the bottom of the float, and so there's no need for it to move down. Since it doesn't move, the header element does not have clearance, and so the margins can all collapse.