簡體   English   中英

一種計算響應式網格中列的方法

[英]A way to count columns in a responsive grid

雖然我還沒有找到答案,但問題很簡單:除了蠻力之外,有沒有辦法計算響應式網格中的列數?

#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 ,這會在最后一個斷點處造成巨大的間隙,我希望能夠檢測到它而不是設置顯式媒體查詢。

在此處輸入圖像描述

獲取 CSS 網格的行數/列數的一種方法是使用網格window.getComputedStyle(grid)的計算樣式中的grid-template-rowsgrid-template-columns

返回的值總是轉換為單獨的像素值(例如 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);

這是完整的代碼段( 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>

我認為沒有蠻力的最簡單方法是考慮一個簡單的划分。 您可以輕松找到容器的寬度,每列由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 列時,寬度將從300px變化到455px

因此,如果我們采用公式300px*N + 10px*(N-1) = WcWc我們的容器寬度,您將看到當 Wc=610px 時N等於2 ,當Wc=610px Wc=920px N 等於3並且在兩者之間我們將得到一個結果在[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>

我喜歡@Robbendebiene 的回答,並將它變成了一個簡單的 react/ts 鈎子來獲取 nCols。 我的項目需要這樣一個鈎子。 在這里張貼,以防它節省任何人一些時間!

/**
 * @param containerRef Ref to HTMLElement with grid styles applied
 * @param defaultCount Count to return during SSR or if the containerRef is not yet set
 * @returns number of columns visible in the grid (updates on resize or containerRef change)
 */
const useVisibleGridCols = <T extends HTMLElement>(
  containerRef:RefObject<T>, defaultCount:number = 1):number => {
  const [visibleCols, setVisibleCols] = useState(defaultCount);

  useEffect(() => {
    const calcColumns = () => {
      // Abord if no ref
      if (!containerRef.current) return;

      // infer # of cols by parsing the computed grid-template-columns
      // see https://stackoverflow.com/a/58393617/5389588
      const containerComputerStyle = window
        .getComputedStyle(containerRef.current);
      const nCols = containerComputerStyle
        .getPropertyValue('grid-template-columns')
        .replace(' 0px', '')
        .split(' ')
        .length;

      // Update
      setVisibleCols(nCols);
    };

    // Do it now
    calcColumns();

    // And on resize
    window.addEventListener('resize', calcColumns);
    return () => {
      window.removeEventListener('resize', calcColumns);
    };
  }, [containerRef, setVisibleCols]);

  return visibleCols;
};

簡而言之,在數學上:

Math.floor((containerWidth + gapWidth) / (columnWidth + gapWidth))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM