为啥这个 inline-block 元素被向下推?

Posted

技术标签:

【中文标题】为啥这个 inline-block 元素被向下推?【英文标题】:Why is this inline-block element pushed downward?为什么这个 inline-block 元素被向下推? 【发布时间】:2012-03-05 14:13:09 【问题描述】:

以下是我的代码,我想了解 为什么 #firstDiv 被所有浏览器向下推。我真的很想了解为什么它被向下推而不是以某种方式向上拉它的事实的内部运作。 (而且我知道如何对齐它们的顶部:))

而且我知道它的溢出:隐藏是导致它的原因,但不确定为什么它会向下推动该 div。

body 
  width: 350px;
  margin: 0px auto;


#container 
  border: 15px solid orange;


#firstDiv 
  border: 10px solid brown;
  display: inline-block;
  width: 70px;
  overflow: hidden;


#secondDiv 
  border: 10px solid skyblue;
  float: left;
  width: 70px;


#thirdDiv 
  display: inline-block;
  border: 5px solid yellowgreen;
<div id="container">
  <div id="firstDiv">FIRST</div>
  <div id="secondDiv">SECOND</div>
  <div id="thirdDiv">THIRD
    <br>some more content<br> some more content
  </div>
</div>

http://jsfiddle.net/WGCyu/.

【问题讨论】:

【参考方案1】:

我本来是开始回复this question的,但还没等我完成就被锁定为骗子,所以我把答案贴在这里。

首先,我们需要了解inline-block是什么。definition in MDN 说:

该元素生成一个块元素框,该框将随 周围的内容,就好像它是一个单一的内联框(表现得很多 就像被替换的元素一样)

要了解这里发生了什么,我们需要查看vertical-align,它是默认值baseline

在此插图中,您有此颜色图表: 蓝色:基线 红色:行高的顶部和底部 绿色:内嵌内容框的顶部和底部。

在#left 元素中,您确实有一些控制基线的文本内容。这意味着里面的文本定义了#left 的基线。 在#right 中,没有内容,所以浏览器没有其他选择,只能使用框底作为基线。

在这个可视化中,我在一个示例中绘制了基线,其中第一个内联容器有一些文本,而下一个是空的:

如果您专门将一个元素与顶部对齐,则实际上是说您将此元素的顶部与行框的顶部对齐。

这可能通过一个例子更容易理解。

div 
    display: inline-block;
    width: 100px;
    height: 150px;
    background: gray;
    vertical-align: baseline;

div#middle 
    vertical-align: top;
    height: 50px

   
div#right 
    font-size: 30px;
    height: 100px
<div id="left">
  <span>groovy</span>
</div>
<div id="middle">groovy</div>

<div id="right">groovy</div>

结果是这样 - 我添加了蓝色基线和红色线框: 这里发生的情况是,行框的高度取决于整行内容的布局方式。这意味着要计算顶部对齐,必须首先计算基线对齐。 #middle 元素具有vertical-align:top,因此它不用于基线定位。但是#left#right 是垂直定位的,因此它们的基线是对齐的。完成后,行框的高度增加了,因为#right 元素由于较大的字体大小而被推高了一点。然后可以计算出#middle 元素的顶部位置,这就是沿着线框的顶部。

【讨论】:

【参考方案2】:

尝试使所有元素的所有 CSS 属性都相同。

我遇到了类似的问题,在解决这个问题时,我发现我正在将一个具有 Font 属性的元素放入 Div 元素中。

删除具有 Font 属性的元素后,所有 DIV 的对齐都被打乱了。为了解决这个问题,我将所有 DIV 元素的 Font 属性设置为与放入其中的元素相同。

在以下示例中,使用 font-size:30 px 定义的“.dldCuboidButton”类的 Dropped 元素。

所以我将相同的属性添加到其余类,即 DIV 元素使用的 .cuboidRecycle、.liCollect、.dldCollect。这样,所有 DIV 元素在将元素放入其中之前和之后都遵循相同的测量值。

