【问题标题】:Masonry layout with css grid带有 CSS 网格的砌体布局
【发布时间】:2017-05-11 13:48:08
【问题描述】:

我正在尝试创建砌体布局使用 CSS 网格布局。网格中的所有项目都有可变高度。而且我不知道会是什么项目。所以我不能为每个项目定义grid-row。是否可以在列中上一个结束后立即开始每个新项目?

我正在尝试的代码:

.wrapper {
  display: grid;
  grid-template-columns: repeat(auto-fill, 330px);
  align-items: flex-start;
  grid-column-gap: 10px;
  grid-row-gap: 50px;
}

.item {
  background: black;
  border-radius: 5px;
}
<div class="wrapper">
  <div class="item" style="height:50px"></div>
  <div class="item" style="height:100px"></div>
  <div class="item" style="height:30px"></div>
  <div class="item" style="height:90px"></div>
  <div class="item" style="height:80px"></div>
  <div class="item" style="height:50px"></div>
  <div class="item" style="height:70px"></div>
  <div class="item" style="height:40px"></div>

</div>

full codepen here

【问题讨论】:

  • AFAIK,CSS Grid 不像其他布局方法那样做砌体样式。
  • @Paulie_D 好的,能说一下什么方法吗?
  • CSS Grid 可以很好地完成砌体,如果您可以定义网格中的高度。它可能不是完全自动化的,但在许多情况下可能很有用。 stackoverflow.com/a/43903119/3597276
  • @user2950602,如果您正在寻找其他选项,请在此处查看我的答案:stackoverflow.com/q/34480760/3597276
  • @Michael_B 问题是我无法定义高度。感谢您提供其他选项的链接

标签: css grid-layout css-grid


【解决方案1】:

在您的问题中,您正在单独设置每个项目的高度。如果您愿意这样做,那么使用网格可以轻松实现 Masonry 布局。

而不是为每个项目设置高度 grid-row-end 以便每个项目跨越一定数量的行。

 <div class="item" style="grid-row-end: span 5"></div>

然后项目的高度将取决于您为网格设置的grid-auto-rowsgrid-row-gap 的值。

我在这里做了一个 Codepen:https://codepen.io/andybarefoot/pen/NaprOB

如果您不想为每个项目单独设置 grid-row-end 值,您可以使用一些 JavaScript 来动态完成。我在每个项目中放置了另一个“容器”div,并测量了这个容器的高度,以计算项目需要跨越多少行。我在页面加载时执行此操作,并在加载任何图像时再次为每个项目执行此操作(因为内容的高度会发生变化)。如果将此方法与响应式布局结合使用,则还应在调整页面大小时重新计算,因为列的宽度可能已更改,这将影响内容的高度。

这是我调整响应列大小的完整示例:https://codepen.io/andybarefoot/pen/QMeZda

如果您有可变宽度的物品,您仍然可以达到类似的效果,但网格的包装不会完美,并且可能会更改物品顺序以优化包装。

我在 Medium 上写了一篇关于这种方法的博客,以防万一:A Masonry style layout using CSS Grid

