【问题标题】:How to create "collapsed" borders around flex items and their container?如何在弹性项目及其容器周围创建“折叠”边框?
【发布时间】:2016-06-11 05:46:48
【问题描述】:

我有以下布局:

#limited-width {
  width: 100%;
  max-width: 200px;
  margin: 0 auto;
  font-size: 18px;
}
ul {
  display: flex;
  flex-flow: row wrap;
  list-style: none;
  padding: 0;
  margin: 20px;
}
ul > li {
  display: block;
  text-align: center;
  flex: 1 0 auto;
  max-width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 4px 7px;
  border: 2px solid rgba(0,0,0,.3);
  background-color: rgba(0,0,0,.03);
}
<div id="limited-width">
  <ul>
    <li>Apple</li>
    <li>Orange</li>
    <li>Pineapple</li>
    <li>Banana</li>
    <li>Tomato</li>
    <li>Pear</li>
    <li>Lemon</li>
  </ul>
</div>

如您所见,ul 内的列表项有一个宽度为2px 的边框,但正因为如此,元素之间的边框加倍了。我正在寻找一种方法来使元素之间的边框宽度相同,同时使用 flexbox 保持外部边框相同(类似于border-collapse 在表格上的工作方式)。这可能吗?如果可以,怎么做?

【问题讨论】:

    标签: css border flexbox


    【解决方案1】:

    有两种主要方法可以实现这一目标。在每种方法下,您都会找到一个工作演示,您可以展开它来查看它的行为方式。将鼠标悬停在元素上会给它们一个红色边框,以便您更轻松地选择最适合您的方法。

    父子边框对齐

    你需要像这样定义边框:

    ul, ul > li {
      border-style: solid;
      border-color: rgba(0,0,0,.3);
    }
    ul      { border-width: 2px  0   0  2px }
    ul > li { border-width:  0  2px 2px  0  }
    

    这里的关键在border-width 属性中:

    • 在容器上,topleft 的值设置为所需大小,而 rightbottom 设置为 0
    • 在项目上,rightbottom 的值设置为所需大小,而 topleft 设置为 0

    通过这样做,边框将以某种方式叠加起来,从而在元素和容器周围形成一个折叠良好、一致的边框。

    :hover { border-color: red }
    #limited-width {
      width: 100%;
      max-width: 200px;
      margin: 0 auto;
      font-size: 18px;
    }
    ul, ul > li {
      border-style: solid;
      border-color: rgba(0,0,0,.3);
    }
    ul {
      display: flex;
      flex-flow: row wrap;
      list-style: none;
      padding: 0;
      margin: 20px;
      border-width: 2px 0 0 2px;
    }
    ul > li {
      display: block;
      text-align: center;
      flex: 1 0 auto;
      max-width: 100%;
      box-sizing: border-box;
      margin: 0;
      padding: 4px 7px;
      border-width: 0 2px 2px 0;
      background-color: rgba(0,0,0,.03);
    }
    <div id="limited-width">
      <ul>
        <li>Apple</li>
        <li>Orange</li>
        <li>Pineapple</li>
        <li>Banana</li>
        <li>Tomato</li>
        <li>Pear</li>
        <li>Lemon</li>
      </ul>
    </div>

    边框减半

    如果您出于任何目的想要为每个元素设置不同的边框,这可能是一种适合您需求的折衷方案。给定所需的border-width2px,CSS 如下:

    ul, ul > li {
      border: 1px solid rgba(0,0,0,.3);
    }
    

    此方法在父项及其子项上设置所需边框宽度的一半,使最终边框2px 变粗。小心使用这种带有小数像素的方法(例如1.5px),你可以使用run into issues

    使用border-color-更改规则时,半角会很明显,但如果您想要更好看的边框,这比第一种方法要好得多。

    :hover { border-color: red }
    #limited-width {
      width: 100%;
      max-width: 200px;
      margin: 0 auto;
      font-size: 18px;
    }
    ul, ul > li {
      border: 1px solid rgba(0,0,0,.3);
    }
    ul {
      display: flex;
      flex-flow: row wrap;
      list-style: none;
      padding: 0;
      margin: 20px;
    }
    ul > li {
      display: block;
      text-align: center;
      flex: 1 0 auto;
      max-width: 100%;
      box-sizing: border-box;
      margin: 0;
      padding: 4px 7px;
      background-color: rgba(0,0,0,.03);
    }
    <div id="limited-width">
      <ul>
        <li>Apple</li>
        <li>Orange</li>
        <li>Pineapple</li>
        <li>Banana</li>
        <li>Tomato</li>
        <li>Pear</li>
        <li>Lemon</li>
      </ul>
    </div>

    【讨论】:

    【解决方案2】:

    我有同样的问题,但我做了这个(见下面的演示)。 我向每个块添加负'margin-left'和负'margin-top'等于边框的宽度。然后我在容器中添加相同但正的“padding-left”和“padding-top”,以补偿偏移量。哇啦啦!现在我们在 flex 项和它们的容器周围得到了“折叠”的边框。

    .catalog-list {
      display: flex;
      flex-direction: row;
      flex-wrap: wrap;
      padding-top: 1px;
      padding-left: 1px;
      box-sizing: border-box;
      max-width: 800px;
      margin: auto;
      box-shadow: inset 0 0 0 1px #8c8c8c;
    }
    
    .catalog-item {
      width: calc(25% + 1px);
      margin-top: -1px;
      margin-left: -1px;
      padding: 20px;
      border: 1px solid #8c8c8c;
      box-sizing: border-box;
      transition: all 0.2s;
      box-sizing: border-box;
    }
    
    .catalog-item:hover {
      border-color: transparent;
      box-shadow: 0 0 15px -2px #8c8c8c;
    }
    <div class="catalog-list">
      <div class="catalog-item"></div>
      <div class="catalog-item"></div>
      <div class="catalog-item"></div>
      <div class="catalog-item"></div>
      <div class="catalog-item"></div>
      <div class="catalog-item"></div>
    </div>

    【讨论】:

      【解决方案3】:

      在我的例子中,边框需要为 1px,这使得它更加困难。我在https://codepen.io/Hawkun/pen/rsIEp/ 找到了一个解决方案,它使用阴影来模拟边框,实际上效果很好。

      下面是实际代码。它不使用 flexbox,但如果你将阴影应用到你的 flex 内容,你就可以开始了。

      body {
        font-family: sans-serif;
        background-color: #eee;
        padding: 20px;
      }
      
      .info {
        color: darkred;
        font-weight: bolder;
      }
      
      .container {
        background-color: white;
        float: left; /* Makes the container height the same as its children. */
        padding: 10px;
        margin-bottom: 40px;
      }
      
      .container div {
        padding: 20px;
        float: left;
        background-color: #def;
        
        
        /* And here comed the trick: */
      
        box-shadow: 
      1px 0 0 0 #888, 
      0 1px 0 0 #888, 
      1px 1px 0 0 #888,   /* Just to fix the corner */
      1px 0 0 0 #888 inset, 
      0 1px 0 0 #888 inset;
      
      }
      
      #container1 {
        width: 100%;
      }
      
      #container2 {
        width: 50%;
      }
      
      #container2 div {
        width: 70%;
      }
      <p>The first container:</p>
      
      <div id="container1" class="container">
        <div>Hello, this is the first floated div</div>
        <div>And this is the second</div>
        <div>And finally the third one</div>
      </div>
      
      <p>The second container:</p>
      
      <div id="container2" class="container">
        <div>Hello, this is the first floated div</div>
        <div>And this is the second</div>
        <div>And finally the third one</div>
      </div>

      【讨论】:

      • 这个答案与Flexbox无关。
      • ...然而正如 Jon Onstott 所说,它适用于 flexbox。
      • 我试图对此做出回应,但我做不到(限制太短)。所以我对主要问题做出回应:stackoverflow.com/a/68074775/4832358
      【解决方案4】:

      这是我的解决方案:

      window.addEventListener('load', function() {
      
          var containsFlex = document.getElementsByClassName('containsFlex');
          var i = containsEdit.length;
          while (i--) containsEdit[i].style.borderWidth = "1px 0 0 0"; 
      
      }
      

      问题在于 FLEX 的编程代码出现在 CSS 中设置宽度的代码之后,因此任何通过 CSS 设置这些项目的尝试都会失败。但是,使用上面的代码(或变体),可以创建可接受的结果。

      [我在工作,所以我不能写一个完整的帖子。向所有人道歉]

      【讨论】:

        【解决方案5】:

        这是我的另一个想法,它可以在 flex box 换行时保持边框“折叠”。它使用顶部和左侧的背景颜色以及右侧和底部的边框。可能很难让它在背景图像上工作。

        .container {
          display: flex;
          flex-flow: row wrap;
          border-style: solid;
          border-width: 0 2px 2px 0;
          border-color: black;
          background-color: black;
        }
        
        .container>div {
          flex: 1 0 auto;
          margin: 2px 0 0 2px;
          background-color: white;
        }
        <div class="container">
          <div>Eh?</div>
          <div>Bee.</div>
          <div>This div contains a whole bunch of stuff.</div>
          <div>This div contains a whole bunch of stuff.</div>
          <div>This div contains a whole bunch of stuff.</div>
          <div>Sea!</div>
          <div>This div contains a whole bunch of stuff.</div>
          <div>This div contains a whole bunch of stuff.</div>
          <div>This div contains a whole bunch of stuff.</div>
        </div>

        【讨论】:

          【解决方案6】:

          我刚刚遇到了这个问题,这是我的解决方案。我的情况是我需要连续渲染每 4 个项目。

          .container {
            display: flex;
            flex-wrap: wrap;
          }
          
          .item {
            flex: 0 0 25%;
            border-right: 1px solid black;
          }
          
          .item:nth-child(4n) {
            border-right: none;
          }
          
          .item:nth-child(n+5) {
            border-top: 1px solid black;
          }
          

          这样,border-right 只显示在同一行的前 1-3 个项目上。从第 5 项(第 2 行)开始,它们都有一个边框顶部。

          它产生与 Ivan 的答案相似的结果。但我认为这种方法要简单得多。

          【讨论】:

            【解决方案7】:

            我希望此评论可能会有所帮助,但我的意愿是对 @jon-onstott 做出回应

            您的回答帮助我解决了一个类似的案例。我注意到您使用了嵌入阴影(我想知道这是否就是您不需要修复其余角落(左上角、右上角和左下角)的原因,但我很确定如果您的所有阴影都是一开始。

            我必须解决的另一点(就我而言)是我用于阴影的颜色使用了透明度(不是 100% 不透明),因此同级框弄乱了颜色。如果需要显示阴影,我使用带有负值的插入剪辑路径修复了它。

            我没有显示任何代码,因为它解决了问题中没有提到的情况*,但我仍然认为这可以帮助任何错误地结束这里的人(起初)寻找一些类似的解决方案问题。

            *:我的案例是一组格式良好的盒子,它们具有确定的列和行的大小。这就是为什么我知道哪些盒子需要显示阴影。尝试在 flexbox 中解决我的问题没有任何意义,因为 flexbox 的形状取决于容纳它的可用空间。

            【讨论】:

              【解决方案8】:

              使用:last-of-type,您可以“折叠”最后一个边框。也许添加一个box-sizing:border-box;

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2018-12-12
                • 2018-07-21
                • 2018-09-07
                • 2016-12-26
                • 1970-01-01
                相关资源
                最近更新 更多