CSS网格布局 - 强制列表项之间的列宽相同

3

我有一个包含多个文本部分的<ul>列表。

我希望每个文本部分尽可能窄,但同时希望它们在所有项目中垂直对齐。例如:

<ul>
  <li> A. Name     | Some complex address        | 555-1234 </li>
  <li> Longer Name | Short Addr.                 | 555-1234 </li>
  <li> P. Diddy    | No home                     | 555-1234 </li>
</ul>

我希望CSS Grid可以帮我解决这个问题,但我不知道该怎么做...

ul {
  list-style: none;
  display: grid;
  justify-content: stretch; 
}

li {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-column-gap: 10px;
}

p:nth-child(1) {
  background: #EEEEEE;
  border-right: 1px solid;
}

p:nth-child(2) {
   background: #CECECE;
   border-right: 1px solid;
}


p:nth-child(3) {
    background: #EEEEEE;
}
<ul>
  <li>
    <p>A. Name</p>
    <p>Some complex address</p>
    <p>555-1234</p>
  </li>
  <li>
    <p>Longer Name</p>
    <p>Short Addr.</p>
    <p>555-1234</p>
  </li>
  <li>
    <p>P. Diddy</p>
    <p>No home</p>
    <p>555-1234</p>
  </li>
</ul>

CSS Grid是不适合这项工作的吗?还是我漏掉了什么?


我知道这样说可能会被踩,但是<table>标签可以满足你的需求。 - ecg8
是的,但是<table>标签也有它自己的问题。 - Vegar
您需要将HTML压平,使所有内容项成为同一容器中的兄弟,并能够识别网格容器行(请注意,这种做法对HTML语义不利)。 - Michael Benjamin
1
或者您可以等待浏览器实现Grid的子网格功能,它允许网格容器的后代(超出子元素)识别顶级容器线。 - Michael Benjamin
我在多次尝试使用子网格之前才注意到“此功能尚未实现”的提示... :-( - Vegar
1
@Michael_B 或者等待显示:内容,可能会在 subgrid 之前出现.... https://css-tricks.com/get-ready-for-display-contents/ - vals
2个回答

3

为了达到这个效果,它们需要属于同一个网格,因此您可以尝试像这样做:

是的,没有更多的列表了

.list {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-column-gap: 10px;
}

p:nth-child(3n + 1) {
  background: #EEEEEE;
  border-right: 1px solid;
}

p:nth-child(3n +2) {
  background: #CECECE;
  border-right: 1px solid;
}

p:nth-child(3n+3) {
  background: #EEEEEE;
}
<div class="list">
  <p>A. Name</p>
  <p>Some complex address</p>
  <p>555-1234</p>

  <p>Longer Name</p>
  <p>Short Addr.</p>
  <p>555-1234</p>

  <p>P. Diddy</p>
  <p>No home</p>
  <p>555-1234</p>
</div>

或者考虑使用display:table,您可以保留列表结构:

.list {
  display: table;
  margin:0;
  padding:0;
  border-spacing: 10px;
}
.list li {
  display:table-row;
}
p {
 display:table-cell;
}
p:nth-child(1) {
  background: #EEEEEE;
  border-right: 1px solid;
  white-space:nowrap;
}

p:nth-child(2) {
  background: #CECECE;
  border-right: 1px solid;
  width:100%;
}

p:nth-child(3) {
  background: #EEEEEE;
  white-space:nowrap;
}
<ul class="list">
<li>
  <p>A. Name</p>
  <p>Some complex address</p>
  <p>555-1234</p>
</li>
<li>
  <p>Longer Name</p>
  <p>Short Addr.</p>
  <p>555-1234</p>
</li>
<li>
  <p>P. Diddy</p>
  <p>No home</p>
  <p>555-1234</p>
</li>
</ul>


也许 display: table 是正确的方式。我想保持层次结构。通常,每个列表项都将是一个 React 组件,尽管可以将组件呈现为一组顶级 <p> 而不是包含子元素的 <li>,但我不确定是否要这样做... - Vegar
@Vegar 是的,但目前还不支持。https://dev59.com/AKjka4cB1Zd3GeqPD8je#48613967 - Temani Afif
我完全同意“应该使用表格”的观点。或者,至少要使用display:table(你的第二个片段)。这应该是被接受的答案。 - vals
我同意这是最好的答案。但我仍然有一些担心,因为它存在一些限制。对于需要使用“hack”的情况,其中一个项目跨越多个表行以在普通表格中垂直传播数据,我想这里也需要相同的“hack”。我的解决方案将是在项目级别上使用网格,并通过具有固定大小列的方式来对齐项目。至少对于我目前的情况,这将可以正常工作。 - Vegar

3

解决这个问题的新方法是使用display: content。

它将使您的HTML保持语义化,同时扁平化。

支持仍然较低, 但可能比subgrid更快地到来。

您可能会发现CSS Tricks上的这篇文章很有趣。

ul {
  list-style: none;
  justify-content: stretch; 
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-column-gap: 10px;
}

li {
  display: contents; /* make it disapear */
}

li:nth-child(odd) {
  background-color: red;
  color: blue;
  font-weight: bold;
}

p:nth-child(1) {
  border-right: 1px solid;
  background-color: inherit;
}

p:nth-child(2) {
   background: #CECECE;
   border-right: 1px solid;
}


p:nth-child(3) {
    background: #EEEEEE;
}
<ul>
  <li>
    <p>A. Name</p>
    <p>Some complex address</p>
    <p>555-1234</p>
  </li>
  <li>
    <p>Longer Name</p>
    <p>Short Addr.</p>
    <p>555-1234</p>
  </li>
  <li>
    <p>P. Diddy</p>
    <p>No home</p>
    <p>555-1234</p>
  </li>
</ul>


添加到li元素的“stuff”会发生什么?例如选择状态/样式? - Vegar
在问题的评论中链接的文章给出了答案:使div不生成任何框,因此其背景、边框和填充不会被渲染。 - Vegar
1
li元素的颜色并没有被渲染,但是p元素继承了它的颜色。至于背景色,它不会被使用因为它被覆盖了。 - vals
我喜欢这个 display: contents,已经在想很多可以用它做的技巧了 :p - Temani Afif

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