.cuboidRecycle 
    height:40px; 
    width:'20px; float:right';
    overflow:'none';
    background-color:#cab287;
    color:#ffffff; 
    border-radius:8px; 
    text-align:'center'; 
    vertical-align:'top';
    display: inline-block;
    font-size: 30px; /* Set a font-size */



.liCollect 
    height:40px; 
    width:'20px; float:right';
    overflow:'none';
    background-color:#cab287;
    color:#ffffff; 
    border-radius:8px; 
    text-align:'center'; 
    vertical-align:'top';
    display: inline-block;
    font-size: 30px; /* Set a font-size */


.dldCollect 
    height:40px; 
    width:'20px; float:right';
    overflow:'none';
    background-color:#009933;
    color:#ffffff; 
    border-radius:8px; 
    text-align:'center'; 
    vertical-align:'top';
    display: inline-block;
    font-size: 30px; /* Set a font-size */



.dldCuboidButton 
    background-color:  #7c6436;
    color: white; /* White text */
    font-size: 30px; /* Set a font-size */
    border-radius: 8px;
    margin-top: 1px;
  

这是使用上述 CSS 动态创建的 html 示例。

$("div#tabs").append(
  "<div id='" + newTabId + "'>#" + uniqueId + 
  "<input type=hidden id=hdn_tmsource_" + uniqueId + "  value='" + divTmpfest + "'>" + 
  "<input type=hidden id=leCuboidInfo_" + uniqueId + " value=''>" + 
  "<div id='" + divRecycleCuboid + "' class=cuboidRecycle ondrop='removeDraggedCuboids(event, ui)'  ondragover='allowDrop(event)'><font size='1' color='red'> Trash bin </font></div>" +
  "<div id='" + divDropLeCuboid  + "' class=liCollect ondrop='dropForLinkExport(event)'  ondragover='allowDrop(event)'><font size='1' color='red'>Drop Template Manifest Cuboid here</font></div>" +
  "<div id='" + divDropDwldCuboid  + "' class=dldCollect ondrop='dropForTMEntry(event)'  ondragover='allowDrop(event)'><font size='1' color='red'>Drop Template Cuboids here..</font></div>" +
  "</div>" 
);

【讨论】:

【参考方案3】:

尝试将 padding:0; 添加到正文并删除 div 的边距。

在背景*之外添加background-color:*any颜色以检查差异。

【讨论】:

编辑格式化代码的答案,您可以通过在代码开始前和代码结束后添加符号`来格式化代码。如code 例如:.background-color:any color 【参考方案4】:

只需使用vertical-align:top;

Demo

【讨论】:

【参考方案5】:

基本上,您在代码中添加了更多混乱,这会造成更多混乱,所以首先我尝试消除妨碍理解真正问题的混乱。

首先,我们必须确定真正的问题是什么? 这就是为什么“inline-block”元素被向下推的原因。

现在我们开始理解它并首先消除混乱。

1 - 为什么不给所有三个 div 相同的边框宽度? Let's give it.

2 - 浮动元素是否与被向下推的inline-block元素有任何联系? 不,这与它无关。

所以,we have removed that div altogether。而且您正在目睹内联块元素被向下推的相同行为。

现在轮到一些literature 来了解行框的概念以及它们如何在同一行中排列,尤其是仔细阅读最后一段,因为这就是您问题的答案。

'inline-block' 的基线是其在正常流中的最后一个行框的基线,除非它没有流内行框或者它的 'overflow' 属性具有除 'visible 之外的计算值',在这种情况下,基线是底部边缘。

如果您不确定baseline,那么这里是简单的简要说明。

除“gjpqy”之外的所有字符都写在基线上,您可以将基线想象成在这些“随机字符”正下方绘制一条与下划线相同的简单水平线,那么它将是基线,但现在如果您写任何'gjpqy' 字符在同一行,然后这些字符的下部将落在该行下方。

所以,我们可以说除了“gjpqy”之外的所有字符都写在基线之上,而这些字符的一部分写在基线之下。

3 - 为什么不检查我们线的基线在哪里? 我已经添加了我们线路的few characters which show the baseline。

4 - 为什么不在我们的 div 中添加一些字符以在 div 中找到它们的基线? 在这里,some characters added in divs to clarify baseline。

现在当您了解基线时,请阅读以下关于内联块基线的简化版本。

i) 如果有问题的 inline-block 将其溢出属性设置为可见(默认情况下不需要设置)。 那么它的基线将是该行的包含块的基线。

ii) 如果有问题的内联块的溢出属性设置为 OTHER THAN 可见。 那么它的下边距将位于包含框行的基线上。

第一点详解

现在look at this again to clarify your concept that what's happening with green div。 如果还有任何混淆,则 here is added more characters close to green div to establish the baseline of the containing block 和绿色 div 基线对齐。

好吧,我现在声称它们具有相同的基线?对吗?

5 - 那么为什么不将它们重叠起来,看看它们是否合适呢? 所以,我带来了第三个 div -left: 35px; to check if they have same baseline now?

现在,我们已经证明了我们的第一点。

第二点详解

好吧,在解释了第一点之后,第二点很容易理解,您会看到溢出属性设置为可见(隐藏)以外的第一个 div 的下边距位于该行的基线上。

现在,您可以做几个实验来进一步说明它。

    设置first div overflow:visible (or remove it altogether)。 设置second div overflow: other than visible。 设置both divs overflow: other than visible。

现在把你的杂物带回来,看看你是否一切都好。

    带上back your floated div(当然有需要 增加一些身体宽度) 你看它没有效果。 Bring back same odd margins。 设置green div to overflow: visible as you set in your question(未对齐是由于边框宽度从1px增加到5px,所以如果adjust negative left你会看到没有问题) 现在remove additional characters I added to aid in understanding。 (当然要去掉负左) 最后是reduce body width,因为我们不再需要更宽的。

现在我们又回到了起点。

希望我已经回答了你的问题。

【讨论】:

感谢您提供如此出色的解释,但我没有明白您的意思“那么它的基线将是该行包含块的基线。”是否与您在第二点明确指出的基线相同? 延迟回复。我刚刚注意到同样的问题,我只想感谢 Gary Lindahl 的 NICE 解释。 +1 ntgCleaner 尽管我很欣赏很好的答案,但 Gary Lindahl 的阅读量很大,我只漏掉了上面写着“解决方案:XY”的那几行 我发现这个详细的解释非常有用,谢谢。我为一个概念苦苦挣扎了一段时间,并制作了一个updated Fiddle,可能会为其他人澄清。 @ntgCleaner 谢谢伙计.. 即使经过所有的解释,我也无法让它发挥作用。但你的评论做到了:)【参考方案6】:

vertical-align 在 CSS 中的默认值为 baseline 并且此规则也适用于 inline-block 阅读此http://www.brunildo.org/test/inline-block.html

在您的inline-block DIV 中写入vertical-align:top

检查这个http://jsfiddle.net/WGCyu/1/

【讨论】:

你读过我的问题吗?我从来没有要求纠正这个问题。 @ShawnTaylor:问题标题非常具有误导性。我们本能地阅读标题,然后拍摄代码,如果有的话。我们很少阅读实际的文本。这是一个坏习惯,但你应该明白为什么会这样。 :P @sandeep:关于您的编辑,为什么即使vertical-align is removed from it firstDiv 也对齐到顶部 @sandeep:您提供的链接提供了丰富的信息,但它对这个问题没有帮助,因为它没有描述display:inline-block 结合float:left/right 的行为。 @ThomasMcCabe 几乎没有;如果有人发布了一个错误的答案,那么它应该被否决,以向未来的观众发出信号,表明它有问题,无论他们的意图如何。也就是说,我认为这个答案不应该被否决。即使在它的原始形式中,它也提供了一个被接受的答案省略的关键部分 - 基线对齐不是元素垂直对齐的唯一方式,如果你更改 vertical-align 属性,没有任何复杂性接受的答案中描述的适用。【参考方案7】:

查看this 替代示例。 CSS3 module: line: 3.2. Line Box wrapping [1]中描述了这种行为的原因:

一般来说,line box 的起始边接触其包含块的起始边,结束边接触其包含块的结束边。但是,浮动框可能会出现在包含块边缘和行框边缘之间。因此,尽管在同一行内格式化上下文中的行框通常具有相同的行进推进(包含块的行进推进),但如果可用的行进推进空间由于浮动而减少,它们可能会有所不同[...]

如您所见,第三个元素被向下推,尽管它没有overflow 属性。原因必须在其他地方找到。您注意到的第二个行为在Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification: 9.5 Floats [2] 中进行了描述:

由于浮动不在流中,因此在浮动框之前和之后创建的非定位块框垂直流动,就好像浮动不存在一样。但是,浮动旁边创建的当前和后续行框会根据需要缩短,以便为浮动的边距框腾出空间。

您所有的display:inline-block; div 都使用一种特殊的baseline 在这种情况下为10.8 Line height calculations: the 'line-height' and 'vertical-align' properties (very end) [3]:

'inline-block' 的基线是其在正常流中的最后一个行框的基线,除非它没有流入行框,或者它的 'overflow' 属性具有除 'visible 之外的计算值',在这种情况下,基线是底部边缘。

所以当你使用浮动元素和inline-block元素时,浮动元素会被推到一边,内联格式会根据1重新计算。另一方面,如果不合适,下一个元素会被缩短。由于您已经在使用最少的空间,因此没有其他方法可以修改您的元素,然后将它们推送2。在这种情况下,最高元素将定义包装 div 的大小,从而定义baseline3,而另一方面,2 中所述的位置和宽度的修改不能应用于这样的最小间隔的最大高度元素。在这种情况下,将产生我第一个演示中的行为。

最后,您的overflow:hidden 将阻止#firstDiv 被推到#container 的下边缘的原因,尽管我在section 11 中找不到原因。如果没有overflow:hidden,它的工作原理是由2 和3 定义和定义的。 Demo

TL;DR:仔细查看 W3 建议和浏览器中的实现。在我的拙见中,如果您不知道浮动元素对周围元素所做的所有更改,它们就会表现出意想不到的行为。这是另一个demo,它显示了浮点数的常见问题。

【讨论】:

这个“标准”真是一团糟。令人惊讶的是,他们能够使这些东西在浏览器之间表现出一致性。哦等等,不,他们从来没有这样做过。【参考方案8】:

问题是因为您在第二个 div 上应用了 float:left。这使得第二个 div 出现在左侧,你的第一个 div 下降并在你的第二个 div 之后。 如果你在第一个 div 上也应用 float:left,你的问题就会消失。

overflow:hidden 不会对布局造成任何问题,overflow:hidden 只影响 div 的内部元素,与外部的其他元素无关。

【讨论】:

好吧,如果它被推送是因为它在浮动 div 之后排在第二位,那么为什么thirdDiv 不向下? 因为第三个 div 前面有第二个 div 没有 float:left; 但是这条规则在哪里提到,如果浮动的 div 之后出现一些 div,那么它会向下下降?我检查了 w3.org。 不浮动的元素下降到基线,如果你投了反对票,我必须说这是最合乎逻辑的答案 不,我没有投反对票,是的,您的回答不值得否定。刚刚投了赞成票。

以上是关于为啥这个 inline-block 元素被向下推?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 flexbox 在包裹项目时不向下推后续内容?

inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移

inline-block元素设置overflow:hidden属性导致相邻行内元素向下偏移

插入新元素时如何向下推 ID

更改基于选项卡的应用程序上的选项卡会向下推 UI 元素

为啥 Gecko 和 Blink 在处理 inline-block 元素时高度计算如此不一致?