【问题标题】:Add dividing line between flex items with equal space distribution在具有相等空间分布的弹性项目之间添加分界线
【发布时间】:2017-05-28 14:53:21
【问题描述】:

我有一个包含不同项目的列表,这些项目具有自动宽度(在我的情况下不能给出固定宽度)。我使用justify-content: space-between,因为我的第一项必须从容器的开头开始,而我的最后一项必须在末尾。

以上所有方法都可以正常工作,但是每当我尝试在这些列表项之间添加一条线时,问题就开始出现。我无法确定我必须定位这些行有多少 px 或 %。有没有办法“动态”定位不同列表项之间的行?

我们使用的 html 是不可编辑的,因为它是由我们使用的 CMS 呈现的。

这就是我所拥有的:

这就是我努力实现的目标

这是我目前拥有的代码

html {
    box-sizing: border-box;
}

.Container {
    max-width: 70%;
    margin-right: auto;
    margin-left: auto;
    background: blue;
    padding-top: 20px;
    padding-bottom: 20px;
}

.Flex {
    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
    list-style: none;
    margin: 0;
    padding: 0;
}

.Flex-item {
    background: red;
    position: relative;
}

.Flex-item:after {
    content: "";
    position: absolute;
    background: white;
    width: 1px;
    height: 40px;
    top: 50%;
    transform: translateY(-50%);
}
<div class="Container">
    <ul class="Flex">
         <li class="Flex-item">Lorem</li>
         <li class="Flex-item">consectetur</li>
         <li class="Flex-item">vestibulum</li>
         <li class="Flex-item">nec</li>
         <li class="Flex-item">condimentum</li>
    </ul>
</div>

