【问题标题】:Make flex items overlap使弹性项目重叠
【发布时间】:2017-10-10 16:07:30
【问题描述】:

我想展示一系列未知数量的扑克牌。为此,如果太多,它们将不得不重叠。我无法说服弹性盒在不缩小卡片的情况下重叠卡片。下面的例子缩小了卡片。我试过flex-shrink: 0,但后来max-width 没有得到尊重。

.cards {
  display: flex;
  max-width: 300px;
}

.card {
  width: 50px;
  height: 90px;
  border: 1px solid black;
  border-radius: 3px;
  background-color: rgba(255, 0, 0, 0.4);
}
<div class='cards'>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
  <div class='card'></div>
</div>

【问题讨论】:

  • 如果你想让它们重叠,为什么要使用 flex,它不是填充空间吗?
  • 重叠部分可以只使用负边距吗?
  • 负边距适用于给定数量的卡片。但它必须为每张卡片和每张卡片的总数而改变。我正在寻找更灵活的东西。
  • 您能更具体地说明您想要实现的目标吗?什么是“太多”?您希望它们如何准确重叠。你在回复@StefanBob 时用“它必须为每张卡片和每张卡片的总数而改变。我正在寻找更灵活的东西。” 是什么意思?那得怎么改?为什么?那里的逻辑是什么? “更灵活”是什么意思?
  • @MichaelCoker 我试图让卡片以类似于这张图片的方式扇出:shpgames.com/zero-mod/fan.jpg(但没有曲线)。卡片不应调整大小 - 它们应始终保持 50 x 90 像素。因此,如果容器的最大宽度为 300 像素宽,则最多可以容纳 6 张卡片且不重叠。一旦添加了第七个,就会有轻微的重叠。如果有 50 张卡片,由于重叠,您只能看到每张卡片 6 个像素。所以我希望 flex 容器可以处理这个计算。

标签: html css flexbox css-grid


【解决方案1】:

聚会迟到了,但这是我对类似情况的解决方法:

有一个建议提到负边距,确实,当没有进行其他调整时,卡片将始终与:margin-left: -30px; 重叠(重叠宽度选择有些随意。您可以选择卡片的最大宽度。)

我在这里所做的更改是将justify-content: space-evenly; 添加到组合中。这会将卡片分散在 flex 容器中的可用空间上,并且只有在过于拥挤时才让卡片重叠。这可能是一个解决方案,如果你对卡片在不重叠时像那样展开没问题。

注意。由于负边距将卡片向左拉,我还把与负边距相同宽度的padding-left 插入到 flex 容器中。

NB2。我更改了原始示例的不透明度,否则卡片会变得透明。

    .cards {
      display: flex;
      max-width: 300px;
      padding-left: 30px;
      justify-content: space-evenly;
    }

    .card {
      width: 50px;
      height: 90px;
      border: 1px solid black;
      border-radius: 8px;
      background-color: rgb(255, 100, 100);
      margin-left: -30px;
    }
    <div class='cards'>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
    </div>

