【问题标题】:How is this HTML5 brick falling down?这个 HTML5 砖是怎么掉下来的?
【发布时间】:2013-05-03 23:16:21
【问题描述】:

我已经准备了一个示例 jsfiddle 来展示我当前在布局中遇到的问题:当我将内容动态插入到特定元素(砖块)中时,该元素与其父元素一起下沉超出了我对 HTML/CSS 的理解。当我删除内容时,原始布局会恢复,除非我使用的是 Chrome……然后它会保留其位置并在插入新内容时再次下降。

概念证明:http://jsfiddle.net/GADk9/

示例中的复选框只是切换块内的文本,仅此而已。我想知道上面的边距(是吗?)来自哪里。

这是一个完整的 HTML5 文档:

<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title>HTML5 Falling Brick - What is this?</title>
<style>
#brick {
    background-color: lightgray;
    border: solid black medium;
    border-radius: 1em;
    color: red;
    font-size: 2em;
    height: 100%;
    text-align: center;
}
#contrail { background-color: lightblue; width: 20em; }
#pit { display: table; }
#pit>* { display: table-cell; }
#pit>*>* { height: 4em; }
</style>
</head>
<body>
    <div>
        <label>Click me twice
            <input onchange="document.getElementById('brick').innerHTML = this.checked ? 'FALL!!!' : ''" type='checkbox'></input>
        </label>
    </div>
    <div id='pit'>
        <div>
            <div>
            </div>
        </div>
        <div id='contrail'>
            <div>
                <div id='brick'></div>
            </div>
        </div>
    </div>
</body>
</html>

更新

再次阅读我的问题后,我意识到这可能暗示了我真正想要完成的是修复一些 HTML 的错误印象。 为了明确强调这一点,我不需要在这里更改任何内容。砖块的例子只是我正在观察的问题的一个有趣的演示。 我真的很想了解在这样的排列中插入内容时导致元素位置改变的原因

【问题讨论】:

  • 这个 HTML5 怎么样? o_o
  • 我不明白。小提琴、Firefox 和 Chrome 对我来说都是一样的。规则 #pit>*>* 也没有任何意义,因为您在 #pit 下的所有内容下都说了所有内容。
  • @Rob 我认为选择器 >* 不是递归的,所以 #pit&gt;* 只会查看其直接子代,而不是其孙子代。
  • @Rob 我认为#pit * 会选择#pit 的每个后代,而#pit&gt;* 只会选择它的孩子
  • 很明显……您正在使用一张桌子。而且桌子无法逃脱万有引力定律 :) en.wikipedia.org/wiki/Gravitation

标签: css html layout


【解决方案1】:

你有

<div id='pit'>
    <div>
        <div>
        </div>
    </div>
    <div id='contrail'>
        <div>
            <div id='brick'></div>
        </div>
    </div>
</div>

而你正在使用

#pit { display: table; }
#pit>* { display: table-cell; }
#pit>*>* { height: 4em; }

现在这是我们的问题,因为它说#pit 是表格,#pit&gt;* 是一个表格单元格,它每次都将height: 4em; 相加。

现在这是我的解决方案。

#pit { display: block; }
#pit>* { display: table; }
#pit>*>* { height: 4em; display: table-cell;}

http://jsfiddle.net/AAbhishekk/GADk9/28/

【讨论】:

  • 砖块上方的额外空间是因为上面的空白div就像一张桌子一样。
  • 额外的空间是由于块的垂直对齐。不是因为那些空的div。空 div 不会显示在基于表格的显示中。它应该有一些内容才能这样做。
  • 将表格向下移动到子级,并将表格单元向下移动到孙子级,从而消除了操作正在进行的表格 -> 单行 -> 单元格的事情。这有效地使每个孩子成为一个具有单行和单元格的表格,从而产生两个表格而不是一个。
【解决方案2】:

我在多次使用表格、表格行和表格单元格显示时看到了浏览器之间的行为差​​异。首先,我从不使用它们,因为总会有更好的解决方案。但是,对于您的问题:

在处理旨在表现得像表格一样的 CSS 时,考虑一点老派是有帮助的。

