【问题标题】:Flexbox tile layout with consistent margins and alignment具有一致边距和对齐方式的 Flexbox 平铺布局
【发布时间】:2015-09-06 03:30:54
【问题描述】:

我们如何实现以下布局:

具备以下条件:

  1. 每行的图块高度应等于该行中最高元素的高度

  2. 行中的最后一个图块应与父容器齐平(无间隙)

  3. 瓷砖可以是不同的宽度比(3 乘以三分之一或三分之一 + 三分之二等)

  4. 图块的顺序未知

  5. 无网格框架

  6. 仅限现代浏览器

还有以下标记:

<div class="tile-wrapper">
  <div class="tile-container">
    <div class="tile third">1/3</div>
    <div class="tile third">1/3</div>
    <div class="tile third">1/3</div>
    <div class="tile two-thirds">2/3</div>
    <div class="tile third">1/3</div>
    <div class="tile sixth">1/6</div>
    <div class="tile sixth">1/6</div>
    <div class="tile third">1/3</div>
    <div class="tile sixth">1/6</div>
    <div class="tile sixth">1/6</div>
  </div>
</div>

【问题讨论】:

    标签: html css flexbox


    【解决方案1】:

    这是一种越来越常见的布局,使用 flexbox 和一些巧妙的容器标记可以相对轻松地实现。

    平铺布局的一个常见问题是在多行中保持不同大小的平铺之间保持一致的间距和对齐方式。假设我们想要一个 30px 边距分隔所有图块,我们可以简单地在所有图块上设置 margin-right: 30px,然后使用第 n 个类型的选择器删除行中最后一个图块的 margin-right

    但是,当图块的相对大小和顺序未知时,这是不可能的。例如,三分之一块旁边的三分之二块将不符合将最后一块块的边距删除为由三个三分之一块组成的行所需的相同类型选择器规则。

    解决这个问题的一个聪明方法是将最右边的 tile 的边距吸收到父容器的宽度中。我们可以通过使用overflow: hidden 将最外层 div 的宽度设置为所需宽度(在本例中为 90%),然后将内部容器的宽度设置为宽度的 100%加上瓷砖边距; width: calc(100% + 30px)。这样,无论行的最右侧位置是什么图块,该图块都会与其容器的边缘齐平。

    为确保图块始终按需要适合,我们将它们的 flex-basis 设置为我们希望它们占据的行宽的 proportionminus瓷砖边距; .third { flex: 0 0 calc(33.33% - 30px); /* for a 1/3 tile */}

    像这样:

    * {
      box-sizing: border-box;
    }
    .tile-wrapper {
      display: block;
      position: relative;
      width: 90%;
      margin: 0 auto;
      overflow: hidden;
    }
    .tile-container {
      display: flex;
      position: relative;
      width: calc(100% + 30px);
      flex-wrap: wrap;
    }
    .tile {
      display: inline-block;
      margin-right: 30px;
      margin-bottom: 30px;
      min-height: 200px;
      line-height: 199px;
      text-align: center;
      border: 1px solid black;
    }
    .two-thirds {
      flex: 0 0 calc(66.66% - 30px);
    }
    .third {
      flex: 0 0 calc(33.33% - 30px);
    }
    .sixth {
      flex: 0 0 calc(16.66% - 30px);
    }
    <div class="tile-wrapper">
      <div class="tile-container">
        <div class="tile third">1/3</div>
        <div class="tile third">1/3</div>
        <div class="tile third">1/3</div>
        <div class="tile two-thirds">2/3</div>
        <div class="tile third">1/3</div>
        <div class="tile sixth">1/6</div>
        <div class="tile sixth">1/6</div>
        <div class="tile third">1/3</div>
        <div class="tile sixth">1/6</div>
        <div class="tile sixth">1/6</div>
      </div>
    </div>

    Here's a Fiddle

    注意:这仅适用于现代浏览器(Chrome、Safari、FF、IE11+)。 IE11 中还有一个已知错误,要求您使用长手的 flex-basis 样式属性才能将其设置为 calc() 值。

    【讨论】:

      【解决方案2】:

      来自问题:

      1. 没有网格框架

      这个问题是在 2015 年发布的,当时 CSS 网格布局对浏览器的支持较弱。

      自 2017 年起,all major browsers support Grid Layout

      因此,假设发布此要求是为了浏览器兼容性,我将回顾它并提供当今浏览器轻松支持的最佳(基于网格)解决方案。

      body {
        margin: 0;
      }
      
      .tile-wrapper {}
      
      .tile-container {
        display: grid;
        grid-template-rows: auto auto auto;
        grid-template-columns: repeat(6, 1fr);
        grid-gap: 30px;
      }
      
      .sixth {
        grid-column: span 1;
      }
      
      .third {
        grid-column: span 2;
      }
      
      .two-thirds {
        grid-column: span 4;
      }
      
      /* demo only */
      .tile {
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: lightgray;
        border: 1px solid gray;
      }
      <div class="tile-wrapper">
        <div class="tile-container">
          <div class="tile third">1/3</div>
          <div class="tile third">1/3<br>
          text<br>text<br>text</div>
          <div class="tile third">1/3</div>
          <div class="tile two-thirds">2/3</div>
          <div class="tile third">1/3<br>
          text<br>text<br>text<br>
          text<br>text<br>text<br>
          text<br>text<br>text</div>
          <div class="tile sixth">1/6<br>
          text<br>text<br>text<br>
          text<br>text</div>
          <div class="tile sixth">1/6</div>
          <div class="tile third">1/3</div>
          <div class="tile sixth">1/6</div>
          <div class="tile sixth">1/6</div>
        </div>
      </div>

      来自问题:

      具备以下条件:

      1. 每行的图块的高度应与最高元素的高度相同 在行中。 检查

      2. 该行中的最后一个图块应与父容器齐平(不 差距)。 检查

      3. 瓷砖可以是不同的宽度比(3 乘以三分之一或 三分之一 + 三分之二等)。 检查

      4. 图块的顺序未知。 好的

      5. 没有网格框架。 不适用(见上文注释)

      6. 仅限现代浏览器。 检查

      【讨论】:

        【解决方案3】:

        你可以试试这个:

        • 为每个项目设置flex-basis: 0 和所需的flex-grow 因子。
        • 强制换行将伪元素放置在正确的位置。
        • 为所有弹性项目设置一些边距。
        • 为 flex 包装器设置相同数量的负边距。

        .tile-wrapper {
          border: 1px solid #000;
        }
        .tile-container {
          display: flex; /* Magic begins */
          flex-wrap: wrap; /* Multiline */
          margin: -5px; /* Neutralize margins at the edges */
        }
        .tile {
          min-height: 50px; /* Just an example */
          margin: 5px;
          border: 1px solid #979797;
          background: #d8d8d8;
        }
        .sixth{ flex: 1; } /* 1/6 * 6 */
        .third{ flex: 2; } /* 1/3 * 6 */
        .two-thirds{ flex: 4; } /* 2/3 * 6 */
        .tile-container::before, .tile-container::after {
          content: ''; /* Enable the pseudo-element */
          order: 1; /* Place it at the appropiate place */
          width: 100%; /* Force line break */
        }
        .tile-container > :nth-child(n+4) { order: 1; }
        .tile-container > :nth-child(n+6) { order: 2; }
        <div class="tile-wrapper">
          <div class="tile-container">
            <div class="tile third">1/3</div>
            <div class="tile third">1/3</div>
            <div class="tile third">1/3</div>
            <div class="tile two-thirds">2/3</div>
            <div class="tile third">1/3</div>
            <div class="tile sixth">1/6</div>
            <div class="tile sixth">1/6</div>
            <div class="tile third">1/3</div>
            <div class="tile sixth">1/6</div>
            <div class="tile sixth">1/6</div>
          </div>
        </div>

        【讨论】:

        • 您能否详细说明“强制换行符将伪元素放置在正确的位置”是什么意思?
        【解决方案4】:

        您可以通过使用容器和瓷砖边距来达到预期的效果,并在调整瓷砖尺寸时考虑在内。这是一个工作的CSS。我添加了一些颜色和文字,以便更好地查看尺寸和展开行为。

        基本上,我们在 x 轴上为容器设置了一个半尺寸的负边距,为顶部设置了一个全尺寸的负边距(它也可能是底部,这并不重要)。每个图块的每一边都有一半大小的边距,所以我们不需要知道哪个是第一个,哪个是最后一个(都是一样的)。在它们之间,我们将拥有全尺寸边距。

        这种方法具有很大的优势,即响应式就绪,可以针对不同的媒体查询开箱即用,以获取磁贴大小的宽度。此外,它还允许您展示完整的无边距观看体验。

        * { box-sizing: border-box; margin:0;padding:0; text-align: center; }
        
        .tile-wrapper {
          border:1px solid black;
          overflow:hidden;
        }
        
        .tile-container {
          display: flex;
          flex-direction: row;
          flex-wrap: wrap;
          margin-left: -15px;
          margin-right: -15px;
          margin-top: -30px;
        }
        
        .tile-container .tile {
          background-color: gray;
          color: black;
          margin-left: 15px;
          margin-right: 15px;
          margin-top: 30px;
          padding: 0;
        }
        
        .tile.third {
          flex: 0 0 calc(33.33333% - 30px);
        }
        
        .tile.two-thirds {
          flex: 0 0 calc(66.6666666% - 30px);
        }
        
        .tile.sixth {
          flex: 0 0 calc(16.66666667% - 30px);
        }
        <div class="tile-wrapper">
          <div class="tile-container">
            <div class="tile third">1/3<br />Lorem ipsum dolor sit amet consectetur adipisicing elit</div>
            <div class="tile third">1/3</div>
            <div class="tile third">1/3</div>
            <div class="tile two-thirds">2/3</div>
            <div class="tile third">1/3<br />Lorem ipsum dolor sit amet consectetur adipisicing elit</div>
            <div class="tile sixth">1/6</div>
            <div class="tile sixth">1/6<br />Lorem ipsum dolor sit amet consectetur adipisicing elit</div>
            <div class="tile third">1/3</div>
            <div class="tile sixth">1/6</div>
            <div class="tile sixth">1/6</div>
          </div>
        </div>

        注意:如果 wrapper 不是 body 的单个直接子元素,或者周围元素可以占 -15px(在示例中)的边距,您可以安全地移除溢出规则。

        【讨论】:

          猜你喜欢
          • 2016-12-03
          • 2015-02-18
          • 2021-05-15
          • 2022-01-12
          • 1970-01-01
          • 2015-03-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多