这是CSS中的一个bug吗?

4

这个话题可能听起来有些过时,因为由于flex-box和grid的出现,没有人再使用inline-block属性了,但我想探讨一下并询问一下相关内容。

当创建两个div,并将它们都分配为inline-block显示,然后在其中一个div内添加任何元素时,结果会相当奇怪,包含该元素的那个div将滑动到另一个div的底部,减去添加元素的高度。

div {
    display: inline-block;
    width: 100px;
    height: 150px;
    background: gray;
}
<div id="left">
  <span>Text</span>
</div>
<div id="right"></div>

要解决这个问题,只需要将 div 垂直对齐到顶部即可。但是奇怪的是,即使没有对受影响的 div 进行垂直对齐,我们仍然可以通过对另一个未受影响的 div 进行垂直对齐来得到相同的结果,那么到底发生了什么呢?

div {
    display: inline-block;
    width: 100px;
    height: 150px;
    background: gray;
}

#left{
     vertical-align: baseline;
}

#right{
      vertical-align: top;
}
<div id="left">
  <span>text</span>
</div>
<div id="right"></div>

更新:

为了更清楚地解释,我删除了子元素并在两个div外添加了文本,并添加了两个div,现在所有的div都没有流内容,但前两个都有一个顶部属性,而最后两个则不同,一个是顶部,另一个是基线:

div {
  display: inline-block;
  width: 100px;
  height: 150px;
  background: gray;
}
.right{
  vertical-align:baseline;
}
.left{
  vertical-align:top;
}
Text
<div class="right"></div>
<div class="left"></div>

<br>

Text
<div class="left"></div>
<div class="left"></div>

在第一种情况下,文本被对齐到顶部,而在下一个情况下,它们被对齐到div的基线上,即使它们没有流内容。

2
由于IE浏览器尚未死亡,因此“inline-block”仍然有其用处,而“grid”和“flex”即使在最新版本的IE(而非Edge)中也存在缺陷。 - Jon P
1
这不是一个错误,而是默认的垂直对齐方式为“基线”。 - Temani Afif
1
现在你有一个完整的重复列表,阅读所有内容,一切都会非常清晰,你将学到更多超出你的预期 ;) - Temani Afif
1
是的,我知道您不需要更改两个元素的对齐方式,只需要一个元素需要垂直对齐,而且它不是包含文本的元素,这也在重复内容中有所解释... 您只需要理解基线和包含块的概念(这在所有重复内容中都有描述)。 - Temani Afif
1
两个div块都是内联元素,两者都会受到影响,你错了,认为只有包含文本的那一个会受到影响并向下移动。两个div块都与基线对齐。花时间去读一下相关资料,起步可能不容易,但你会理解的。 - Temani Afif
显示剩余12条评论
2个回答

4
这种情况发生的原因是,内联元素的默认vertical-align值是baseline
那么问题来了: inline-block元素的基线是什么?在这里,我们必须区分具有特定流内容和不具有特定流内容的元素:
  • 对于包含流内容(例如您问题中的左侧div)的元素,基线与最后一个内容元素的基线相同。(*) 对于左侧div,这对应于内部span的基线。
    (*)当设置元素的溢出时,还有一些额外的考虑因素,但我将其排除在范围之外。
  • 对于不包含流内容(例如您问题中的右侧div)的元素,基线是元素边框框盒的底部。对于右侧div,这对应于
    本身的底部。
因此,总结一下:您看到垂直移位的原因是,元素根据它们的基线垂直对齐,并且具有和不具有内容元素的基线计算方式不同。
要测试此内容,请尝试向右侧div添加一些文本,您将看到两个基线现在相同。

div {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: gray;
}
<div id="left">Text</div>
<div id="right">Other text</div>

通过调整字体大小,下面的示例更清楚地演示了基线变化如何影响垂直定位:

div {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: gray;
}

#left {
  transition: all 2s ease;
  animation: anim 2s infinite linear alternate;
}

@keyframes anim {
  0% {font-size: 100%;}
  100% {font-size: 300%;}
}
<div id="left">Text</div>
<div id="right"></div>


2
那解释了当两个div都在基线上时的初始状态。我并不认为它回答了OP的问题,即为什么将任一个div设置为vertical-align: top会消除偏移量。 - Alohci
1
@TemaniAfif - 其实,我认为对于这个问题的完整回答,特别是最新形式的回答,需要解释一下行框是如何构建的。那些没有与顶部和底部行框边缘对齐的项目首先会相互对齐,然后再添加顶部和底部项目。我不确定任何一个重复的回答都做到了这一点。但目前我没有时间写一个适当的答案。 - Alohci
1
@Alohci,如果我没记错的话,您已经在这里完成了它:https://stackoverflow.com/questions/43305825/understand-inline-elemnt-vertical-align-line-box-and-line-height - Temani Afif
1
@TemaniAfif - 我已经这样做了。谢谢。 - Alohci
1
好的,我承认,我错了,这让我感觉像是重新学习CSS一样,我曾经相信CSS要简单得多,但现在我看到了所有这些背后的原理逻辑,谢谢你们的解释,对任何不便表示歉意。 - Tarek.hms
显示剩余8条评论

0

display: inline-block 属性

与 display: inline 相比,主要区别在于 display: inline-block 允许在元素上设置宽度和高度。

此外,使用 display: inline-block,顶部和底部的边距/填充会被尊重,但是使用 display: inline 则不会。

与 display: block 相比,主要区别在于 display: inline-block 不会在元素后添加换行符,因此该元素可以与其他元素并排。

还有一个问题:

请问 textarea 是 inline-block,但哪一行是正确的呢?浏览器认为第二个 inline-block 的底部是行的位置,所以当它绘制子元素时,它会看到 textarea 必须是内联的,并将其位置更改为第二个 inline-block 的底部是行的位置,由于它具有任何填充和相对位置,因此导致父 div 向下移动,只是为了使 textarea 内联。


我找到了,请检查:https://www.w3.org/TR/CSS2/sample.html - Mahdi Aslami Khavari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接