15

我正在尝试使用 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>

完整的codepen在这里

4

4 回答 4

2

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

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

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

grid-auto-rows然后项目的高度将取决于grid-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

于 2017-09-26T20:38:30.697 回答
0

这是仅使用 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>

注意:代码不是我自己做的,我自己做了一些小的改编,原代码可以在这里找到。


请注意,正如Zen所指出的:

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

于 2017-05-11T14:57:01.810 回答
0

您可以动态设置spangrid-row-end(使用一些 JS,例如下面示例中基于我的Codepen 实验的值)并使用dense关键字 for grid-auto-placement

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>

于 2017-08-07T07:39:19.650 回答
-2

您可以使用column.

.wrapper {
    column-gap: 10px;
    column-count: 4;
}

.item {
    display: inline-block;
    background: #000;
    width: 100%;
    border-radius: 3px;
}

看起来您正在尝试使用 and 的组合flexgrid这可能会造成混淆。据我所知, flex 与页面上的其余项目相关,其中设置列会影响落入这些列的项目。

更新的代码笔

于 2017-05-11T14:13:42.960 回答