【问题标题】:Layout depending on number of elements布局取决于元素的数量
【发布时间】:2019-07-14 14:17:24
【问题描述】:

我有一个可以包含 2、3 或 4 个元素的包装器(我事先不知道,因为每个元素都会呈现自己,具体取决于 API 响应)。

如果有 3 个(或更少),我希望它们像这样堆叠:

没什么大不了的。但是当有 4 个时,我需要这个其他布局:

到目前为止,我认为 CSS Grid 是可行的方法,我尝试了:

/* Just to add some interaction to the demo */

const w = document.getElementById("wrapper");
let x;

function toggle(event) {

  const d = document.getElementById("D");
  return d 
    ? 
      x = d.cloneNode() && w.removeChild(d) 
    : w.appendChild(x);
}
#wrapper {
  width: 100%;
  max-width: 500px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-gap: 10px;
}



.item {
  grid-column-start: span 2
}

.item:nth-last-child(1),
.item:nth-last-child(2) {
  grid-column-start: auto;
}


/* Non-relevant CSS here: */

button {
  margin: 20px auto;
  font-size: 16px;
  padding: 3px 6px;
  border-radius: 6px;
}

#A { background: #7984f7 }
#B { background: #cb8af8 }
#C { background: #8cd4fb }
#D { background: #97f8d8 }

.item {
  border-radius: 6px;
  padding: 10px 0;
  font-family: sans-serif;
  font-weight: bold;
  color: white;
  text-align: center;
}
<div id="wrapper">
  <div id="A" class="item">A</div>
  <div id="B" class="item">B</div>
  <div id="C" class="item">C</div>
  <div id="D" class="item">D</div>
</div>

<button onclick="toggle()">Click me!</button>

但它不适用于 3 个元素...事实上,我已经尝试了很多东西(所有 CSS 网格相关)并且可能有一个更简单的解决方案我现在看不到...任何帮助都会非常感谢!