【问题讨论】:

    标签: html css flexbox


    【解决方案1】:

    不要使用:after,而是使用一种风格的、ARIA 代表性的 LIs

    <li class="separator" aria-hidden="true" role="presentation"></li>
    

    喜欢:

    .Container {
      max-width: 70%;
      margin: 0 auto;
      background: blue;
    }
    
    .Flex {
      display: flex;
      justify-content: space-between;
      list-style: none; padding: 20px 0; margin:0;
    }
    
    .Flex-item {
      background: red;
    }
    
    .separator {
      background: white; width: 1px;
    }
    <div class="Container">
      <ul class="Flex">
        <li class="Flex-item">Lorem</li>
        <li class="separator" aria-hidden="true" role="presentation"></li>
        <li class="Flex-item">consectetur</li>
        <li class="separator" aria-hidden="true" role="presentation"></li>
        <li class="Flex-item">vestibulum</li>
        <li class="separator" aria-hidden="true" role="presentation"></li>
        <li class="Flex-item">nec</li>
        <li class="separator" aria-hidden="true" role="presentation"></li>
        <li class="Flex-item">condimentum</li>
      </ul>
    </div>

    P.S:是的,我最初尝试在 :after 伪上使用 display: list-item,但不适用。

    【讨论】:

    • 嘿伙计,感谢您的回复。不幸的是,我们无法修改 html,因为 html 是由我们的 CMS 呈现的:/。所以添加分隔符不是一种选择
    • 此外,辅助技术现在将看到一个包含 10 项的列表。
    【解决方案2】:

    我正在我正在进行的项目中使用此解决方案。

    它在弹性容器上设置justify-content: space-between;,在子容器上设置flex: 1 1 auto;,除了第一个之外,所有子容器都有左边框。

    我修改了您的示例 CSS,以便您查看。我不确定您是否要在孩子身上设置背景颜色,所以我只是使用 line-height 来获得更大的边框。

    html {
        box-sizing: border-box;
    }
    
    .Container {
        max-width: 70%;
        margin-right: auto;
        margin-left: auto;
        background: blue;
        padding-top: 20px;
        padding-bottom: 20px;
    }
    
    .Flex {
        display: flex;
        flex-flow: row wrap;
        justify-content: space-between;
        list-style: none;
        margin: 0;
        padding: 0;
    }
    
    .Flex-item {
        flex: 1 1 auto;
        background: red;
        position: relative;
        text-align: center;
        line-height: 40px;
    }
    
    .Flex-item + .Flex-item {
        border-left: solid 1px white;
    }
    
    /** Optional for OPs exact layout */
    
    .Flex-item:first-child {
        text-align: left;
    }
    
    .Flex-item:last-child {
        text-align: right;
    }
    <div class="Container">
        <ul class="Flex">
            <li class="Flex-item">Lorem</li>
            <li class="Flex-item">consectetur</li>
            <li class="Flex-item">vestibulum</li>
            <li class="Flex-item">nec</li>
            <li class="Flex-item">condimentum</li>
        </ul>
    </div>

    不修改 HTML。

    【讨论】:

    • 我看到这与 OP 所需布局之间的一个区别是第一个和最后一个项目不与左右边缘齐平。
    • 当然。我不记得我在剪断时是否意识到这一点,但如果需要,可以通过添加 Flex-item:first-child { text-align: left; } Flex-item:last-child { text-align: right; } 来修复它。我也编辑了原始解决方案。
    • 第一个和最后一个项目现在比其他项目有更大的间距。是否可以使其保持一致?
    • .Flex-item + .Flex-item这样添加两次Flex-item有什么意义?
    • 这是相邻兄弟的 CSS 选择器。因此,类 Flex-item 的元素与类 Flex-item 的元素相邻的元素在左侧有一个边框。在这种情况下,它是“跳过”具有左边框的第一个元素。这样你就不必写.Flex-item:first-child { border-left: 0; }developer.mozilla.org/en-US/docs/Web/CSS/…
    【解决方案3】:

    如果你覆盖flex,你可能会得到一些接近的东西,而不需要任何额外的标记。

    它涉及pseudos,order & css3 选择器(除了flex)。

    http://codepen.io/gc-nomade/pen/BpzYWP

    body {
      margin:0;
    }
    
    .Flex, .Flex-item {
      display:flex;
      padding:0.5em 0;
      margin:0;
    }
    .Flex-item  {
      flex:1;/*spray them evenly*/
      
    }
    .Flex-item:before,
    .Flex-item:after {/* add pseudos to fill extra space */
      content:'';
      flex:1;/* thats where it takes room not use by the text */
      margin:-1em 0;/* grow them taller */
      border-right:solid 1px white;
    }
    .Flex-item:first-child:before
    {
      order:2;/* put both pseudo after text*/ 
      flex:.5;/* shrink that one can be .75 to .25 */
      border:none; /* remove the border useless for the show */
    }
    
    .Flex-item:last-child:after {
      order:-1;/* put both pseudos before text */
      flex:0.5;/* shrink that one can be .75 to .25 */
    }
    .Flex-item:first-child + .Flex-item:before ,
    .Flex-item:nth-last-child(1):after{
      border:none; /* remove the border useless for the show */
    }
    body, :after, :before {
      background:tomato;/* pseudo will hide li background */
    }
    li {
      background:turquoise;
    }
    
    /* give some space around the text */
    .Flex-item:first-child {
      padding-left:1em;
    }
    .Flex-item:last-child {
      padding-right:1em;
    }
    .Flex-item:before {
      border:none;/* we do not need those after all */
      margin-right:1em;
    }
    .Flex-item:after {
      margin-left:1em;
    }
    .Flex-item:first-child:before {
      margin:-1em 0;
    }.Flex-item:last-child:after {
      margin:-1em 0;
    }
    <div class="Container">
        <ul class="Flex">
             <li class="Flex-item">Lorem</li>
             <li class="Flex-item">consectetur</li>
             <li class="Flex-item">vestibulum</li>
             <li class="Flex-item">nec</li>
             <li class="Flex-item">condimentum</li>      
        </ul>
    </div>

    【讨论】:

      【解决方案4】:

      我认为使用 flexbox 完成此操作的唯一方法是将文本包装在一个新元素中,就像 @Kukkuz 在 another answer 中所做的那样。

      没有那个额外的包装,你仍然可以得到等间距的分隔符,但红色背景并不局限于文本的长度。

      下面是一个例子:

      • HTML 没有变化。
      • 不需要伪元素。
      • 无需绝对定位。

      如果不需要文本的背景颜色,则将其删除,这应该就是您所需要的。

      .Flex {
        display: flex;
        list-style: none;
        margin: 0;
        padding: 0;
      }
      .Flex-item {
        flex: 1 1 auto;
        background: red;
      }
      .Flex-item {
        text-align: center;
      }
      .Flex-item:first-child {
        text-align: left;
      }
      .Flex-item:last-child {
        text-align: right;
      }
      .Flex-item + .Flex-item {
        border-left: 1px solid white;
      }
      .Container {
        max-width: 70%;
        margin-right: auto;
        margin-left: auto;
        background: blue;
        padding-top: 20px;
        padding-bottom: 20px;
      }
      <div class="Container">
        <ul class="Flex">
          <li class="Flex-item">Lorem</li>
          <li class="Flex-item">consectetur</li>
          <li class="Flex-item">vestibulum</li>
          <li class="Flex-item">nec</li>
          <li class="Flex-item">condimentum</li>
        </ul>
      </div>

      如果您可以在文本周围添加span,这将允许您将红色背景限制为文本的长度,那么您就大功告成了:

      .Flex {
        display: flex;
        list-style: none;
        margin: 0;
        padding: 0;
      }
      .Flex-item {
        flex: 1 1 auto;
        display: inline-flex;
        justify-content: center;
      }
      .Flex-item span {
          background-color: red;
      }
      .Flex-item:first-child span {
        margin-right: auto;
      }
      .Flex-item:last-child span {
        margin-left: auto;
      }
      .Flex-item + .Flex-item {
        border-left: 1px solid white;
      }
      .Container {
        max-width: 70%;
        margin-right: auto;
        margin-left: auto;
        background: blue;
        padding-top: 20px;
        padding-bottom: 20px;
      }
      <div class="Container">
        <ul class="Flex">
          <li class="Flex-item"><span>Lorem</span></li>
          <li class="Flex-item"><span>consectetur</span></li>
          <li class="Flex-item"><span>vestibulum</span></li>
          <li class="Flex-item"><span>nec</span></li>
          <li class="Flex-item"><span>condimentum</span></li>
        </ul>
      </div>

      【讨论】:

        【解决方案5】:

        您可以使用 嵌套 flexboxes 使其工作 - 我知道您无法更改标记,但至少您必须包装内容将li 转换为span,就像我在这里一样:

        1. .flex-item 也设为flexbox,将span 中的文本(现在将具有红色背景)和分隔符 作为:after 元素

        2. flex-growflex-shrink 应用于Flex-item 1 和flex-basisauto

        3. flex: 0 到最后一个 Flex-itemmargin-auto:after 也有助于效果。

        演示可能会更好地解释它 - 见下文:

        html {
          box-sizing: border-box;
        }
        .Container {
          max-width: 70%;
          margin-right: auto;
          margin-left: auto;
          background: blue;
          padding-top: 20px;
          padding-bottom: 20px;
        }
        .Flex {
          display: flex;
          justify-content: space-between;
          list-style: none;
          margin: 0;
          padding: 0;
        }
        .Flex-item {
          display: flex;
          justify-content: space-between;
          align-items: center;
          flex: 1 1 auto;
        }
        .Flex-item span {
          background: red;
        }
        .Flex-item:not(:last-child):after {
          content: "";
          border: 1px solid white;
          height: 40px;
          margin: auto;
        }
        .Flex-item:last-child {
          flex: 0;
        }
        <div class="Container">
          <ul class="Flex">
            <li class="Flex-item">
              <span>Lorem</span>
            </li>
            <li class="Flex-item">
              <span>consectetur</span>
            </li>
            <li class="Flex-item">
              <span>vestibulum</span>
            </li>
            <li class="Flex-item">
              <span>nec</span>
            </li>
            <li class="Flex-item">
              <span>condimentum</span>
            </li>
          </ul>
        </div>

        【讨论】:

        • 这个答案可能无效,因为它改变了标记,这不是一个选项,如问题中所述。
        【解决方案6】:

        试试这个

        html {
            box-sizing: border-box;
        }
        
        .Container {
            max-width: 90%;
            margin-right: auto;
            margin-left: auto;
            background: blue;
            padding-top: 11px;
            padding-bottom: 50px;
        }
        
        .Flex {
            list-style: none;
            margin: 0;
            padding: 0;
            position: relative;
            left: 50%;
            transform: translateX(-50%);
            float: left;
        }
        
        .Flex-item {
            position: relative;
            float: left;
            padding: 5px 10px;
            border-right:1px solid #fff;
        }
        .Flex-item:last-child{border-right:none;}
        
        .Flex-item >div{
          margin:0 5px;
          background:red;
          padding:5px;
        }
        <div class="Container">
            <ul class="Flex">
                 <li class="Flex-item"><div>
                 Lorem
                 </div></li>
                 <li class="Flex-item"><div>
                 consectetur
                 </div></li>
                 <li class="Flex-item"><div>
                 vestibulum
                 </div></li>
                 <li class="Flex-item"><div>
                 nec
                 </div></li>
                 <li class="Flex-item"><div>
                 condimentum
                 </div></li>
            </ul>
        </div>

        【讨论】: