在 table-cell 元素中使用 float 属性 将先前的内容向下滑动

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

我正在尝试在具有 display:table-cell 属性 的元素内使用浮动 div,但我遇到了意外行为。

为什么第一列的元素会受到第二列元素的影响(第一列的a突然下移了)?有什么办法可以防止这种行为吗?

.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>

您在该规则 .cell+.cell a 中有一个加号(即:adjacent siblings selector),删除它会按预期工作:

.cell a {
  float: left;
}

http://jsfiddle.net/vg5j7xgc/5/

迷人的行为。我有几个理论。虽然我同意使用 display: table-cell 似乎是随机的,但它偶尔会被使用,所以我会把它留在那里供我回答。如果我的回答过于复杂,我很抱歉;我会尽量简化它:

首先

要理解为什么元素被下推是理解 vertical-alignment 如何为 table-cell 工作的问题:

应该用于 table-cell 的唯一 vertical-align 属性 值是 topmiddlebottom(请参阅this excellent css-tricks article)。任何其他行为都是未定义的行为——这意味着浏览器可以对它们做任何他们想做的事情,不同的浏览器可能会做不同的事情。这可能不是 [永远...] 我们想要的。

默认情况下,浏览器会提供所有 td 个元素 vertical-align: middle。所以当你创建一个正常的 HTML table 时,你永远不必担心 vertical-align 属性.

另一方面,默认情况下,所有普通元素都有 vertical-align: baselinedisplay: table-cell 元素上的这个值会导致我们可怕的未定义行为。

您正在使用默认情况下不会像 table 那样表现的元素手动构建 table(这就是为什么您可能不应该在以下情况下使用 display: table-cell你不完全确定你在做什么)。因此,您必须自己设置 all 个 table 的默认样式。这包括为您的 .cell 指定 vertical-align: top|middle|bottom 属性。

那么为什么只有当我在一个单元格中浮动元素时它才被按下?

同样,这是未定义的行为。当您不漂浮时,这似乎不会造成问题;这些元素仍然能够智能地找到内部文本的基线并垂直对齐它们,以便它们出现在您期望的位置。漂浮在这里,有两点需要注意:

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.

结合这两者让我认为当你浮动这些元素时:

1) 他们的 .cell parent 忘记了文本在其中的位置。

2) 它无法与基线所在的相邻单元正确通信——它只是使用其底部边缘。

3) 相邻单元格正确地将其内容垂直对齐到该基线,导致向下移动。

修复?

vertical-align: middle 负责任地放在您的 .cell 上:

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

a 标签也应该是 display: inline-block)。这是更新后的 JSFiddle。问候。

CSS 2.1 says

The baseline of a cell is the baseline of the first in-flow line box in the cell, or the first in-flow table-row in the cell, whichever comes first. If there is no such line box or table-row, the baseline is the bottom of content edge of the cell box.

这是理解行为的关键。太有技术含量了,我就试着拆解一下。

第一个单元格有一个流入行框,由文本 "cell1" 形成。它的基线是文本的基线。

对于第二个单元格,所有非空白文本都通过“float:left”从流中删除,所有空白都通过正常的空白规则删除。因此,它没有任何流入线框。它也不包含任何流入 table 行,因此单元格的基线位于单元格框内容边缘的底部。

由于table单元格形成了一个block formatting context,单元格的内容包括浮点数,所以底部内容边缘是浮点数的底部。

默认情况下,第一个单元格的垂直对齐值为 baseline。因此,它必须与第二个单元格的基线对齐,即浮动的底部。

现在,第一个单元格中的 a 元素是一个不可替换的内联元素。 Its height rules

The vertical padding, border and margin of an inline, non-replaced box start at the top and bottom of the content area, and has nothing to do with the 'line-height'. But only the 'line-height' is used when calculating the height of the line box.

... 而第一个 table-cell 的高度是它的行框堆栈的高度,在这种情况下,它是它包含的唯一一行的行高.所以 a 元素填充和边框不会影响 table 单元格的高度,实际上会转义第一个 table 单元格,如果你添加 background-color to the cells

正如已经指出的那样,决议是add vertical-align:middle to the first cell