首页 > 解决方案 > 如何在带有列表项的块子元素的html / css有序列表中使项目编号具有自适应性?

问题描述

目标

  1. 使有序列表自定义为:before允许的伪元素样式(AFAIK 任意形状是不可能的)。
  2. 容器内容边缘(即使左侧填充为 时也有边框0)和项目编号(指定为l)之间的间距以及编号和项目(指定为m)之间的间距必须是可调整的。
  3. 由于位数增加,项目编号必须是自适应的。

在此处输入图像描述

  1. li可以有子块元素,如div, p,figure等。

在此处输入图像描述

问题

以下没有定位的解决方案满足前三个要求。

ol {
  counter-reset: section;
}
ol li:before {
  content: "";
  display: inline-block;
  counter-increment: section;
  content: counters(section, ".") " ";
  margin-left: 4px;
  margin-right: 10px;
  padding: 4px 6px;
  background: lightblue;
  border: 1px solid skyblue;
  border-radius: 4px;
}
ol + li {
  margin-top: 6px;
}

小提琴

在此处输入图像描述

但是第四个要求呢?让我们尝试将子元素添加到li

<ol>
  <li>Alpha</li>
  <li>
    <ol>
      <li>
        <p>Lorem ipsum</p>
        <p>Duis aute</p>
      </li>
    </ol>
  </li>
</ol>

在此处输入图像描述

从概念上讲,:before伪元素必须占据一列(它下面的空间必须是空的,直到下一个li)。目前,我只知道一种解决方案:定位。

ol {
  counter-reset: section;
}
ol li {
  position: relative;
}
ol li:before {
  position: absolute;
  left: 0;
  counter-increment: section;
  content: counters(section, ".") " ";
  display: inline-block;
  padding: 4px 6px;
  background: lightblue;
  border: 1px solid skyblue;
  border-radius: 4px;
}
ol li + li {
  margin-top: 12px;
}
ol li > li {
  padding-left: 30px;
}
ol li > li > ol > li {
  padding-left: 44px;
}

菲尔德

除了丑陋之外,这个解决方案只达到了第一个和第四个目标:

对于第四个目标,需要进行垂直间距调整,但并不难。

您能否提出一些替代解决方案?CSS 的灵活性到此结束了吗?

标签: htmlcss

解决方案


这是一个使用 CSS 网格的想法,我将稍微调整您的初始代码:

ol {
  counter-reset: section;
  list-style:none;
  margin:0;
  padding:0;
}
ol li {
  display:grid; /* added this */
  grid-template-columns:auto 1fr; /* auto for the bullet and 1fr for the content*/
  align-items:baseline; /* keep all the text aligned */
}

ol li:before {
  content: "";
  /* make sure the bullet span many rows os it's kept on the first column
     and the content will placed on the second column
   */
  grid-row:span 1000; 
  counter-increment: section;
  content: counters(section, ".") " ";
  margin-left: 4px;
  margin-bottom:3px;
  margin-right: 10px;
  padding: 4px 6px;
  background: lightblue;
  border: 1px solid skyblue;
  border-radius: 4px;
}
ol + li {
  margin-top: 6px;
}
<ol>
  <li>Alpha</li>
  <li>
    <ol>
      <p>Something</p>
      <li>
        <p>Lorem ipsum</p>
        <p>Duis aute</p>
      </li>
    </ol>
  </li>
  <li>Charlie</li>
  <li>Delta</li>
  <li>Echo</li>
  <li>Foxtrotg</li>
  <li>Golf</li>
  <li>Hotel</li>
  <li>India</li>
  <li>Juliet</li>
</ol>

或者像下面这样:

ol {
  counter-reset: section;
  list-style:none;
  margin:0;
  padding:0;
}
ol li {
  display:grid; /* added this */
  grid-template-columns:auto 1fr; /* auto for the bullet and 1fr for the content*/
  align-items:baseline; /* keep all the text aligned */
}
ol li > * {
  grid-column:2; /* all the content in the second column and keep only the bullet in the first*/
}
ol li:before {
  content: "";
  counter-increment: section;
  content: counters(section, ".") " ";
  margin-left: 4px;
  margin-bottom:3px;
  margin-right: 10px;
  padding: 4px 6px;
  background: lightblue;
  border: 1px solid skyblue;
  border-radius: 4px;
}
ol + li {
  margin-top: 6px;
}
<ol>
  <li>Alpha</li>
  <li>
    <ol>
      <p>Something</p>
      <li>
        <p>Lorem ipsum</p>
        <p>Duis aute</p>
      </li>
    </ol>
  </li>
  <li>Charlie</li>
  <li>Delta</li>
  <li>Echo</li>
  <li>Foxtrotg</li>
  <li>Golf</li>
  <li>Hotel</li>
  <li>India</li>
  <li>Juliet</li>
</ol>


推荐阅读