Масонство с сеткой css

Я пытаюсь создать макетную раскладку с использованием макета сетки 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>

Ответы

Ответ 1

Это один из способов создания масонского макета с использованием только CSS.

*,
*: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>

Ответ 2

Вы можете установить значения span для grid-row-end динамически (с небольшим количеством JS, например, на основе эксперимента Codepen в примере ниже) и используйте ключевое слово dense для 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>

Ответ 3

В вашем вопросе вы устанавливаете высоту каждого элемента отдельно. Если вы с удовольствием сделаете это, макет можно легко выполнить с помощью сетки.

Вместо установки высоты для каждого набора элементов 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 об этом подходе, если он представляет интерес: макет стиля масонства с использованием CSS Grid

Ответ 4

Вы можете выполнить это с помощью column.

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

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

Похоже, вы пытались использовать комбинацию flex и grid, что, возможно, путало вещи. Насколько мне известно, flex относится к остальным элементам страницы, где установка столбца влияет на элементы, попадающие в эти столбцы.

обновленный код