【问题讨论】:

    标签: html css flexbox alignment css-grid


    【解决方案1】:

    您可以使用:nth-child(n+4) 选择第三个​​孩子之后的元素,使用:nth-child(n+3) 选择第二个孩子之后的元素,然后变出:

    .item:nth-child(n+4):nth-last-child(1),
    .item:nth-child(n+3):nth-last-child(2) {
      grid-column-start: auto;
    }
    

    现在您已经获得了您搜索的网格配置 - 这将适用于 任何item 元素 - 请参见下面的演示:

    /* Just to add some interaction to the demo */
    const w = document.getElementById("wrapper");
    let x;
    function toggle(event) {
      const d = document.getElementById("D");
      return d ?
        x = d.cloneNode() && w.removeChild(d) :
        w.appendChild(x);
    }
    #wrapper {
      width: 100%;
      max-width: 500px;
      display: grid;
      grid-template-columns: 1fr 1fr;
      grid-gap: 10px;
    }
    .item {
      grid-column-start: span 2;
    }
    /* CHANGED THIS */
    .item:nth-child(n+4):nth-last-child(1),
    .item:nth-child(n+3):nth-last-child(2) {
      grid-column-start: auto;
    }
    /* Non-relevant CSS here: */
    button {
      margin: 20px auto;
      font-size: 16px;
      padding: 3px 6px;
      border-radius: 6px;
    }
    #A {
      background: #7984f7
    }
    #B {
      background: #cb8af8
    }
    #C {
      background: #8cd4fb
    }
    #D {
      background: #97f8d8
    }
    .item {
      border-radius: 6px;
      padding: 10px 0;
      font-family: sans-serif;
      font-weight: bold;
      color: white;
      text-align: center;
    }
    <div id="wrapper">
      <div id="A" class="item">A</div>
      <div id="B" class="item">B</div>
      <div id="C" class="item">C</div>
      <div id="D" class="item">D</div>
    </div>
    <button onclick="toggle()">Click me!</button>

    【讨论】:

      【解决方案2】:

      我建议使用 flexbox。对于给定的三种可能性,请在下面的 sn-p 中使用这个简单的 css。

      基本上,您可以使项目连续显示,但如果它们不合适,则进行包装。您使前两个元素占据所有宽度,以便每行只有一个。对于第 3 次和第 4 次,您将它们的 flex-basis(初始宽度)设置为更小,并在有空间的情况下使它们增长(flex-grow:1)。

      .examples{
        display: flex;
        flex-direction: row;
        align-items: flex-start;
      }
      .container{
        width: 200px;
        border: 1px solid red;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: flex-start;
      }
      .box{
        height: 50px;
        background-color: blue;
        margin: 5px;
        border-radius: 5px;
        flex-basis: 200px;
      }
      .box:nth-child(3), .box:nth-child(4){
        flex-basis: 50px;
        flex-grow: 1;
      }
      <div class="examples">
        <div class="container">
          <div class="box"></div>
          <div class="box"></div>
        </div>
        <div class="container">
          <div class="box"></div>
          <div class="box"></div>
          <div class="box"></div>
        </div>
        <div class="container">
          <div class="box"></div>
          <div class="box"></div>
          <div class="box"></div>
          <div class="box"></div>
        </div>
      </div>

      解决方案也在这里:JSFiddle

      【讨论】:

      • 如果您不必去其他网站就可以看到答案,答案会更好。考虑使用Stack Snippets 在 Stack Overflow 上嵌入一个可运行的 sn-p。请注意,您可以单击 Copy sn-p to answer 按钮以使其更容易。
      • 好电话,@HereticMonkey。我添加了 sn-p - 感谢您的提示。
      【解决方案3】:

      或者,您可以使用 flexbox 来做类似的事情,而不是使用网格设置。 我个人认为 flexbox 是一个更有用/更强大的工具,它可以让事情变得响应而不以丑陋的方式破坏。添加响应式样式以进行相应修改很容易。

      你可以这样做:

      #wrapper {
        width: 100%;
        max-width: 500px;
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
      }
      .item:first-of-type {
        width: 100%;
      }
      .item:nth-of-type(2) {
        width: 100%;
      }
      .item:nth-of-type(3):last-of-type {
        width: 100%;
      }
      .item:nth-of-type(3) {
        width: 50%;
      }
      .item:nth-of-type(4) {
        width: 50%;
      }
      

      这样,如果您有第 5 或第 6(或等)项,并且您希望它们的宽度根据元素的数量而变化,您可以在这里做类似的事情。如果您查看我的演示,如果您删除第 4 项,则作为最后一个元素的第 3 项将具有 100% 的宽度。

      CodePen rough example

      【讨论】:

      • 如果您不必去其他网站就可以看到答案,答案会更好。考虑使用 Stack Snippets 在 Stack Overflow 上嵌入可运行的 sn-p。
      【解决方案4】:

      这是一个有效的技巧。

      第三个孩子也是倒数第二个,第四个孩子的 grid-column-start 将设置为 auto。

      .item:nth-child(3):nth-last-child(2),
      .item:nth-child(4) {
        grid-column-start: auto;
      }
      

      如果您希望将第 4 位以上的所有孩子分成两列,请稍作调整。

      .item:nth-child(3):nth-last-child(2),
      .item:nth-child(n+4) {
        grid-column-start: auto;
      }
      

      /* Just to add some interaction to the demo */
      
      const w = document.getElementById("wrapper");
      let x;
      
      function toggle(event) {
      
        const d = document.getElementById("D");
        return d 
          ? 
            x = d.cloneNode() && w.removeChild(d) 
          : w.appendChild(x);
      }
      #wrapper {
        width: 100%;
        max-width: 500px;
        display: grid;
        grid-template-columns: 1fr 1fr;
        grid-gap: 10px;
      }
      
      
      
      .item {
        grid-column-start: span 2
      }
      
      .item:nth-child(3):nth-last-child(2),
      .item:nth-child(n+4) {
        grid-column-start: auto;
      }
      
      
      /* Non-relevant CSS here: */
      
      button {
        margin: 20px auto;
        font-size: 16px;
        padding: 3px 6px;
        border-radius: 6px;
      }
      
      #A { background: #7984f7 }
      #B { background: #cb8af8 }
      #C { background: #8cd4fb }
      #D { background: #97f8d8 }
      
      .item {
        border-radius: 6px;
        padding: 10px 0;
        font-family: sans-serif;
        font-weight: bold;
        color: white;
        text-align: center;
      }
      <div id="wrapper">
        <div id="A" class="item">A</div>
        <div id="B" class="item">B</div>
        <div id="C" class="item">C</div>
        <div id="D" class="item">D</div>
      </div>
      
      <button onclick="toggle()">Click me!</button>

      【讨论】:

        【解决方案5】:

        使用 CSS 网格:

        1. 默认在两列中显示所有项目
        2. 在单列中显示项目 1 和 2
        3. 仅当第 3 项为最后一项时,才将第 3 项显示在单列中

        一个副作用是,如果超过 4 个项目,额外的项目将显示在两列中。

        /* Just to add some interaction to the demo */
        
        const w = document.getElementById("wrapper");
        let x;
        
        function toggle(event) {
        
          const d = document.getElementById("D");
          return d 
            ? 
              x = d.cloneNode() && w.removeChild(d) 
            : w.appendChild(x);
        }
        #wrapper {
          width: 100%;
          max-width: 500px;
          display: grid;
          grid-template-columns: 1fr 1fr;
          grid-gap: 10px;
        }
        
        
        
        .item {
          grid-column-start: auto;
        }
        
        .item:nth-child(1),
        .item:nth-child(2),
        .item:nth-child(3):last-child {
          grid-column-start: span 2;
        }
        
        
        /* Non-relevant CSS here: */
        
        button {
          margin: 20px auto;
          font-size: 16px;
          padding: 3px 6px;
          border-radius: 6px;
        }
        
        #A { background: #7984f7 }
        #B { background: #cb8af8 }
        #C { background: #8cd4fb }
        #D { background: #97f8d8 }
        
        .item {
          border-radius: 6px;
          padding: 10px 0;
          font-family: sans-serif;
          font-weight: bold;
          color: white;
          text-align: center;
        }
        <div id="wrapper">
          <div id="A" class="item">A</div>
          <div id="B" class="item">B</div>
          <div id="C" class="item">C</div>
          <div id="D" class="item">D</div>
        </div>
        
        <button onclick="toggle()">Click me!</button>

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-11-09
          • 2019-07-11
          • 2017-10-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-01
          • 2019-01-09
          相关资源
          最近更新 更多