【讨论】:

    【解决方案2】:

    这是仅使用 CSS 创建 Masonry 布局的一种方法。

    *,
    *:before,
    *:after {
      box-sizing: border-box !important;
    }
    
    article {
      -moz-column-width: 13em;
      -webkit-column-width: 13em;
      -moz-column-gap: 1em;
      -webkit-column-gap: 1em;
    }
    
    section {
      display: inline-block;
      margin: 0.25rem;
      padding: 1rem;
      width: 100%;
      background: #efefef;
    }
    
    p {
      margin: 1rem 0;
    }
    
    body {
      line-height: 1.25;
    }
    <article>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Error aliquid reprehenderit expedita odio beatae est.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Nobis quaerat suscipit ad.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rem nihil alias amet dolores fuga totam sequi a cupiditate ipsa voluptas id facilis nobis.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Rem ut debitis dolorum earum expedita eveniet voluptatem quibusdam facere eos numquam commodi ad iusto laboriosam rerum aliquam.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quaerat architecto quis tenetur fugiat veniam iste molestiae fuga labore!</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Odit accusamus tempore at porro officia rerum est impedit ea ipsa tenetur. Labore libero hic error sunt laborum expedita.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima asperiores eveniet vero velit eligendi aliquid in.</p>
      </section>
      <section>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus dolorem maxime minima animi cum.</p>
      </section>
    </article>

    注意:代码不是我做的,我发现它做了一些小的改编, 原代码可以在here找到。


    请注意,正如Zen指出的那样:

    [...] 项目的布局从上到下从左到右, 而人们通常期望的(文化假设除外)是 从左到右从上到下布局。这是通常的基于 CSS3 列的推荐的最佳选择。

    【讨论】:

    • "这个解决方案的问题是项目是从上到下、从左到右排列的,而人们通常期望的(排除文化假设)是从左到右的,从上到下的布局。这是通常基于 CSS3 列的推荐的最佳展示。"
    【解决方案3】:

    您可以动态地为grid-row-end 设置span 的值(使用一点JS,就像下面示例中基于我的Codepen experiment 的那个)并为grid-auto-placement 使用dense 关键字:

    const gridStyles = getComputedStyle(document.querySelector('.wrapper',null));
    const rowHeight = parseInt(gridStyles.getPropertyValue('--grid-row-height'));
    const gap = parseInt(gridStyles.getPropertyValue('--grid-gutter'));;
    
    let makeGrid = function() {
      let items = document.querySelectorAll('.item');
      for (let i=0, item; item = items[i]; i++) {
        // take an item away from grid to measure it
        item.classList.add('is-being-measured');
        let height = item.offsetHeight;
        // calcylate the row span
        let rowSpan = Math.ceil((height + gap)/(rowHeight + gap));
        // set the span value for grid-row-end
        item.style.gridRowEnd = 'span '+rowSpan;
        // return the item into the grid
        item.classList.remove('is-being-measured');
      }
    }
    
    window.addEventListener('load', makeGrid);
    window.addEventListener('resize', () => {
      clearTimeout(makeGrid.resizeTimer);
      makeGrid.resizeTimer = setTimeout(makeGrid, 50);
    });
    .wrapper {
      display: grid;
      grid-template-columns: repeat(auto-fill, 330px);
      --grid-gutter: 10px;
      grid-gap: var(--grid-gutter);
      --grid-row-height: 10px;
      grid-auto-rows: var(--grid-row-height);
      grid-auto-flow: row dense;
      position: relative;
    }
    
    .item {
      background: black;
      color: white;
      border-radius: 5px;
    }
    .item.is-being-measured {
      /* temporary styles for measuring grid items */
      position: absolute;
      width: 330px;
      top: 0;
      left: 0;
    }
    
    .item > * { margin-left: 20px; }
    <div class="wrapper">
      <div class="item"><h3>1.1</h3><p>1.2</p></div>
      <div class="item"><p>2.1</p><p>2.2</p><p>2.3</p><p>2.4</p><p>2.5</p></div>
      <div class="item"><h2>3.1</h2></div>
      <div class="item"><h2>4.1</h2><p>4.2</p><p>4.3</p><p>4.4</p></div>
      <div class="item"><p>5.1</p><p>5.2</p><p>5.3</p><p>5.4</p></div>
      <div class="item"><h2>6.1</h2><p>6.2</p></div>
      <div class="item"><h2>7.1</h2><p>7.2</p><p>7.3</p></div>
      <div class="item"><p>8.1</p><p>8.2</p></div>
    
    </div>

    【讨论】:

      【解决方案4】:

      您可以通过column 完成此操作。

      .wrapper {
          column-gap: 10px;
          column-count: 4;
      }
      
      .item {
          display: inline-block;
          background: #000;
          width: 100%;
          border-radius: 3px;
      }
      

      您似乎在尝试使用flexgrid 的组合,这可能会造成混淆。据我所知,flex 是相对于页面上的其余项目而言的,其中设置列会影响落入这些列的项目。

      updated codepen

      【讨论】:

      • 虽然这在理论上可以回答问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能会失效
      • @WillThresher,是什么让您认为“flex 与页面上的其余项目相关”? Flexbox 的特殊规则仅适用于具有display:flex 的元素的直接后代。
      猜你喜欢
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2021-12-22
      相关资源
      最近更新 更多