Вы можете сделать это, выбрав последнего нечетного ребенка и указав grid-column: 1 / -1
.
.grid {
border: 2.5px solid gray;
border-radius: 10px;
width: fit-content;
height: fit-content;
padding: 1em;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1em;
}
.grid__item {
min-width: 100px;
min-height: 100px;
border: 2.5px solid palevioletred;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
}
.grid__item:nth-child(2n-1):last-child {
background: pink;
grid-column: 1 / -1;
}
<div class = "grid">
<div class = "grid__item">1</div>
<div class = "grid__item">2</div>
<div class = "grid__item">3</div>
<div class = "grid__item">4</div>
<div class = "grid__item">5</div>
<div class = "grid__item">6</div>
<div class = "grid__item">7</div>
</div>
нет нет. Вы не используете сетку для этой задачи.
Вам понадобится display: flex
и немного математики.
Сначала создайте элемент контейнера и его элементы:
<div id = "grid">
<div class = "item">
<!-- ... -->
</div>
<!-- ...and more. -->
</div>
Затем сделайте его флексбоксом с помощью flex-wrap: wrap
:
#grid {
display: flex;
flex-wrap: wrap;
}
Пусть номер столбца, который мы хотим, будет c
. По наблюдениям мы знаем, что есть c
столбцов (по определению), c - 1
промежутков и 2 заполнения, которые в сумме составляют 100%
ширины контейнера:
┌──────────────────────────┐
│ ┌──┐ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │
│p│c1│g│c2│g│c3│g│c4│g│c5│p│
│ └──┘ └──┘ └──┘ └──┘ └──┘ │
│ │
│ │
│ │
│ │
└──────────────────────────┘
Это означает, что ширина элемента может быть рассчитана как:
w = (100% - (g * (c - 1)) - p * 2) / c
Мы соответствующим образом переводим это в CSS и добавляем flex-grow: 1
, чтобы последние элементы занимали все оставшиеся места:
.item {
flex-grow: 1;
width: calc((100% - var(--gap) * (var(--columns) - 1) - var(--padding) * 2) / var(--columns));
}
Попробуй это:
const grid = document.querySelector('#grid');
const input = document.querySelector('input');
input.addEventListener('input', function() {
grid.style.setProperty('--columns', this.value);
});
const l = 30 + Math.random() * 71 | 0;
for (let i = 1; i < l; i++) {
const item = document.createElement('div');
item.classList.add('item');
item.textContent = i;
grid.appendChild(item);
}
#grid {
--columns: 3;
--padding: 1em;
--gap: 1em;
display: flex;
flex-flow: row wrap;
gap: var(--gap);
border: 1px solid #000;
padding: var(--padding);
}
.item {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
height: 100px;
width: calc(
(
100% -
var(--gap) * (var(--columns) - 1) -
var(--padding) * 2
) /
var(--columns)
);
background: #ddd;
}
label {
position: fixed;
bottom: 2em;
left: 2em;
}
<div id = "grid"></div>
<label>
Columns:
<input type = "range" min = "1" max = "10" step = "1" value = "3">
</label>
Не рассчитывайте отступы и, кроме того, границу. Сделайте свою жизнь проще и используйте box-sizing: border-box
. Для родительского элемента применяется значение по умолчанию content-box
, если отступ не используется для ширины в первую очередь. Нет необходимости рассчитывать отступы там.
Поскольку этот аспект уже был рассмотрен в вашем ответе, я не собираюсь добавлять его в свой. Тем не менее, хороший звонок.
В целом это задача не для CSS-Grid, а для Flexbox. Во Flexbox вы можете использовать flex-grow: 1
, чтобы элементы увеличивались, чтобы заполнить оставшееся пространство.
Flexbox может использовать flex-wrap: wrap
, чтобы элементы, которые переполняются, переносились на следующую строку. Сложность здесь в том, что ширина каждого вызова должна быть рассчитана правильно.
Для расчетов я рекомендую использовать переменные CSS. Одна переменная для промежутков, а затем одна переменная для столбцов. Правильная ширина может быть рассчитана с помощью этого алгоритма:
width = ((100% - (size of gaps * (amount of columns - 1))) / amount of columns)
Для корректной работы для модели коробки контейнеров должно быть установлено значение по умолчанию (content-box
), а для модели коробки карточек должно быть установлено значение border-box
, чтобы отступы и границы были включены в ширину:
:root {
--gap: 1em;
}
section {
display: flex;
flex-wrap: wrap;
gap: var(--gap);
}
.col-2 {
--column: 2;
}
.col-3 {
--column: 3;
}
section > div {
flex-grow: 1;
box-sizing: border-box;
width: calc((100% - (var(--gap) * (var(--column) - 1))) / var(--column));
}
/* for demo purpose only */
section > div {
border: 2px dashed red;
text-align: center;
padding: 2em;
}
<h1>Grid with 2 columns and 3 cards</h1>
<section class = "col-2">
<div>1</div>
<div>2</div>
<div>3</div>
</section>
<h1>Grid with 3 columns and 4 cards</h1>
<section class = "col-3">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</section>
<h1>Grid with 3 columns and 5 cards</h1>
<section class = "col-3">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</section>
Отличное исправление для сетки 2x2, которое на самом деле решает мою проблему, но чтобы лучше ответить на вопрос, есть ли способ сделать это, который решает это для сетки 3x3 только с 1 или 2 элементами в последней строке?