• CSS September 1, 2009

    Floats are a powerful feature of CSS and for the most part are pretty straightforward to use.
    However, there are many subtleties about them which can cause people to wonder why, for example, images aren’t correctly positioned.
    Usually the quickest solution is to throw a bunch of clear: both CSS rules either onto objects or onto empty divs.
    This post goes into some of the details about how floats are implemented and how to use them.
    How the various browsers’ float implementations differ will also be discussed, but for the most part the latest versions of the browsers all do a good job of agreeing with how to implement the specifications.


    This post is divided into several examples which demonstrate particular behaviors of floats:

    These examples and explanations refer to the CSS 2.1 and CSS 3 float specifications.
    The examples are targeted for the latest versions of the major at the time of this writing, Safari 4, Firefox 3.5, Internet Explorer 8, and Opera 10.
    Chrome is not covered at this time, but it should behave as Safari does since they use the same HTML/CSS core.

    Display type of floats

    For the most part, a float will behave the same regardless of the display type of the object.
    Most display types will be positioned as if they were display: block, with the exception of inline-table and table which are displayed as table and list-item which is displayed as list-item.

    This example shows how this works.
    The floated item has a 5px border and a height of 20px.
    It also has list-style-type: disc which is ignored by display types other than list-item.
    The whole example also has a 1em margin on the left so the bullet will show when list-item is selected.


    Display type of floats

    Floated object displayed as:



    Floated block with display: blockinlinetablelist-item
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui turpis, vehicula vel varius sed, auctor at ante. Etiam eu ante ligula. Donec ipsum turpis, posuere id lacinia id, pellentesque non augue. Cras imperdiet consequat est vel sagittis. Aenean pharetra pellentesque iaculis. Vestibulum dapibus urna nulla, sit amet dapibus arcu.

    As you can see, the block and inline settings act the same.
    The table setting appears shorter because the height and width of a table take the border into account, unlike other display types (mentioned in an earlier post, CSS and Tables, part 1).
    The list-item setting appears the same as block and inline, but the bullet appears as if this were a normal list item.

    IE 7 and earlier seem to not be able to treat the object as a list-item, so the bullet doesn’t appear.

    Both IE 8 and IE 7 do not seem to take the border into account when computing width and height of a floated table, which is why the height of the float doesn’t change when selecting table.

    Display types and flowing around floats

    Perhaps the most surprising behavior for users who first start using floats that a float can appear to be inside a block element which follows it.
    This example shows how different display types flow around a float.
    The code’s skeleton is:

    <div>Floated element</div>
    <container>This text...</container>

    where container is the equivalent of div for the block type, span for the inline type, and img for the inline-block type (implementation details are after the example).
    The block has no padding, but has a border so you can see what area it covers.
    The float has a 5px margin on the right and 2px on the bottom, none on the left or top.


    Display types and flowing around floats

    Content after float displayed as:



    Floated element


    This text after the float displayed as blockinlineinline-blockinline-block and is long enough to make it wider than the space to the right of the float.

    block

    At first the position of the block’s border seems surprising, especially since the float is declared before the “div“.
    Both CSS 2.1 and CSS 3 specify:

    Since a float is not in the flow, non-positioned block boxes created before and after the float box flow vertically as if the float didn’t exist.
    However, line boxes created next to the float are shortened to make room for the margin box of the float.

    The “div” is not positioned, which is why it occupies the same area as the top of the floated element.
    The text, however, constitutes a line box, which is why the text says to the right of the float.
    There’s a small gap between the float’s border and the text because of the float’s right margin.

    The float’s black border appears to obscure the red border of the “div“, even though the float appears first in the HTML.
    This is because of the specified layering of floats, covered later in the Layering of float, block, inline section of this post.

    inline

    The “span” acts just like the text in the block example except it seems to sit a bit higher.
    This is because:

    If there’s a line box, the top of the floated box is aligned with the top of the current line box.

    The top of the line box is not the same as the top of the whole box (including the border), which accounts for the discrepancy.

    inline-block

    The border of the non-wide “img” is at the same level as the float, since its dimensions are computed as a block, not as an inline.
    The wide “img” is on the next line, however, because:

    If a shortened line box is too small to contain any further content, then it is shifted downward until either it fits or there are no more floats present.

    The “img” is a block in an implicit line box, and while the line box can be shortened (by wrapping words to the next line) inline-block objects aren’t shortened.
    Even though this inline-block contains text, that text won’t get wrapped unless the inline-block can’t get any wider.
    The border of the wider inline-block has a 2px gap between it and the floating block because of the 2px bottom border on the float.

    IE 7 and earlier, unlike IE 8 and other current browsers, will shrink inline-block elements to fit to the right of a floated element.

    Implementation notes

    This example switches between the different display types through CSS.
    Most browsers will allow you to set any display type on any object, but IE 7 and earlier only correctly set inline-block on an object which is naturally an inline.
    If you set display: inline-block on a div, the element will fill the available width rather than only the width of the content.
    In this example, selecting inline would look as it does now except the border would extend all the way to the right edge.
    Because of this behavior, the text after the float is wrapped in a span.

    Position types and floating

    Only objects in the normal flow can be floated.
    Since position: absolute removes a block from the normal flow, it does not float.

    In this example, the floated element has bottom: 5px and right: 5px set, as well as having 5px right margin and 2px bottom margin.
    Its width is set to 125px so its text will wrap to multiple lines to make it easier to see the effect of changing the positioning.
    If no width were set, the box would expand until the width of the container is reached, then the text would wrap.
    Note you could also explicitly set a width wider than the parent container.

    The block with the red border has padding: 5px and is set to be a flow container, which is explained in the Flow roots example after this one.


    Floated element position types

    Position as:


    Float with position: staticrelativeabsolute

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui turpis, vehicula vel varius sed, auctor at ante. Etiam eu ante ligula. Donec ipsum turpis, posuere id lacinia id, pellentesque non augue. Cras imperdiet consequat est vel sagittis. Aenean pharetra pellentesque iaculis. Vestibulum dapibus urna nulla, sit amet dapibus arcu.

    static

    A position of static is the default for a block, so the float acts normally, with the text flowing around it.
    The float honors its container’s padding, which is why it is 5 pixels from the top and left sides.
    The bottom and right attributes have no effect for static positioning.

    relative

    An object with relative positioning is first positioned as static and then moved.
    According to CSS 2.1:

    Once a box has been laid out according to the normal flow or floated, it may be shifted relative to this position.
    This is called relative positioning. Offsetting a box (B1) in this way has no effect on the box (B2) that follows: B2 is given a position as if B1 were not offset and B2 is not re-positioned after B1’s offset is applied.

    and:

    A relatively positioned box keeps its normal flow size, including line breaks and the space originally reserved for it.

    The CSS 3 Positioning Recommendation is still a working draft and has not been released at this time, but it’s reasonable to expect it to be the same as CSS 2.1 for the purposes of this post.

    The float’s definition specifies that once layout has been done, the box should be moved 5 pixels up and 5 pixels to the left.
    Because the container has 5 pixels of padding, the final position of the float is against the container’s top-left corner.

    absolute

    Unlike static or relative positioning, absolute positioning removes the object from the normal flow, which negates the block’s float attribute.
    The container’s text therefore has a layout which fills the entire container, and the box and text overlap.

    The position of the box is relative to the content area of the container, ignoring any padding but taking the float’s margins into account.
    This is why the box is positioned 10 pixels from the bottom right corner (5 pixels each for the positioning of the bottom and right plus 5 pixels from the right and 2 pixels from the bottom for the float’s margin).

    IE 6 has vastly different absolute positioning.
    Admittedly, I did not experiment enough for this post to be able to explain why it appears below the containing element.

    Flow roots

    CSS 3 defines a flow root as a box that is one of:

    • a float
    • has an overflow value other than none
    • has a display of table-cell, table-caption, inline-block, or inline-table
    • has a position of neither static nor relative
    • has either a vertical (tb) block-progression and its parent has a horizontal (lr or rl) one, or vice-versa

    This post will not cover block-progression.
    CSS 2.1’s name for a flow root is a formatting context.

    Understanding flow roots can help eliminate surprises when working with floats.
    More specific implications of flow roots are discussed after the example.

    The float in this example is contained within the red box, and the green and blue boxes come after the red box.
    The red, green, and blue boxes have padding of 5px and have top and bottom margins of 5px.
    The only margin set on the floating box is 5px on the right (to separate it from objects flowing around it).
    The float also has an opaque background, so it obscures the other borders.
    This is done to make the float’s text easier to view.

    This example will not work with IE 6, since that browser does not support overflow: hidden.


    Flow roots

    Set as flow root:


    Floated element which is tall enough to go through the red and green boxes and at least descend into the blue box.

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui turpis, vehicula vel varius sed, auctor at ante.

    Etiam eu ante ligula. Donec ipsum turpis, posuere id lacinia id, pellentesque non augue. Cras imperdiet consequat est vel sagittis. Aenean pharetra pellentesque iaculis. Vestibulum dapibus urna nulla, sit amet dapibus arcu.
    In a malesuada magna.
    Nunc aliquet, eros vitae sodales cursus, massa erat feugiat ipsum, ut auctor augue nunc sed turpis.

    neither

    When neither the red nor the green box is set as a flow root, the float is positioned inside the padding of the red box.
    Because the green and blue boxes are not flow roots and have block display, they are not affected by the float.
    The text in the green and blue boxes, however, have inline display, and therefore flow around the float.

    red box

    When the red box is set as a flow root (in this example, with overflow: hidden) the box will expand to contain the whole float, as addressed in the CSS 3 specification in Auto heights for flow roots:

    …if the element has any floating descendants whose bottom margin edge is below the bottom, then the height is increased to include those edges.
    Only floats that are children of the element itself or of descendants in the normal flow are taken into account, e.g., floats inside absolutely positioned descendants or other floats are not.

    As you can see, not only does the box grow in height to accommodate the float, but it also leaves room for the container’s padding.
    It would also leave room for the float’s bottom margin were one defined.

    This automatic height behavior will also be covered later in this post as a way to clear a float.

    green box

    The green box is also made to be a flow root by setting overflow: hidden.
    Because CSS 3 specifies:

    The border box of a table, a block-level replaced element, or an element in the normal flow that is a flow root (such as an element with ‘overflow’ other than ‘visible’) must not overlap any floats in the same flow as the element itself.

    The green box will sit next to the float, rather than extending behind it.
    The box also honors the float’s 5 pixel right margin.
    This behavior is slightly different than setting the green box to display: inline-block because the box will not expand beyond the available width to the right of the float, causing it to move underneath the floated object.
    This behavior can be overridden by explicitly setting the width of the green box or if an object in the green box forces a wider width.

    Since a container which is a flow root will not intersect a float, the method can also be used if you want a background color or image to not slip behind a floated object.
    You can use margins for any desired separation.

    The blue box, not being a flow root, will always go behind the float and its text will always wrap around the float.

    Clearing floats

    This section will discuss the various ways to clear floats, as well as methods you can use to contain floats.
    For this example, the blue and green boxes have no padding or margin, but the float has padding to force it to be tall enough to descend into the green box.
    The float has a right margin of 5px and bottom margin of 2px, and is contained within the blue box.


    Clearing floats

    • No float clearing
    Floating block

    Text in same container as float.

    Text in container after float.

    No float clearing

    This is how the text would look when no clearing is done.
    As with the previous example, the green box goes behind the float, while the text in the green box flows around the float.

    Set clear: both on green block

    This is perhaps the most straightforward way to clear the float.
    There’s almost always a block available to use the clear attribute, but if there isn’t, it’s common to use an empty div to clear the float.
    Notice the float still extends below the blue box, since the clearing doesn’t happen until after the float and blue box are positioned.
    Also, there is a 2px gap between the float and the green box because of the float’s bottom margin.

    Set clear: both on empty block in blue block

    The only difference between this and using the green block to clear the float is that with this setting, the blue box will expand to fully contain the float.
    If there were no border on the blue box (and no background is set) then the two solutions will end up looking the same.
    However, if you have a border or want to set a different background, then you need to pick the method which will give you the effect you want.

    The float’s bottom 2px margin again comes into play, this time creating a space between the float and the bottom border of the blue box.

    Set overflow: hidden on blue block

    For this example, making the blue block a flow root looks the same as using an empty div within the blue block to clear the float.
    It has the advantage that you don’t need to add an extra container, but has the disadvantage of needing a block which contains both the float and the text.
    If you already have a container, then this is an easy way to clear a float.

    A side-effect of setting overflow: hidden is if you have an object which would normally extend outside the bounds of the container (such as an image which is wider than the container) then that object will get truncated.
    You can set overflow: auto but that will cause scroll bars to appear.

    Another method to make the blue block a flow root is to make it a float.
    If you either know the content will force the block to the full width of the container or the having it not be full width doesn’t matter, this method can work well.
    You do have to be careful, however, that it does take up enough of the width so objects which come after the blue block aren’t narrow enough to position to the side rather than below.
    If you set a width for the blue block, you have to be sure that you take the padding and border into account, or put the border and padding on a nested object so you can set the float’s width.

    You can also set position: absolute on the blue box, but that removes it from the document flow which will very likely cause undesirable side-effects for your layout.

    As with the previous example, this technique will not work on IE 6 because of the lack of support for overflow: hidden.
    IE 7 does not not take the float’s bottom margin into account and the bottom blue border is right against the lower edge of the float.

    Set clear: both using ::after

    CSS allows you to insert text at the end of a block, but instead of a block we want something to clear a float.
    The CSS we use for this is:

    .container::after {
        display: block;
        clear: both;
        content: "";
    }

    IE doesn’t support this pseudo-selector, but with the latest versions of the other major browsers, this can be an effective technique.
    IE 8 does support :after (with one colon), which was the CSS 2.1 pseudo-selector.
    To make this example work for both CSS 2.1 and CSS 3, the block is duplicated and :after used for the second selector.
    You can’t use a comma to specify both selectors with the same set of rules, since IE won’t understand the ::after and will ignore the whole block.

    Since we want to use the ::after block to clear floats, we need to make sure it’s displayed as block rather than the default, inline. The next line does the clear itself.

    The last line is necessary for Safari and Opera, which will ignore the ::after block unless content is supplied.
    Since we don’t actually want content, it works to just specify an empty string.

    Floats don’t collapse margins

    Unlike normal block objects, margins on floats never collapse.
    In this example, the boxes are normal block objects.
    The green box has a bottom margin of 10px while the blue box has both a top and bottom margin of 10px.
    The red box is floated and has a top margin of 10px.


    Floats and vertical margins

    Set margins of blue box to:

    Box with bottom margin of 10px
    Box with no top and bottom margins of 10px
    Box floated left with top margin of 10px

    When the blue box has no margins, the gap between it and the green box is 10px, the value of the bottom margin of the green box.
    You see the same gap between the blue box and the float, because the of the float’s 10px top margin.

    When you change the blue box to have a 10px margin on the top and bottom, the gap between it and the green box doesn’t change because those margins collapse together.
    However, the gap between the float and the blue box is twice as wide, because of the lack of margin collapsing.

    Layering of float, block, inline

    Floats normally will act as you expect, appearing in front of the background it obscures. However, text will appear on top of the float, as shown in this example which uses a negative margin to force the float (the red box) to be superimposed over the green box’s border and background, but the green box’s text will still show over the red box’s border and background.


    Layering of float, block, inline

    Top margin for red block:

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui turpis, vehicula vel varius sed, auctor at ante. Etiam eu ante ligula. Donec ipsum turpis, posuere id lacinia id, pellentesque non augue. Cras imperdiet consequat est vel sagittis. Aenean pharetra pellentesque iaculis. Vestibulum dapibus urna nulla, sit amet dapibus arcu.
    Floated block

    This behavior may seem odd, but it indeed is according to the spec:

    A float can overlap other boxes in the normal flow (e.g., when a normal flow box next to a float has negative margins). When this happens, floats are rendered in front of non-positioned in-flow blocks, but behind in-flow inlines.

    IE 7 and earlier also forces the float over all inline boxes, which is why the text in the green box is obscured by the float.

    Negative margins and rearranging columns

    In 2005 the article One True Layout appeared which tied many of the concepts outlined above into a recipe for using CSS to display content in multiple columns.
    That in and of itself wasn’t exactly new, but what made this article notable is it explained how you could have the column’s content in one order in the HTML but appear in a different order when displayed in the browser.

    The major piece of the technique is that floats can be used to reorder the columns, as long as you are careful about how you position them.
    The rule of thumb is to always position a column relative to the right edge of the column which appears before it in the HTML.

    In this example the red and green boxes are both floated to the left. Each has a width of 180px and left and right padding of 10px, making each 200px wide.
    The whole example is wide enough for two boxes, but not three.


    Negative margins and rearranging columns

    • Left margin for red box:

    • Left margin for green box:


    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas dui turpis, vehicula vel varius sed, auctor at ante.
    Etiam eu ante ligula. Donec ipsum turpis, posuere id lacinia id, pellentesque non augue.

    With no changes to the margins, each box is floated and appears on one line.
    When you change the left margin of the red box to 200px, the green box wraps to the next line because there isn’t enough room for it to the right of the red box.

    With the red box still having a 200px left margin, changing the green box to have a left margin of -200px brings it back up to the same line as the red box, since there is now room for it.
    Because the the red box is 200px wide, the green box will appear on top of the red box because the HTML for the green box comes after the HTML for the red box.

    Changing the left margin on the green box to -400px moves it more to the left, enough to show up directly to the left of the red box, making them displayed in a different order than they appear in HTML.

    To generalize how to swap two columns, you first need to know the width of each column.
    The column which is first in the HTML (the red one in this example) needs to have a left margin equal to the width of the second one (green in this example).
    The second column needs to have a negative left margin, equal to the sum of its width and the width of the first column.
    You can add a gap between the columns by increasing the first column’s left margin by the width of the gap and increasing the second column’s negative left margin by the same amount.

    This method can be expanded to more than two columns, remembering that the left margin needs to be computed based on the right edge of the final position of the column which appears before it in the HTML.

    This post only directly covers the column positioning part of the One True Layout.
    It indirectly covers how to clear floats after the columns by defining a flow root, since the column last declared in the HTML may have enough space to its right to allow content to flow to its right, obscuring other columns.
    It doesn’t cover making columns equal length, which is much more involved than ordering the columns.

    The CSS has one concession to IE 6 in that the red and green boxes have display: inline set to prevent the Doubled Float-Margin Bug.
    As the name implies, if you change the margin for a float which has display: block, the margin will actually be doubled.

    Posted by fmf @ 3:29pm

  • One Response

    WP_Modern_Notepad

    Leave a Comment

    Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.