一种计算响应式网格中列的方法
A way to count columns in a responsive grid
虽然我还没有找到答案,但是问题很简单:有没有办法,除了暴力force, 计算响应式网格中的列数?
#grid-container {
width: 100%;
height: 85%;
position: relative;
padding: var(--gap); /* adjusted with JS to make var(--gap) responsive */
display: grid;
grid-gap: var(--gap); /* adjusted with JS to make var(--gap) responsive */
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
box-sizing: border-box;
background: skyblue;
}
.grid-item {
width: 100%;
min-width: 120px;
max-width: 450px;
height: ; /* adjusted with JS on resize events to roughly maintain proportions */
min-height: 192px;
border-radius: 10px;
background: #333;
}
我问的原因是因为我给了网格项 max-width
导致最后一个断点处出现巨大间隙,我希望能够检测到它而不是设置显式媒体查询.
我认为没有蛮力的最简单方法是考虑一个简单的除法。您可以轻松找到容器的宽度,每列由 minmax(300px,1fr)
定义,我们知道 gap
。使用所有这些信息,计算应如下所示:
如果我们将有 N
列,那么我们将有 N-1
个间隙。我们也知道 W
至少应该是 300px
并且不能超过一个值(我们将调用 Wmax
)。
假设差距等于 10px
。
如果 N=2
且每列等于 300px
,我们的容器宽度将等于 300px*2 + 10px*1 = 610px
。
如果 N=3
并且每列等于 300px
我们将有 300px*3 + 10px*2=920px
.
现在很明显,如果容器宽度在 610px
和 920px
之间,我们将有 2 列,因为没有 space 来容纳 3 列,但足够 space 来容纳 2 列,我们扩展这些列以填充剩余的 space(使用 1fr
),所以 Wmax
在这种情况下是 (920px - 10px)/2 = 455px
。换句话说,当有 2 列时,宽度将从 300px
到 455px
不等。
因此,如果我们采用公式 300px*N + 10px*(N-1) = Wc
和 Wc
我们的容器宽度,您会看到 N
等于 2
当 Wc=610px
和 3
when Wc=920px
and between 我们将得到 [2,3]
的结果,所以我们只需将值四舍五入到最小值(在本例中为 2),我们将得到列号。
这是一个基本示例:
var gap = 10;
var minW = 200;
var Wc = document.querySelector('.grid').offsetWidth;
var N = Math.floor((Wc+gap)/(minW+gap));
console.log(N);
window.addEventListener('resize', function(event){
Wc = document.querySelector('.grid').offsetWidth;
N = Math.floor((Wc+gap)/(minW+gap));
console.log(N);
});
.grid {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
grid-gap:10px;
}
span {
min-height:50px;
background:red;
}
<div class="grid">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
如果您不知道 gap 和 min-width 的值,您可以考虑 getComputedStyle()
来获取不同的值。在这种情况下,N
应该已经是一个整数,因为 grid-template-columns
将为我们提供每列的计算宽度(实际上,由于四舍五入,我们仍然会有一些分数)。
var grid = document.querySelector('.grid');
var gap = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("column-gap"));
var minW = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("grid-template-columns"));
var Wc = document.querySelector('.grid').offsetWidth;
var N = (Wc+gap)/(minW+gap);
console.log(N);
window.addEventListener('resize', function(event){
Wc = document.querySelector('.grid').offsetWidth;minW = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("grid-template-columns"))
N = (Wc+gap)/(minW+gap);
console.log(N);
});
.grid {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
grid-gap:10px;
}
span {
min-height:50px;
background:red;
}
<div class="grid">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
获取 css 网格的 rows/columns 数量的一种方法是使用 grid-template-rows
或 grid-template-columns
从网格的计算样式 window.getComputedStyle(grid)
.
返回值始终是 transformed to separated pixel values(例如 20px 20px 50px),其中每个值代表各自 column/row 的大小。剩下要做的就是将字符串拆分成一个数组并计算值的数量。
const gridComputedStyle = window.getComputedStyle(grid);
// get number of grid rows
const gridRowCount = gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").length;
// get number of grid columns
const gridColumnCount = gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length;
console.log(gridRowCount, gridColumnCount);
这是完整的片段 (Codepen):
function getGridData () {
// calc computed style
const gridComputedStyle = window.getComputedStyle(grid);
return {
// get number of grid rows
gridRowCount: gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").length,
// get number of grid columns
gridColumnCount: gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length,
// get grid row sizes
gridRowSizes: gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").map(parseFloat),
// get grid column sizes
gridColumnSizes: gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").map(parseFloat)
}
}
window.addEventListener("DOMContentLoaded", outputGridData);
window.addEventListener("resize", outputGridData);
function outputGridData () {
const gridData = getGridData();
output.textContent = `
Rows: ${gridData.gridRowCount}
Columns: ${gridData.gridColumnCount}
Rows sizes: ${gridData.gridRowSizes}
Column sizes: ${gridData.gridColumnSizes}
`;
}
#grid {
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fill, 200px);
}
#output {
white-space: pre-wrap;
}
.A, .B, .C {
font-family: Arial;
font-weight: 600;
font-size: 2rem;
border-radius: 50% 50%;
width: 80px;
height: 80px;
text-align: center;
line-height: 80px;
box-shadow: -3px 5px 20px -3px #AAA;
border: solid 10px #fff;
color: #fff;
}
.A {
background: #ffc300;
}
.B {
background: #c70039;
}
.C {
background: #581845;
}
<div id="output"></div>
<div id="grid">
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
</div>
虽然我还没有找到答案,但是问题很简单:有没有办法,除了暴力force, 计算响应式网格中的列数?
#grid-container {
width: 100%;
height: 85%;
position: relative;
padding: var(--gap); /* adjusted with JS to make var(--gap) responsive */
display: grid;
grid-gap: var(--gap); /* adjusted with JS to make var(--gap) responsive */
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
box-sizing: border-box;
background: skyblue;
}
.grid-item {
width: 100%;
min-width: 120px;
max-width: 450px;
height: ; /* adjusted with JS on resize events to roughly maintain proportions */
min-height: 192px;
border-radius: 10px;
background: #333;
}
我问的原因是因为我给了网格项 max-width
导致最后一个断点处出现巨大间隙,我希望能够检测到它而不是设置显式媒体查询.
我认为没有蛮力的最简单方法是考虑一个简单的除法。您可以轻松找到容器的宽度,每列由 minmax(300px,1fr)
定义,我们知道 gap
。使用所有这些信息,计算应如下所示:
如果我们将有 N
列,那么我们将有 N-1
个间隙。我们也知道 W
至少应该是 300px
并且不能超过一个值(我们将调用 Wmax
)。
假设差距等于 10px
。
如果 N=2
且每列等于 300px
,我们的容器宽度将等于 300px*2 + 10px*1 = 610px
。
如果 N=3
并且每列等于 300px
我们将有 300px*3 + 10px*2=920px
.
现在很明显,如果容器宽度在 610px
和 920px
之间,我们将有 2 列,因为没有 space 来容纳 3 列,但足够 space 来容纳 2 列,我们扩展这些列以填充剩余的 space(使用 1fr
),所以 Wmax
在这种情况下是 (920px - 10px)/2 = 455px
。换句话说,当有 2 列时,宽度将从 300px
到 455px
不等。
因此,如果我们采用公式 300px*N + 10px*(N-1) = Wc
和 Wc
我们的容器宽度,您会看到 N
等于 2
当 Wc=610px
和 3
when Wc=920px
and between 我们将得到 [2,3]
的结果,所以我们只需将值四舍五入到最小值(在本例中为 2),我们将得到列号。
这是一个基本示例:
var gap = 10;
var minW = 200;
var Wc = document.querySelector('.grid').offsetWidth;
var N = Math.floor((Wc+gap)/(minW+gap));
console.log(N);
window.addEventListener('resize', function(event){
Wc = document.querySelector('.grid').offsetWidth;
N = Math.floor((Wc+gap)/(minW+gap));
console.log(N);
});
.grid {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
grid-gap:10px;
}
span {
min-height:50px;
background:red;
}
<div class="grid">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
如果您不知道 gap 和 min-width 的值,您可以考虑 getComputedStyle()
来获取不同的值。在这种情况下,N
应该已经是一个整数,因为 grid-template-columns
将为我们提供每列的计算宽度(实际上,由于四舍五入,我们仍然会有一些分数)。
var grid = document.querySelector('.grid');
var gap = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("column-gap"));
var minW = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("grid-template-columns"));
var Wc = document.querySelector('.grid').offsetWidth;
var N = (Wc+gap)/(minW+gap);
console.log(N);
window.addEventListener('resize', function(event){
Wc = document.querySelector('.grid').offsetWidth;minW = parseFloat(window.getComputedStyle(grid,null).getPropertyValue("grid-template-columns"))
N = (Wc+gap)/(minW+gap);
console.log(N);
});
.grid {
display:grid;
grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
grid-gap:10px;
}
span {
min-height:50px;
background:red;
}
<div class="grid">
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
获取 css 网格的 rows/columns 数量的一种方法是使用 grid-template-rows
或 grid-template-columns
从网格的计算样式 window.getComputedStyle(grid)
.
返回值始终是 transformed to separated pixel values(例如 20px 20px 50px),其中每个值代表各自 column/row 的大小。剩下要做的就是将字符串拆分成一个数组并计算值的数量。
const gridComputedStyle = window.getComputedStyle(grid);
// get number of grid rows
const gridRowCount = gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").length;
// get number of grid columns
const gridColumnCount = gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length;
console.log(gridRowCount, gridColumnCount);
这是完整的片段 (Codepen):
function getGridData () {
// calc computed style
const gridComputedStyle = window.getComputedStyle(grid);
return {
// get number of grid rows
gridRowCount: gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").length,
// get number of grid columns
gridColumnCount: gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").length,
// get grid row sizes
gridRowSizes: gridComputedStyle.getPropertyValue("grid-template-rows").split(" ").map(parseFloat),
// get grid column sizes
gridColumnSizes: gridComputedStyle.getPropertyValue("grid-template-columns").split(" ").map(parseFloat)
}
}
window.addEventListener("DOMContentLoaded", outputGridData);
window.addEventListener("resize", outputGridData);
function outputGridData () {
const gridData = getGridData();
output.textContent = `
Rows: ${gridData.gridRowCount}
Columns: ${gridData.gridColumnCount}
Rows sizes: ${gridData.gridRowSizes}
Column sizes: ${gridData.gridColumnSizes}
`;
}
#grid {
display: grid;
grid-gap: 20px;
grid-template-columns: repeat(auto-fill, 200px);
}
#output {
white-space: pre-wrap;
}
.A, .B, .C {
font-family: Arial;
font-weight: 600;
font-size: 2rem;
border-radius: 50% 50%;
width: 80px;
height: 80px;
text-align: center;
line-height: 80px;
box-shadow: -3px 5px 20px -3px #AAA;
border: solid 10px #fff;
color: #fff;
}
.A {
background: #ffc300;
}
.B {
background: #c70039;
}
.C {
background: #581845;
}
<div id="output"></div>
<div id="grid">
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
</div>