为什么 flexbox 会影响其包含列表项的标记?

Why does flexbox affect its containing list-item's marker?

知道后,我用容器包裹我的内容,然后将容器放入<li />

有内容的元素一切顺利。 但是,如果容器中的第一个元素没有子节点,<li /> 的标记意外位于底部。

虽然在我的情况下我可以简单地添加一个 display: none 来解决问题,但我仍然感到困惑: flexbox中的内容如何影响它的祖父节点?

示例:(标记 1. 位于 <li /> 的右下角)

.flex { display: flex; }
<ol style="width: 15em">
    <li>
        <div class="flex">
            <div></div>
          <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
        </div>
    </li>
    <li>
        <div class="flex">
            <div>TITLE</div>
            <div>If there's content in the first element, then it goes as expected.</div>
        </div>
    </li>
    <li>
        <div class="flex">
            <div>It's also fine if there's only one child here.</div>
        </div>
    </li>
</ol>

相关问题: CSS伪元素::marker在流行的浏览器中没有实现,只有Firefox支持@counter-style。目前建议在 <ol /> 中实现用户定义的标记是什么? (我看到有些人使用 ::before 这样做,目的是让用户不要复制标记的文本。但我不知道它是否好。)

我不确定您要在元素内使用 flexbox 来完成什么,但是 display flex 内的空元素会塌陷,因此会产生奇怪的影响。您可以通过使用 flex: numberflex-basis: 50px

给元素一个 "size" 来解决这个问题

我会避免使用 ::marker 属性,因为它有 horrific support 并且只需使用 css 计数器创建您自己的属性。

这是一个例子:

ol {
  display:block;
  width: 30em;
  list-style: none;
  counter-reset: counterName;
}
li {
 padding-left: 2em;
 padding-bottom: 1em;
 border-bottom: 1px solid #ccc;
 margin-bottom: 1em;
 position: relative;
 counter-increment: counterName;
}
li:before {
  content:'#' counter(counterName);
  position: absolute;
  left:0;
  top:0;
}

.flex {
  display:flex;
  justify-content: space-between;
  flex-wrap:no-wrap;
}

.flex > * {
  flex: 1;
}
<ol>
    <li>
        <div class="flex">
            <div></div>
          <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
        </div>
    </li>
    <li>
        <div class="flex">
            <div>TITLE</div>
            <div>If there's content in the first element, then it goes as expected.</div>
        </div>
    </li>
    <li>
        <div class="flex">
            <div>It's also fine if there's only one child here.</div>
        </div>
    </li>
</ol>

要解决这个问题,只需将对齐方式调整为基线:(最后的另一个解决方案)

.flex {
  display: flex;
  align-items:baseline;
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div></div>
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>TITLE</div>
      <div>If there's content in the first element, then it goes as expected.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>


为了更好地理解正在发生的事情(基于我自己的解释)让我们为空元素添加一些宽度和背景:

.flex {
  display: flex;
}
div:empty {
  width:30px;
  background:red;
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div></div>
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>TITLE</div>
      <div>If there's content in the first element, then it goes as expected.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>

由于默认对齐,空元素被拉伸,然后数字旋转与其底部对齐。

如果你increase/decrease身高你会更好地注意到这个

.flex {
  display: flex;
}
div:empty {
  width:30px;
  background:red;
  animation:change 5s linear infinite alternate;
}
@keyframes change {
   from {
     height:5px;
   }
   to  {
     height:80px;
   }
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div></div>
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>TITLE</div>
      <div>If there's content in the first element, then it goes as expected.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>

如果您将第一个弹性项目中的 inline-block 元素设置为 overlow:hidden(使其基线成为底部边框)

,也会发生这种情况

.flex {
  display: flex;
}
div:empty {
  width:30px;
  background:red;
}
.inline-block {
  display:inline-block;
  height:50px;
  background:green;
  width:50px;
  overflow:hidden;
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div></div>
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div><div class="inline-block">some text </div></div>
      <div>TITLE</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>

基本上,numerotation 试图与第一项的基线对齐。如果你增加第一项的 font-size 我们也可以注意到这一点:

.flex {
  display: flex;
}
.size {
  animation:change 5s linear infinite alternate;
}
@keyframes change {
   from {
     font-size:5px;
   }
   to  {
     font-size:30px;
   }
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div></div>
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div class="size">TITLE</div>
      <div>If there's content in the first element, then it goes as expected.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>


正如您已经注意到的,只有当它是关于第一个项目时才会发生这种情况,这使得它有点复杂并且不容易解释:

.flex {
  display: flex;
}
div:empty {
  width:30px;
  background:red;
}
.inline-block {
  display:inline-block;
  height:50px;
  background:green;
  width:50px;
  overflow:hidden;
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
      <div></div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>TITLE</div>
      <div><div class="inline-block">some text </div></div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>

除了更改对齐方式之外的另一个解决方法是考虑在 flexbox 容器内使用一个伪元素,它将成为我们的第一个 flex 项目,从而避免与我们的 real 元素进行任何交互。

诀窍是不要让该元素为空,但至少要有一个内容。我使用了零宽度 space 字符 0B:

.flex {
  display: flex;
}
.flex:before {
  content:"0B"; /*a non collapsible white space*/ 
}
div:empty {
  width:30px;
  background:red;
  animation:change 5s linear infinite alternate;
}
@keyframes change {
   from {
     height:5px;
   }
   to  {
     height:80px;
   }
}
.size {
  color:green;
  animation:size 5s linear infinite alternate;
}
@keyframes size {
   from {
     font-size:5px;
   }
   to  {
     font-size:20px;
   }
}
<ol style="width: 15em">
  <li>
    <div class="flex">
      <div></div>
      <div>When an element without content is preceding, the ::marker of the list-item is located at the bottom.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div class="size">TITLE</div>
      <div>If there's content in the first element, then it goes as expected.</div>
    </div>
  </li>
  <li>
    <div class="flex">
      <div>It's also fine if there's only one child here.</div>
    </div>
  </li>
</ol>