【讨论】:

    【解决方案2】:

    您可以使用transform: translateX(-10px) 使弹性布局中的元素重叠,但这不会解决您想要获得的布局。我认为你不能在 flexbox 中做到这一点。但是你可以很容易地用 JS 做到这一点。

    var parentEl = document.getElementById("cards");
    
    function sortCards() {
      var cards = document.getElementsByClassName("card"),
          cw = parentEl.clientWidth,
          sw = parentEl.scrollWidth,
          diff = sw - cw,
          offset = diff / (cards.length - 1);
    
      for (var i = 1; i < cards.length; i++) {
        cards[i].style.transform = "translateX(-" + offset * i + "px)";
      }
    }
    
    sortCards();
    
    var b = document.getElementById("button");
    b.addEventListener("click", function() {
      var div = document.createElement("div");
      div.classList.add("card");
      parentEl.appendChild(div);
      sortCards();
    });
    .cards {
      display: flex;
      max-width: 300px;
    }
    
    .card {
      height: 90px;
      border: 1px solid black;
      border-radius: 3px;
      background-color: rgba(255, 0, 0, 0.4);
      flex: 0 0 50px;
      background: red;
      transition: transform .25s;
    }
    <div><button id="button">addcards</button></div>
    <div class='cards' id="cards">
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
    </div>

    【讨论】:

    • 虽然不灵活,但这是一个很好的解决方案。它满足给定空间中可变数量卡片的所有要求。如果有人仍然有弹性解决方案,我很想听听,但到目前为止,这是一个足够好的答案。
    • @MichaelArrison 其他人回答说你可以让元素与margin 重叠 - 你也可以使用transform: translateX() 来做到这一点,就像我在这里所做的那样,但这不会影响你的布局,所以我没有使用它。你需要一些数学(我认为)来做到这一点。但是我更新了我的答案以使用 flex 和 transform,因为您在最初的问题中有这个。
    • 为什么您的解决方案中的for 循环不从i=1 开始?
    • @BoltKey '因为我主要编写 CSS,这就是我默认使用 JS 循环的方式:) 用你的建议更新了答案,谢谢!
    【解决方案3】:

    这将一个右孩子重叠在一个左孩子之上,不包括第一个。

    .overlapped {
      > * + * {
        postion: absolute;
        margin-left: -7px;
      }
    }
    

    你的容器也应该有 flex 和 flex-direction 行。

    【讨论】:

      【解决方案4】:

      flex 容器旨在沿 X 轴和 Y 轴对齐项目。

      您是在询问沿 Z 轴的对齐方式。

      Flexbox 不是为 z 轴对齐(重叠)而设计的。

      任何重叠都必须来自负边距、绝对定位、CSS 网格布局、JavaScript 或其他东西。 z-index 属性可能也需要发挥作用。

      这是一个使用 CSS Grid 的基本示例:

      .cards {
        display: grid;
        grid-template-columns: repeat(30, 10px);
        grid-template-rows: 90px;
        max-width: 300px;
      }
      
      .card {
        grid-row-start: 1;
        background-color: lightgreen; 
        border: 1px solid black;
      }
      
      .card:nth-child(1) { grid-column: 1 / 6; }
      .card:nth-child(2) { grid-column: 4 / 9; }
      .card:nth-child(3) { grid-column: 7 / 12; }
      .card:nth-child(4) { grid-column: 10 / 15; }
      .card:nth-child(5) { grid-column: 13 / 18; }
      .card:nth-child(6) { grid-column: 16 / 21; }
      .card:nth-child(7) { grid-column: 19 / 24; }
      .card:nth-child(8) { grid-column: 22 / 27; }
      .card:nth-child(9) { grid-column: 25 / 30; }
      <div class='cards'>
        <div class='card'>1</div>
        <div class='card'>2</div>
        <div class='card'>3</div>
        <div class='card'>4</div>
        <div class='card'>5</div>
        <div class='card'>6</div>
        <div class='card'>7</div>
        <div class='card'>8</div>
        <div class='card'>9</div>
      </div>

      使用line-based placement 使卡片重叠。在这种情况下,grid-column 属性用于使列轨道重叠。

      不过,如果卡片的数量动态变化,则需要编写一些脚本,因为重叠量需要变化才能使所有卡片精确地适合固定宽度的容器。

      【讨论】:

      • 虽然一张卡片应该在另一张卡片之上,但这不是这里的重要问题。重要的问题是让它们在 x 轴上重叠。 Flex 容器有许多沿 x 轴对齐的选项。但我只是不确定它是否有任何重叠。
      • 我认为使用 jquery 您可以在第二张卡片的左边距上放置一个公式,该公式将动态计算并重叠卡片。如果你愿意,我可以给你举个例子。
      • @NasirT 提出了一个很好的观点,尽管它可以简化为纯 css。像 .card:nth-child(n+2) { margin-left: -30px; 这样的规则如果提前知道卡片的数量,} 将会非常有效。
      【解决方案5】:

      div.card-area
      {
          height: 16vh; /* whatever */
          display: flex;
      }
      div.card-area > div
      {
          flex: 1 0 0;
          overflow-x: hidden;
      }
      div.card-area > div:last-of-type
      {
          flex: 0 0 auto;
      }
      div.card-area img
      {
          height: 100%;
      }
      <div class="card-area N">
          <div><img src="img/cards/AH.png"></div>
          <div><img src="img/cards/KH.png"></div>
          <div><img src="img/cards/QH.png"></div>
          <div><img src="img/cards/JH.png"></div>
          <div><img src="img/cards/10H.png"></div>
          <div><img src="img/cards/9H.png"></div>
          <div><img src="img/cards/8H.png"></div>
          <div><img src="img/cards/7H.png"></div>
          <div><img src="img/cards/6H.png"></div>
          <div><img src="img/cards/5H.png"></div>
          <div><img src="img/cards/4H.png"></div>
          <div><img src="img/cards/3H.png"></div>
          <div><img src="img/cards/2H.png"></div>
      </div>

      【讨论】:

        【解决方案6】:

        您可以通过使用 grid 而不是 flex 仅使用 css 来完成。

        .hand{
          width: 50%;
          margin-left: auto;
          margin-right: auto;
          justify-content: center;
          display: grid;
          grid-template-columns: repeat(auto-fit,  minmax(10px, max-content)) ;
        }
        .card{
          width: 3em;
          height: 2.4em;
          padding: 3px;
          margin: 2px;
          background-color: lightgreen;
          border-style: solid;
          transform: rotate(3deg);  /*makes it easier to see the overlap*/
        }
        <div class="hand"> 
          <div class="card"> card </div>
          <div class="card"> card </div>
          <div class="card"> card </div>
          <div class="card"> card </div>
          <div class="card"> card </div>
          <div class="card"> card </div>
          <div class="card"> card </div>
          <div class="card"> card </div>
        </div>

        【讨论】:

          【解决方案7】:

          这是我使用 flexbox 的方法。

          .cards {
            display: flex;
            align-content: center;
            max-width: 35em;
          }
          
          .cardWrapper {
            overflow: hidden;
          }
          
          .cardWrapper:last-child, .cardWrapper:hover {
              overflow: visible;
          }
          
          .card {
              width: 10em;
              min-width: 10em;
              height: 6em;
              border-radius: 0.5em;
              border: solid #666 1px;
              background-color: #ccc;
              padding: 0.25em;
            
              display: flex;
              flex-direction: column;
              justify-content: center;
              align-items: center;
          }
          <div class="cards">
            <div class="cardWrapper">
              <div class="card">card 1 blah blah blah</div>
            </div>
            <div class="cardWrapper">
              <div class="card">card 2 blah blah blah</div>
            </div>
            <div class="cardWrapper">
              <div class="card">card 3 blah blah blah</div>
            </div>
            <div class="cardWrapper">
              <div class="card">card 4 blah blah blah</div>
            </div>
            <div class="cardWrapper">
              <div class="card">card 5 blah blah blah</div>
            </div>
          </div>

          请注意,从技术上讲,卡片并没有重叠,它们只是被剪裁了。但它们看起来就像是重叠的。诀窍是用 overflow: hidden 将每张卡片包装在另一个元素中。

          包装元素被缩小以适应可用空间,并且尽可能多的卡片显示在该空间中。

          我包含 :hover 规则只是为了展示如何从“堆栈”中间完全显示一张卡片,但在实际项目中我可能会为选定的卡片而不是悬停的卡片执行此操作。

          【讨论】:

            【解决方案8】:

            我想出了一个通用的、基于 CSS 的解决方案。但是,有一些警告:

            1. 最后一张卡片溢出.cards 容器。
            2. 需要.card 的子元素才能产生重叠效果。

            .cards {
              display: flex;
              max-width: 300px;
            }
            
            .card {
              position: relative;
              flex-basis: 50px;
              height: 90px;
            }
            
            .card::before {
              content: '';
              display: block;
              position: absolute;
              width: 50px;
              height: 100%;
              border: 1px solid black;
              border-radius: 3px;
              background-color: rgba(255, 0, 0, 0.4);
              box-sizing: border-box;
            }
            <div class='cards'>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
              <div class='card'></div>
            </div>

            【讨论】:

              【解决方案9】:

              您可以使用 margin 属性并通过手动或 JS 应用到您想要的项目。

              .cards {
                display: flex;
                max-width: 300px;
              }
              
              .overl {
              margin-left:-10px;
              }
              
              .card {
                width: 50px;
                height: 90px;
                border: 1px solid black;
                border-radius: 3px;
                background-color: rgba(255, 0, 0, 0.4);
              }
              <div class='cards'>
                <div class='card'></div>
                <div class='card overl'></div>
                <div class='card'></div>
                <div class='card'></div>
                <div class='card'></div>
                <div class='card'></div>
                <div class='card'></div>
                <div class='card'></div>
                <div class='card'></div>
              </div>

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2019-09-26
                • 2018-12-07
                • 2019-08-13
                • 2018-09-07
                • 1970-01-01
                • 2018-04-15
                • 2017-10-01
                相关资源
                最近更新 更多