定位 div 中 uls 的高度之谜:它是如何工作的?

mystery of the height of uls in positioned divs: How does it even work?

我对css、盒模型和一般定位有一定的了解。

但是有一个谜团我从来没有摸索过,我也无法google理解它,很多时候它减慢了我的布局实现速度:

The mystery of the ul inside a positioned div

为什么我必须将 ul font-size 设置为 0,将 line-height 设置为 1,然后将它们重置为我希望它们在 li 为了使 ul 成为正确的高度并且(似乎)包含在 div?

如果我将ul line-height设置为我想要的标称行高,神秘的额外高度从何而来?为什么这个额外的高度在每个浏览器上都不一样?

还有很多其他方法可以得到神秘的高度和偏移量,但我觉得如果我理解这些情况,我就会有一个足够的模型。

有没有人拥有可以让我预测这些行为的心智模型? (因此希望记住它们,这样我就不会浪费时间每 6 个月重新计算一次)?

Here is a playground demonstrating what I seek to understand.

section {
  background-color: gray;
  width: 500px;
  height: 700px;
  padding-top: 10px;
  font-size: 12px;
  line-height: 25px;
}
.reference {
  background-color: aquamarine;
  height: 25px;
  width: 75px;
  float: left;
  padding: 0;
  margin: 0;
}
.container {
  padding: 0;
  margin: 0;
  background-color: white;
  height: 25px;
  width: 423px;
}
ul {
  list-style-type: none;
  background-color: rgba(255, 50, 50, 0.25);
}
li {
  display: inline;
}
.case-one {
  display: inline-block;
}
.reference-two {
  position: absolute;
  top: 130px;
}
.reference-two-b {
  position: absolute;
  top: 200px;
}
.case-two {
  position: absolute;
  left: 85px;
}
.case-two-a {
  top: 130px;
}
.case-two-b {
  top: 200px;
}
.case-two ul {
  position: relative;
  font-size: 0px;
}
.case-two-a ul {
  line-height: 1;
}
.case-two-b ul {
  line-height: 25px;
}
.case-two li {
  display: inline;
  font-size: 12px;
  line-height: 25px;
}
<section>
  <div class="container case-one">this I fully understand</div>
  <div class="reference">case one</div>
  <br/>
  <br/>


  <div class="container case-one">
    <div style="background-color: rgba(50,50,200,0.4); width:8px;height: 12px; position: absolute;"></div>
    <ul>
      <li>but</li>
      <li>not this.</li>
      <li>why is the ul offset?</li>
      <li>why by font-size, not line-height?</li>
    </ul>
  </div>
  <div class="reference">case one b</div>


  <div class="container case-two case-two-a">
    <ul>
      <li>why does</li>
      <li>setting the ul font-size to 0 work?</li>
    </ul>
    <div style="line-height: 1.2;">also, why does the ul line-height have to be set to 1? If it is set to 25px, the ul grows, see below</div>
  </div>
  <div class="reference reference-two">case two</div>

  <div class="container case-two case-two-b">
    <div style="background-color: rgba(50,50,200,0.4);left:4px;width:8px; height: 30px; position: absolute;"></div>
    <div style="background-color: rgba(50,200,50,0.4);width:8px; height: 29px; position: absolute;left:16px;"></div>
    <div style="background-color: rgba(200,50,50,0.4);width:8px; height: 28px; position: absolute;left:28px;"></div>
    <ul>
      <li>why does</li>
      <li>setting the ul line-height to 25px result in it being 30px high?</li>
    </ul>
    <div style="line-height: 1.4;margin-top: 8px;">where does the 5px come from?? Why is it 4px on chrome? Why is it 3px on firefox? Anyone else get any other heights, lol?</div>
  </div>
  <div class="reference reference-two-b">case two</div>

</section>

是不是因为要去掉默认的margin

ul{
   margin:0;
}

看到这个Fiddle

是的。您需要的心智模型是 strut。这似乎是 CSS 最好的秘密,这很不幸,因为它对于理解案例二和许多类似行为至关重要。找出支柱的位置和高度,许多布局行为开始变得有意义。

首先,案例一。浏览器将 ul 元素的默认顶部(和底部)边距定义为字体大小的比例。不同的浏览器可以自由设置他们想要的任何比例,因此某种重置或规范化是司空见惯的。

现在案例二,回到支柱。仅包含行内级元素的块盒由一堆行盒组成。每个行框都以一个零宽度的虚拟内联元素开始——strut。现在,行高只影响行内元素。但是当您设置块元素的行高时,每个子元素(包括支柱)都会继承该行高。您可以覆盖真正的子元素的行高,但不能覆盖 strut。

所以当你说 ul { font-size:0; line-height:1; } 时,这意味着支柱的高度将是 0px 乘以系数 1 = 0px,所以无论支柱在哪里,它都不会占用 space .

但是,当您说 ul { line-height:24px; } 时,这意味着支柱的有效高度将为 24px。内联元素的行高通过在元素字符的上方和下方添加 space 来影响它们所在文本行的高度。因此,如果字符高 18px,行高为 24px,则要添加的额外 space 为 6px。这叫做leading。行距的一半添加在元素上方,一半添加在元素下方。这些被称为 half-leading.

因此,如果您有 ul { font-size:0; line-height:24px; },每行文本的支柱的字符大小为 0,但上下半行距为 12px。但是其他元素的字符大小不为零。如果他们的字体 em 大小是 12px,这可能取决于字体,给使用的字符高度 16px(比如基线以上 13px 和基线以下 3px)。所以他们将领先一半 (24px - 16px) / 2 = 4px.

但除了他们的高度,您还必须考虑他们的垂直对齐方式。支柱始终是“vertical-align:baseline”,并在此基础上与该行文本上的其他内联元素对齐。

为简单起见,我们假设其他文本元素也是 vertical-align:baseline

那么文本行的总行高是基线以上的最大高度 max(13px + 4px (character), 12px (strut) 加上基线以下的最大高度 max(3px + 4px (character), 12px (strut)。这是 17px + 12px = 29px,因此超过了指定的 24px 行高。

Lister 先生在 an answer to a related question

中提供了一些有用的图表