事实证明,让您的 POC 在 Fiddle 中正常运行的神奇 CSS 属性是垂直对齐。事实上,这解决了所有浏览器中奇怪的插入额外垂直空间的问题,而不仅仅是 Chrome,同时也解决了 Chrome 保留额外空间的问题。

看看这个小提琴的小修改: http://jsfiddle.net/rtzeK/

#brick {
    background-color: lightgray;
    border: solid black medium;
    border-radius: 1em;
    color: red;
    font-size: 2em;
    height: 100%;
    text-align: center;
}
#contrail { background-color: lightblue; width: 20em; }
#pit { display: table; }
#pit>* { display: table-cell; vertical-align: top; }
#pit>*>* { height: 4em; }

在我链接的小提琴中,我只是将子元素设置为 display: table-cell 以具有附加属性,vertical-align:top。事实证明,您可以将其设置为中间或底部,都具有相同的效果。它阻止了不当行为 - 显然 Chrome 需要被告知 在这种情况下如何表现

我确实觉得 Chrome 的行为不端有点奇怪,而且它似乎是一个错误。也就是说,我回到我之前关于避免像瘟疫一样的显示属性值的声明。显示的组合:inline、inline-block、block,结合相对和绝对定位在父母和孩子之间适当使用会呈现其他麻烦的 css 属性,例如浮动,没必要。

干杯

【讨论】:

  • 并不总是有更好的解决方案。告诉我如何获得一个无序列表以在未定义宽度相等的已分配空间上水平扩展而不会中断?表格单元格和表格显示肯定有它们的位置,我觉得其他建议是徒劳的。
  • 哦!一个挑战。爱它。今晚有空的时候我会整理一下 :) 干杯。
  • 我有兴趣查看解决方案。显示:内联;空白:nowrap;和 Width: >% 将使您达到 95% 的路程,但它不考虑在不深入研究 javascript 的情况下添加到列表中的未指定数量。意识到我对最后的评论有点粗鲁。我很抱歉。
  • 哎呀在你的答案中而不是我的答案中发布了这个答案......jsfiddle.net/gFFYj li 元素之间的额外空间是由于空格,例如换行符。上面的小提琴提供了两种方法来实现您所要求的不间断并确保不超过容器宽度,而每个 li 元素的宽度相同。第一种方法是使用 float: left (ugh) 第二种方法是将 li 元素缩小到同一行。干杯
  • 顺便说一下,我的观点是重新使用内联、块和内联块(我意识到这只是我的偏好,基于我的 css 经验可以追溯到 netscape 4 的黑暗时代...... ) - 这是原始发布问题的另一个小提琴,它消除了表格和表格单元以代替块和内联块。看看这个,挺有意思的。不使用垂直对齐时,行为是增长/收缩,而使用垂直对齐时,它会保持恒定大小。更好,不是吗? jsfiddle.net/wTtfE
【解决方案3】:

如果您将标记简化为几个单元格,每个单元格都包含一个 div,这将更容易理解。

<div class="cell left">
  <div class="inner"></div>
</div>
<div class="cell middle">
  <div class="inner"></div>
</div>
<div class="cell right">
  <div class="inner"></div>
</div>

然后使用类似这样的 CSS 为每个 div 分配不同的高度。

.cell {
  display:table-cell;
  background-color:black;
  width:200px;
}

.inner {
  background-color:silver;
}

.left .inner {
  height:80px;
}
.middle .inner {
  height:140px;
}
.right .inner {
  height:100px;
} 

默认情况下,这些内部 div 与其基线垂直对齐。因此,没有任何文本,所有 div 都沿单元格底部对齐:

+------+ | | | +------+ +--------+ | | | | | | | | | | +-----+------+------+

但是,如果您向其中任何一个 div 添加文本,该 div 将被下推,以便第一行文本的基线与其他 div 的底部边缘对齐。

+------+ | | | | +--------+ | | | +------+ | | |正文 | +--------+------+ | | | +------+

