Search code examples
htmlcsscss-floatvertical-alignment

Using float property inside table-cell element slides previous content down


I'm trying to use floating divs inside the element with the display:table-cell property, but I have encountered unexpected behavior.

Why are the elements in the first column affected by the elements in the second column (a in the first column is suddenly moved down)? Is there any way to prevent that behavior?

.table {
    display: table;
}
.cell {
    display: table-cell;
}
.cell a {
    padding: .5em;
    border: .1em solid black;
}
.cell+.cell a {
    float: left;
}
<div class='table'>
    <div class='cell'>
        <a>cell1</a>
    </div>
    <div class='cell'>
        <a>cell2</a>
        <a>cell2</a>
    </div>
</div>


Solution

  • Fascinating behavior. I have several theories. Although I agree that using display: table-cell seems random, there are occasional uses for it so I'll leave that in there for my answer. I'm sorry if my answer is overtly complex; I'll try to simplify it:

    First of all

    To understand why the element is pushed down is a matter of understanding how vertical-alignment works for table-cells:

    The only vertical-align property values that should be used for table-cells are top, middle, and bottom (see this excellent css-tricks article). Anything else is undefined behavior--meaning browsers may do whatever they want with them, and different browsers will probably do different things. This is probably not [ever...] what we want.

    By default, browsers will give all td elements vertical-align: middle. So when you're creating a normal HTML table, you never necessarily have to worry about the vertical-align property.

    On the other hand, all normal elements, by default, have vertical-align: baseline. This value on elements with display: table-cell causes our dreaded undefined behavior.

    You are manually constructing a table using elements that won't, by default, behave like a table (this is why you probably shouldn't be using display: table-cell when you're not completely sure what you're doing). You therefore have to put all the default styles of a table on by yourself. This includes specifying a vertical-align: top|middle|bottom property for your .cells.

    So why is it only pushed down when I float the elements in one cell?

    Again, it's undefined behavior. When you don't float, this doesn't seem to cause a problem; the elements are still able to intelligently find the baseline of the inner text and vertically align themselves so they appear where you'd expect them. When you float here, there are two things to note:

    1) Remember that floating removes an element from the normal flow of the DOM. This means other elements, including the element's parent, can't interact with that element like they normally would.

    2) Remember that table-cells are intelligent; they can dynamically, vertically position their children.

    Combining these two leads me to think that when you float those elements:

    1) Their .cell parent is losing track of where the text is inside them.

    2) It can't properly communicate to its neighbor cell where the baseline is--it just uses its bottom edge.

    3) The neighbor cell correctly vertically aligns its content to that baseline, resulting in the shift downward.

    The fix?

    Put vertical-align: middle responsibly on your .cells:

    .cell {
        display: table-cell;
        vertical-align: middle;
    }
    

    (And the a tags should probably be display: inline-block too). Here's an updated JSFiddle. Regards.