【问题标题】:A way to count columns in a responsive grid一种计算响应式网格中列的方法
【发布时间】:2019-08-07 19:24:13
【问题描述】:

虽然我还没有找到答案,但问题很简单:有没有办法, 除了蛮力, 计算响应式网格中的列数?

#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,这会在最后一个断点处导致巨大的间隙,我希望能够检测到它而不是设置显式媒体查询。

【问题讨论】:

  • 你已经设置了max-width: 450px,但是在最后一个断点你想让它超过这个值吗?
  • 如果你增加grid-gap,你可以看到在其他断点中你也会开始看到这个gap...考虑删除max-width
  • @kukkuz 我只是希望能够计算在任何给定时间显示的列数,而无需创建一些复杂的算法
  • 我可能完全误解了这一点,但您不只是在寻找:last-child 选择器吗?或者您是否明确需要列的数量?如果是这样并且您的#grid-container 中只有列,您可以使用childNodes property
  • @Evochrome 你太离谱了,哈哈。在响应式网格中,例如我的问题中的网格,列数会随着您调整窗口大小而增加或减少。在不创建一些蛮力算法的情况下,我要做的就是能够知道在任何给定时间显示了多少列。另外,childNodes 只会返回一个子节点数组??

标签: javascript css css-grid grid-layout


【解决方案1】:

获取 CSS 网格的行数/列数的一种方法是使用网格的计算样式 window.getComputedStyle(grid) 中的 grid-template-rowsgrid-template-columns

返回值始终为transformed to separated pixel values(例如 20px 20px 50px),其中每个值代表相应列/行的大小。剩下要做的就是将字符串拆分为一个数组并计算值的数量。

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);

这是完整的 sn-p (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>

【讨论】:

  • 这对响应式网格有用吗?例如,随着网格和列数和行数的缩小或增长,这个值会相应地更新吗?
  • @BugWhisperer 是的,只需查看链接的 Codepen 示例并调整窗口大小
  • 这太棒了!您是否知道单个网格项目上的任何计算样式,我们可以用来计算坐标?即:第 2 行第 3 列?
  • 这很好,谢谢,虽然……我发现有时计算的列以“0px”结尾,导致列计算结果为 1。只需在 @ 之前添加 .replace(' 0px', '') 即可修复987654331@.
  • @JonathanSchofield 我已经使用replace(/ 0px/g, "")(正则表达式而不是字符串)测试了您的解决方案,它对我来说可以正常工作。它只计算可见的非零列/行。我从未遇到过零宽度行与非零宽度行具有相同宽度的情况。
【解决方案2】:

我认为没有蛮力最简单的方法是考虑一个简单的划分。您可以轻松找到容器的宽度,每列由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

现在很明显,如果容器宽度在 610px920px 之间,我们将有 2 列,因为没有空间容纳 3 列,但有足够的空间容纳 2 列,我们展开以填充剩余空间(使用1fr) 所以Wmax 在这种情况下是(920px - 10px)/2 = 455px。换句话说,当有 2 列时,宽度将在 300px455px 之间变化。

因此,如果我们采用公式 300px*N + 10px*(N-1) = WcWc 容器宽度,您将看到 NWc=610px3 时等于 2Wc=920px 和之间我们将有一个结果为[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>

【讨论】:

  • 如果不考虑这种蛮力,我几乎会考虑,并且 id 还必须考虑填充等,但尽管如此,这种方法的问题是列在 最少 300px,有时不是300px??理想情况下,我希望能够单独使用 CSS 来做到这一点,但我们都同意这绝对是不可能的,因为没有办法知道 innerWidth,对吗?当我有更多空闲时间时,我必须回到这个问题
  • @Anthony 至少 300px 只是为了解释一个特定的案例,以便您理解逻辑,正如您在上一个示例中看到的那样,它是动态的,我使用了 200px不是 300px ...关于填充,这也很容易,因为使用 JS 你可以得到宽度减去填充和边框等。当然只有 CSS 是不可能的。
  • 哦,所以你说的是300pxminmax 中的min 的值可以或用于公式/算法中而不会出现问题。
  • 为了计算Wmax,为什么要减去10px再除以2?你为什么要这样计算Wmax?是不是减去10px 就代表了少一列的网格?
  • 如果我想扩展网格每一侧的填充以防止具有不同数量子级的行,考虑到#grid { grid-gap: var(--grid-gap); padding: 0 var(--grid-gap) } 中的var(--grid-gap) 是响应式的,这变得非常棘手。
猜你喜欢
  • 2016-09-03
  • 1970-01-01
  • 2021-10-14
  • 2016-05-18
  • 1970-01-01
  • 2021-01-24
  • 2017-10-13
  • 2022-09-28
相关资源
最近更新 更多