Моя цель - создать адаптивную сетку с неизвестным количеством элементов с соотношением сторон 16: 9. Сейчас это выглядит так:
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, 160px);
grid-template-rows: 1fr;
grid-gap: 20px;
}
.item {
height: 90px;
background: grey;
}<div class = "grid">
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
</div>Проблема в том, что элементы не масштабируются с размером экрана, что приводит к появлению поля на правильном сайте. Но когда сетка адаптируется к размеру экрана, например, с помощью grid-template-columns: repeat(auto-fit, minmax(160p, 1fr)) и удаляется height: 90px;, соотношение сторон не сохраняется.
Может быть, есть лучшее решение без css grid? (Возможно, используя javascript)
Это именно то, что я искал! Если вы ответите на вопрос, я поставлю вам галочку в качестве решения :) Спасибо!






Возможно, я не могу понять вопрос, но как вы планируете сохранить соотношение сторон элемента 16: 9, при этом желая масштабировать элементы по ширине экрана?
Если вас устраивают элементы с увеличенной шириной между размерами экрана, это может сработать:
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
grid-template-rows: 1fr;
grid-gap: 20px;
}
.item {
height: 90px;
background: grey;
}<div class = "grid">
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
</div>Ваше решение действительно хорошее, но проблема в том, что соотношение 16: 9 не сохраняется. Они не должны «растягиваться» по оси абсцисс. Есть ли способ масштабировать их по обеим осям?
Когда ширина экрана увеличивается, они либо растягиваются (что разрушит 16: 9, мое решение), либо оставляют поля (между или в конце, ваше решение). Нет третьей возможности, имо. Какую ты хочешь?
Взгляните на эту страницу: ссылка на сайт (мне нужен похожий вид, но без указания 10 разной ширины экрана @media)
Мое решение делает именно это. Попробуйте здесь. Если вы увеличите ширину экрана, элементы будут временно растягиваться, но когда экран станет настолько широким, что в него может поместиться новый элемент, все элементы вернутся к ширине 160 пикселей, и к ним присоединится новый элемент (160 пикселей).
Но на странице, которую я отправил вам, элементы не растягиваются (они одинаково масштабируются с обеих сторон)
Вы можете воспользоваться тем фактом, что процентное заполнение зависит от ширины.
Эта статья о CSS-хитростях хорошо объясняет идею:
...if you had an element that is 500px wide, and padding-top of 100%, the padding-top would be 500px.
Isn't that a perfect square, 500px × 500px? Yes, it is! An aspect ratio!
If we force the height of the element to zero (height: 0;) and don't have any borders. Then padding will be the only part of the box model affecting the height, and we'll have our square.
Now imagine instead of 100% top padding, we used 56.25%. That happens to be a perfect 16:9 ratio! (9 / 16 = 0.5625).
Итак, чтобы столбцы сохранили соотношение сторон:
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr))
Добавьте к элементам псевдоэлемент, чтобы сохранить соотношение сторон 16: 9:
.item: before { содержание: ""; дисплей: блок; высота: 0; ширина: 0; padding-bottom: calc (9/16 * 100%); }
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
grid-template-rows: 1fr;
grid-gap: 20px;
}
.item {
background: grey;
display: flex;
justify-content: center;
}
.item:before {
content: "";
display: block;
height: 0;
width: 0;
padding-bottom: calc(9/16 * 100%);
}<div class = "grid">
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
<div class = "item"></div>
</div>Я столкнулся с небольшой проблемой ... Элементы становятся действительно огромными, если в сетке всего 1 или 2 элемента ... Есть ли способ предотвратить такое поведение?
да, попробуйте заменить auto-fit на auto-fill - см. мой пост здесь в пункте 2, я объяснил разницу
Ох, как я мог не подумать об этом ... Огромное спасибо за помощь!
Когда я вставляю много текста в первый элемент, весь ряд элементов растягивается внизу. Разве нельзя СОХРАНИТЬ соотношение сторон 16: 9?
Мне любопытно, как этого добиться с изображениями. Не с фоновыми изображениями, а с изображениями, использующими свойство объектно-подходящего css.
По моему опыту, это не работает с фиксированной высотой.
Мне нужно было то же самое для макетов видео, но я не мог использовать другие ответы, потому что мне нужно было ограничиваться шириной а также height. В основном моим вариантом использования был контейнер определенного размера, неизвестного количества элементов и фиксированного соотношения сторон элементов. К сожалению, это невозможно сделать в чистом CSS, для этого нужен JS. Мне не удалось найти хороший алгоритм упаковки контейнеров, поэтому я написал его сам (при условии, что он может имитировать существующие).
По сути, я взял максимальный набор строк и нашел подходящее с наилучшим соотношением. Затем я нашел лучшие границы элементов, сохраняющие соотношение сторон, а затем установил их как автоматически подгоняемые по высоте и ширине для сетки CSS. Результат довольно приятный.
Вот полный пример, показывающий, как использовать его с чем-то вроде настраиваемых свойств CSS. Первая JS-функция является основной, которая определяет наилучший размер. Добавляйте и удаляйте элементы, изменяйте размер браузера, чтобы увидеть, как он сбрасывается для оптимального использования пространства (или вы можете увидеть эта версия CodePen).
// Get the best item bounds to fit in the container. Param object must have
// width, height, itemCount, aspectRatio, maxRows, and minGap. The itemCount
// must be greater than 0. Result is single object with rowCount, colCount,
// itemWidth, and itemHeight.
function getBestItemBounds(config) {
const actualRatio = config.width / config.height
// Just make up theoretical sizes, we just care about ratio
const theoreticalHeight = 100
const theoreticalWidth = theoreticalHeight * config.aspectRatio
// Go over each row count find the row and col count with the closest
// ratio.
let best
for (let rowCount = 1; rowCount <= config.maxRows; rowCount++) {
// Row count can't be higher than item count
if (rowCount > config.itemCount) continue
const colCount = Math.ceil(config.itemCount / rowCount)
// Get the width/height ratio
const ratio = (theoreticalWidth * colCount) / (theoreticalHeight * rowCount)
if (!best || Math.abs(ratio - actualRatio) < Math.abs(best.ratio - actualRatio)) {
best = { rowCount, colCount, ratio }
}
}
// Build item height and width. If the best ratio is less than the actual ratio,
// it's the height that determines the width, otherwise vice versa.
const result = { rowCount: best.rowCount, colCount: best.colCount }
if (best.ratio < actualRatio) {
result.itemHeight = (config.height - (config.minGap * best.rowCount)) / best.rowCount
result.itemWidth = result.itemHeight * config.aspectRatio
} else {
result.itemWidth = (config.width - (config.minGap * best.colCount)) / best.colCount
result.itemHeight = result.itemWidth / config.aspectRatio
}
return result
}
// Change the item size via CSS property
function resetContainerItems() {
const itemCount = document.querySelectorAll('.item').length
if (!itemCount) return
const container = document.getElementById('container')
const rect = container.getBoundingClientRect()
// Get best item bounds and apply property
const { itemWidth, itemHeight } = getBestItemBounds({
width: rect.width,
height: rect.height,
itemCount,
aspectRatio: 16 / 9,
maxRows: 5,
minGap: 5
})
console.info('Item changes', itemWidth, itemHeight)
container.style.setProperty('--item-width', itemWidth + 'px')
container.style.setProperty('--item-height', itemHeight + 'px')
}
// Element resize support
const resObs = new ResizeObserver(() => resetContainerItems())
resObs.observe(document.getElementById('container'))
// Add item support
let counter = 0
document.getElementById('add').onclick = () => {
const elem = document.createElement('div')
elem.className = 'item'
const button = document.createElement('button')
button.innerText = 'Delete Item #' + (++counter)
button.onclick = () => {
document.getElementById('container').removeChild(elem)
resetContainerItems()
}
elem.appendChild(button)
document.getElementById('container').appendChild(elem)
resetContainerItems()
}#container {
display: inline-grid;
grid-template-columns: repeat(auto-fit, var(--item-width));
grid-template-rows: repeat(auto-fit, var(--item-height));
place-content: space-evenly;
width: 90vw;
height: 90vh;
background-color: green;
}
.item {
background-color: blue;
display: flex;
align-items: center;
justify-content: center;
}<!--
Demonstrates how to use CSS grid and add a dynamic number of
items to a container and have the space best used while
preserving a desired aspect ratio.
Add/remove items and resize browser to see what happens.
-->
<button id = "add">Add Item</button><br />
<div id = "container"></div>Это здорово, я повсюду искал что-то подобное, спасибо за публикацию!
Если у вас 2 div в первой строке и 1 div во второй строке, нашли ли вы способ центрировать 1 div во второй строке?
Теперь мы можем использовать свойство CSS4 aspect-ratio (Могу ли я использовать ?), чтобы легко управлять соотношением сторон без отступов и трюков с псевдоэлементами. В сочетании с object-fit мы получаем очень интересный рендеринг.
Вот фотографии в различных пропорциях, которые мне нужно отрендерить в формате 16/9:
section {
display: grid;
gap: 10px;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* Play with min-value */
}
img {
background-color: gainsboro; /* To visualize empty space */
aspect-ratio: 16/9;
/*
"contain" to see full original image with eventual empty space
"cover" to fill empty space with truncating
"fill" to stretch
*/
object-fit: contain;
width: 100%;
}<section>
<img src = "https://placeimg.com/640/360/architecture">
<img src = "https://placeimg.com/640/360/tech">
<img src = "https://placeimg.com/360/360/animals">
<img src = "https://placeimg.com/640/360/people">
<img src = "https://placeimg.com/420/180/architecture">
<img src = "https://placeimg.com/640/360/animals">
<img src = "https://placeimg.com/640/360/nature">
</section>Детская площадка: https://codepen.io/JCH77/pen/JjbajYZ
Примерно так: codepen.io/danield770/pen/bjYvOj?