正如其他人所指出的,您可以通过设置不同的vertical-align 属性来更改发生的情况。例如,将vertical-align:top 添加到 .cell 选择器会得到如下结果:

+-----+------+------+ | | |正文 | | | | | +--------+ | | | +------+ | | +------+

我发现在 codepen 中玩这种东西最容易,您可以在其中看到所做的更改。 Here's an example 进行实验。

【讨论】:

  • 很好的分析。很好地阐明了这个问题。
  • 谢谢詹姆斯,感谢您的清晰解释。赏金是首先指出垂直对齐问题的答案。
【解决方案4】:

这是我能想到的最好的主意,我希望我能做到,或者它至少接近它。
在您的 CSS 规则中,您有:

#pit { display: table; }
#pit>* { display: table-cell; }
#pit>*>* { height: 4em; }

它告诉浏览器#pit 是一个表格,它的所有子元素都是单元格(而孙子元素就是它们的样子,因为 CSS 没有强制显示)

这里我看到 2 个问题:

问题 1

#pit 里面你有:

<div>
    <div>
    </div>
</div>
<div id='contrail'>
    <div>
        <div id='brick'></div>
    </div>
</div>

注意孩子,因为你有 2 个,选择器 #pit&gt;*EVERY #pit CHILD 我会为此更改 CSS 规则:

#pit { display: table; }
#pit>#contrail { display: table-cell; }
#pit>#contrail>* { height: 4em; }

但是要小心你想要什么,因为这会使来自#pit&gt;#contrail的孩子高4em,而不是内在的孩子#brick,也许这就是你想要的,但要注意它。

问题 2 @ Chrome(如果你“解决”了第一个问题,则不存在)

我不确定我在说什么,但是...这可能是 webkit 错误吗? Opera 也会出现这种情况吗?
编辑:Opera 的行为不像 Chrome,它返回到正常布局,所以也许它毕竟不是 webkit 错误:/

所以你有一个表格和表格单元格,但浏览器会认为“等等……如果这是一个表格,这是一个单元格……行在哪里!?”,所以它创造了一个“幽灵行”,所以它可以快乐。但是,我不确定当您删除文本时“它”会怎么想,因为它“正常工作”。如果您查看开发人员工具,您会发现没有实际的行元素或类似的东西。
当您“重新添加”文本时,浏览器会介意=打击,因为表格布局。所以它再次重新创建了行(拉伸#pit),可能是因为“幽灵行”没有被清除,或者因为#pit的高度不再重新计算,它只会在幽灵行产生时增加。

如果您想保留相同的 CSS 规则,则必须执行以下操作:

#pit { display: table; }
#pit>* { display: table-row; }
#pit>*>* { height: 4em; display: table-cell; }

【讨论】:

  • 您不需要在 display:table 中包含表格行。使用此属性不会使元素成为表格,而只会将其显示为表格。例如:quirksmode.org/css/css2/display.html#table
  • @Rob 你就在那儿,但是浏览器将“创建”一行(必要时还有表格)以在缺少适当的元素时显示一些表格单元格的东西,因此导致这种情况(我认为)
  • 不会。如果这就是您所说的,至少不在 HTML 中。
  • @Rob 不,我不是指在 HTML 中,我是指在浏览器的内部,但正如我之前所说,这只是我的想象猖獗:P
  • @Goodwine Table-row 不像在 display:table 中那样使用。如果未指定该行,则该行是隐含的,并且仅在必要时用于指定内联内容中的中断。表格行是一个组织元素,而不是布局元素,因此实际上应用的样式很少。
【解决方案5】:

有时,最简单的答案会被忽略。不要将内容重置为空(例如“”),只需将空内容作为非中断空间开始,然后将其重置回非中断空间。表格单元格在没有内容时不会呈现。不间断的空格被单元格视为内容,因此它可以正确呈现。

JSFiddle here

问题来了:

您需要将此规则添加到您的#brick 块中:

vertical-align: top;

并且您需要为应该呈现内容的空表格单元格提供一些内容,以这种方式完成:

<div id='contrail'>
    <div>
        <div id='brick'>&nbsp;</div>
    </div>
</div>

瞧,它已在 Chrome 中修复,并且在其他任何地方都以相同的方式显示。这是一个老式的表问题。看来 Chrome 决定忠实于他们在过去糟糕的日子里最初的行为方式。

或者,对于纯 CSS 解决方案,您也可以将内容规则添加到 #brick 块:

vertical-align: top;
content: '&nbsp;';

它的工作方式完全相同。尽情享受吧!

【讨论】:

  • jsfiddle.net/GADk9/76 删除  它仍然可以正常工作。正如我昨天发布的那样,vertical-align: top css 是关键。
  • @JimSpeaker 你是对的。我同意认为老派是这里的解决方案,我承认在发布我自己的评论之前我没有完整地查看你的评论。
【解决方案6】:

看起来 chrome 不满意 display:table-cell 内部 display:table 没有 display:table-row 介于两者之间。

如果你添加它(并给砖一些宽度),它会停止下落:

#brick {
    background-color: lightgray;
    border: solid black medium;
    border-radius: 1em;
    color: red;
    font-size: 2em;
    height: 100%;
    width: 200px;
    text-align: center;
}
#contrail { background-color: lightblue; width: 20em; }
#pit { display: table; }
#pit>* { display: table-row; }
#pit>*>* { display: table-cell; }
#pit>*>* { height: 4em; }

