Масонство с сеткой 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 относится к остальным элементам страницы, где установка столбца влияет на элементы, попадающие в эти столбцы.
обновленный код