flo*_*olu 5 html css sass responsive-design css-grid
我的目标是创建一个响应网格,其中包含未知数量的项目,其长宽比保持在16:9。现在看起来像这样:
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, 160px);
grid-template-rows: 1fr;
grid-gap: 20px;
}
.item {
height: 90px;
background: grey;
}Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
问题在于,这些项目不会随屏幕尺寸缩放,从而在正确的位置留出空白。但是,当使用例如:使网格适应屏幕尺寸grid-template-columns: repeat(auto-fit, minmax(160p, 1fr))并删除时height: 90px;,长宽比不会持久。
如果没有CSS网格,也许有更好的解决方案?(也许使用JavaScript)
JCH*_*H77 19
我们现在可以使用aspect-ratioCSS4 属性(我可以使用吗?)来轻松管理宽高比,而无需填充和伪元素技巧。结合起来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%;
}Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
游乐场:https://codepen.io/JCH77/pen/JjbajYZ
我需要与视频布局完全相同的东西,但我无法使用其他答案,因为我需要受到宽度和高度的限制。基本上我的用例是一个具有一定大小、未知项目数量和固定长宽比的项目的容器。不幸的是,这不能在纯 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.log('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()
}Run Code Online (Sandbox Code Playgroud)
#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;
}Run Code Online (Sandbox Code Playgroud)
<!--
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>Run Code Online (Sandbox Code Playgroud)
您可以利用以下事实:百分比填充基于宽度。
这篇CSS技巧文章很好地解释了这个想法:
...如果元素的宽度为500px,且padding-top为100%,则padding-top为500px。
那不是500px×500px的完美正方形吗?是的!长宽比!
如果我们强制元素的高度为零(高度:0;)并且没有任何边界。然后,填充将成为影响高度的盒子模型的唯一部分,我们将得到正方形。
现在想象一下,我们使用56.25%代替100%顶部填充。碰巧是完美的16:9比例!(9/16 = 0.5625)。
因此,为了使列保持长宽比:
1)根据您的建议设置列宽:
grid-template-columns: repeat(auto-fit, minmax(160p, 1fr))
2)在项目中添加一个伪元素以保持16:9的宽高比:
.item:before {
content: "";
display: block;
height: 0;
width: 0;
padding-bottom: calc(9/16 * 100%);
}
Run Code Online (Sandbox Code Playgroud)
.item:before {
content: "";
display: block;
height: 0;
width: 0;
padding-bottom: calc(9/16 * 100%);
}
Run Code Online (Sandbox Code Playgroud)
.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%);
}Run Code Online (Sandbox Code Playgroud)