【讨论】:

  • display:table 不需要表格行。
  • @artem 在插入带有{ display: table-row; } 的元素时,文档树会发生变化,因此必须将#pit&gt;*&gt;* { height: 4em; } 重写为#pit&gt;*&gt;*&gt;* { height: 4em; }
  • @ft1 我不建议在 DOM 中插入任何东西——你的 HTML 已经有足够的 div。我刚刚用 jsfiddle 检查了如果紧接在 #pit 下方的那些被设置为 display: table-row
  • @artem: 好的,但是你不只是在#pit 下立即重新设计 div,你还将布局结构从同一(隐式)行中的两个单元格更改为两行每个单元格。
【解决方案7】:
#pit { display: table; }
#pit>* { display: table-cell; }

以上导致它膨胀(而不是收缩)。这是预期的行为吗?不,因为它不会发生在 IE 或 Firefox 上,我相信这是一个错误解释 display: tabledisplay: table-cell 行为的 Chrome 错误。它似乎没有重新计算表格单元格的高度,在您的情况下为&lt;div id="contrail"&gt;,当文本被删除时。

Have a look at this fiddle - 我已经用实际的表格替换了 div。每次填充文本时,表格单元格的高度都会扩展,但在清除文本时会收缩回原始大小。我会得出结论,这是一个 Chrome 错误,因为这种 CSS 显示模式的目的是模仿 &lt;table&gt;&lt;td&gt; 的使用。

【讨论】:

    【解决方案8】:

    我相信有一个奇怪的规则:

    #brick {
        background-color: lightgray;
        border: solid black medium;
        border-radius: 1em;
        color: red;
        font-size: 2em;
        line-height:2em;
        height: 100%;
        text-align: center;
        margin:0;
        padding:0;
        height:2em;
    }
    #contrail { background-color: lightblue; width: 20em; }
    #pit { display: table; }
    #pit>* { display: table-cell; }
    

    http://jsfiddle.net/GADk9/77/

    【讨论】:

      【解决方案9】:

      我注意到只是添加了一个

         <p> around your text </p>
      

      解决了问题

      这是一个有效的jsfiddle

      【讨论】:

      • 嗯,这会将偏移减少到 1 个像素 (!)
      【解决方案10】:

      Answer: 浏览器不理解你的 html/css 布局组合,因为它没有按照官方规范格式化。格式不正确的 HTML 会使浏览器无法正确显示元素。

      表格单元格必须有一个父表格行:

      http://www.whatwg.org/specs/web-apps/current-work/multipage/tabular-data.html#the-td-element

      表格单元格不允许作为表格元素的直接子元素:

      http://www.whatwg.org/specs/web-apps/current-work/multipage/tabular-data.html#the-table-element

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-04
        • 1970-01-01
        相关资源
        最近更新 更多