網格佈局grid

2023-10-27 06:00:43

起因

昨天面試的時候,出了一道面試題,模擬面試公司的列表的元素寬度伸縮變化,根據螢幕大小的不同,一行上放置最多的元素,元素寬度不固定,間距固定,可換行,靠左對齊,當時猜出來用flex➕js監聽resize來實現,最後發現媒體查詢結合grid即可實現,所以今天的重頭戲就是 grid

定義

grid 是一種佈局方案,css3的一種屬性,叫網格佈局,它將網頁劃分成一個個網格,可以任意組合的網格
類似於彈性佈局flex,flex是一維佈局,grid是二維佈局,有縱向也有橫向
網格容器是決定將網格分為幾行幾列
用途,舉個例子:

根據這個範例,如果按照平時寫法,會巢狀很多div進行佈局,而grid的出現,就是為了解決這個佈局

概念介紹

宣告方式

  1. display: grid
    指定容器使用網格佈局

  2. display: inline-grid
    指定容器設為行內元素並使用網格佈局

兩者的區別:

  1. display: grid預設情況下,元素會獨佔一行,並且如果有多個元素,則會按順序從左到右排列(比如說,一行上每個元素等比展示,正好佈滿一行)
  2. display: inline-grid 元素會根據內容進行自動調整大小,並與其他行內元素在同一行中排列(比如說,一行上每個元素的寬度取決於其中某個元素最長的寬度,並不一定佈滿一行)

注意:只是宣告這一個屬性,也不會生效 因為display: grid的宣告只建立了一個只有一列的網格,所以你的子項還是會像正常佈局流那樣從上而下一個接一個的排布,需要使用一些屬性,才能變成網格

定義

  1. 網格容器
    當一個元素的屬性設定為display:grid時, 它是所有網格項(Grid Items)的直接父元素,比如下面的con

    <div class="con">
      <div class="item"></div>
      <div class="item"></div>
      <div class="item"></div>
    </div>
    
  2. 網格項
    網格容器的子節點元素。這裡 item元素都是網格項,但是sub-item不包含其中
    說明,網格項只存在於父子之間的關係,不存在祖孫的關係

    <div class="con">
      <div class="item"></div>
      <div class="item"></div>
      <div class="item">
        <div class="sub-item"></div>
      </div>
    </div>
    
  3. 網格列 column
    網格項的垂直線被稱為列

  4. 網格行 row
    網格項的水平線被稱為行。

  5. 網格間隙
    每列/行之間的間隔

屬性介紹

容器屬性

容器屬性,顧名思義就是作用於容器上的,就是宣告display:grid的標籤上的屬性

  1. grid-template-columns
    網格佈局中的列數,並可定義每列的寬度,該值是以空格分隔的列表,其中每個值定義相應列的長度。

    .con{
      display: grid;
      /* 按照固定寬度分配(px,rem,em,pt) */
      grid-template-columns: 100px 200px 300px 400px; 
      /* 將根據內容的大小自動調整。這意味著網格項將根據其內部的內容來決定寬度,並自動適應不同內容的大小 */
      grid-template-columns: auto auto auto auto;
      /* 相對單位,表示剩餘空間的分數 */
      grid-template-columns: 1fr 1fr 1fr 1fr;
      /* 相對於父元素的寬度 */
      grid-template-columns: 20% 30% 40% 30%;
      /* 第一個列寬度為 100px,第二個列寬度為父元素寬度的 20%,第三個列寬度為 200px,第四個列將根據內容自動調整  */
      grid-template-columns: 100px 20% 200px auto;
      /* 第一列寬度為100px,第二列為剩餘寬度的2/3,第三列為固定寬度200px;第四列為剩餘寬度的1/3 */
      grid-template-columns: 100px 2fr 200px 1fr;
      /* !!!!!!! 1fr代表就一列,個數代表有幾列 */
      grid-template-columns: 1fr;
      /* 有兩列 */
      grid-template-columns: 1fr 1fr;
      /* 重複建立三個等1fr的列 */
      grid-template-columns: repeat(3, 1fr);
      /* 重複建立三個等200px的列 */
      grid-template-columns: repeat(3, 200px);
      /* 同上 */
      grid-template-columns: auto;
      grid-template-rows: auto;
    }
    
  2. grid-template-rows
    網格佈局中的行數,定義每列的高度,同理,該值是以空格分隔的列表,其中每個值定義相應列的高度。
    例子和grid-template-columns一樣,略有不同,當元素沒有那麼多時,高度會固定,下邊會有空白

    .con{
      display: grid;
      grid-template-columns: 1fr 1fr;
      /* 按照固定高度分配(px,rem,em,pt) */
      grid-template-rows: 100px 200px 300px 400px; 
      /* 將根據內容的高度自動調整。這意味著網格項將根據其內部的內容來決定高度 */
      grid-template-rows: auto auto auto auto;
      /* 根據內容高度 */
      grid-template-rows: 1fr 1fr 1fr 1fr;
      /* 第二行將會比其他行略高,因為它佔據了剩餘空間的 2/5。其他行將均分剩餘空間的 1/5 */
      grid-template-rows: 1fr 2fr 1fr 1fr;
      /* 相對於父元素的高度對其進行分配 */
      grid-template-rows: 20% 30% 40% 30%;
      /* 第一個列高度為 100px,第二個列高度為父元素高度的 20%,第三個列高度為 200px,第四個列將根據內容自動調整 */
      /* 有溢位的情況,主要原因是如果網格項的高度使用百分比進行定義,則該百分比是相對於其父容器的高度計算的。如果父容器的高度沒有明確設定或是受到其他因素的影響,可能導致計算出的高度與預期不符,從而導致溢位 */
      grid-template-rows: 100px 20% 200px auto;
      /* 第一列高度為100px,第二列為剩餘高度的2/3,第三列為固定高度200px;第四列為剩餘高度的1/3 */
      /* 重複建立三個等1fr的行 */
      grid-template-rows: repeat(3, 1fr);
      /* 重複建立三個等200px的行 */
      grid-template-rows: repeat(3, 200px);
      grid-template-rows: 100px 2fr 200px 1fr;
    }
    
  3. justify-content
    在網格容器內對齊整個網格,和flex的justify-content意思一樣,不過多了個space-evenly

    .con{
      display: grid;
      /* 注意!!!!1fr為單位的無法生效 */
      grid-template-colums: 20% 20% 20%;
      grid-template-rows: auto;
      /* 網格項在主軸的末尾位置對齊 */
      justify-content: end;
      /* 預設值 */
      /* 網格項在主軸的起始位置對齊 */
      justify-content: start;
      /* 網格項在主軸的中間位置對齊 */
      justify-content: center;
      /* 網格項在主軸上均勻分佈,並且兩個網格項之間有相等的空間,而第一個網格項和最後一個網格項與容器的邊緣之間的空間是其他網格項間隔的兩倍 */
      justify-content: space-around;
      /* 網格項在主軸上均勻分佈,並且第一個網格項在容器的起始位置,最後一個網格項在容器的末尾位置 */
      justify-content: space-between;
      /* 網格項在主軸上均勻分佈,並且網格項之間的空間相等 */
      justify-content: space-evenly;
    }
    
  4. align-content
    用於垂直對齊容器內的整個網格,和flex的align-items一樣

    .con{
      display: grid;
      /* 注意!!!!1fr為單位的無法生效 */
      height: 800px;
      grid-template-colums: 20%;
      grid-template-rows: 10px 20px 30px;
      /* 網格行在交叉軸的起始位置對齊 */
      align-content: start;
      /* 網格行在交叉軸的末尾位置對齊 */
      align-content: end;
      /* 網格行在交叉軸上居中對齊 */
      align-content: center;
      /* 網格行在交叉軸上均勻分佈,並且第一行在容器的起始位置,最後一行在容器的末尾位置 */
      algin-content: space-between;
      /* 網格行在交叉軸上均勻分佈,並且兩個網格行之間有相等的空間,而第一行和最後一行與容器的邊緣之間的空間是其他網格行間隔的兩倍 */
      align-content: space-around;
      /* 網格行在交叉軸上均勻分佈,並且網格行之間的空間相等 */
      align-content: space-evenly;
      /* 預設值,網格行會沿交叉軸拉伸以填充整個網格容器的高度 */
      align-content: stretch;
    }
    
  5. grid-column-gap
    設定列之間的間隙

    .con{
      display: grid;
      grid-template-columns: 1fr 1fr 1fr;
      grid-column-gap: 20px;
    }
    
  6. grid-row-gap
    設定行之間的間隙

    .con{
      display: grid;
      grid-template-column: 1fr 1fr 1fr;
      grid-template-rows: 1fr 1fr 1fr;
      grid-row-gap: 20px;
    }
    
  7. grid-gap
    設定行列的間隙 grid-row-gap grid-column-gap的縮寫,注意順序

    .con{
      display: grid;
      grid-template-column: 1fr 1fr 1fr;
      grid-template-rows: 1fr 1fr 1fr;
      /* 行列都是20px的間隙 */
      grid-gap: 20px;
      /* 行為20px的間隙,列為30px的間隙 */
      grid-gap: 20px 30px;
    }
    
  8. grid-template-areas
    高階技巧
    以可讀性強的方式指定網格項的位置。你可以通過使用字串來為每個網格區域命名,並使用這些命名來描述整個佈局。這個屬性只能在網格容器上使用
    使用 grid-template-areas,你可以為每個網格項指定一個名稱,並使用這些名稱來建立一個網格佈局模板。每個字串表示一個網格行,在字串中使用空格或點號 (.) 來表示每個網格單元格的位置

    .item1 { grid-area: header; }
    .item2 { grid-area: menu; }
    .item3 { grid-area: main; }
    .item4 { grid-area: right; }
    .item5 { grid-area: footer; }
    
    .grid-container {
      display: grid;
      grid-template-columns: repeat(6, 1fr);
      grid-template-areas:
        'header header header header header header'
        'menu main main main right right'
        'menu footer footer footer footer footer';
      grid-gap: 10px;
      background-color: #2196F3;
      padding: 10px;
    }
    
    .grid-container > div {
      background-color: rgba(255, 255, 255, 0.8);
      text-align: center;
      padding: 20px 0;
      font-size: 30px;
    }
    

注意點:

  1. 網格項不能跨越命名區域:在一個命名區域中,不能將同一個網格項跨越多個網格單元格。如果需要建立跨越多個網格單元格的網格項,可以考慮使用 grid-row-start、grid-column-start、grid-row-end 和 grid-column-end 或 grid-area 來指定跨越的行和列的範圍
  2. 網格項名稱和網格模板的定義應保持一致:在網格模板中指定的網格項名稱必須與你在網格容器中的子元素選擇器中使用的名稱一致。否則,佈局模板將無法正確應用到網格項上
  3. 使用相同數量的格子來定義每一行:在網格模板中,每行的格子數量應該一致。否則,會導致網格項在佈局中無法正確對應,造成不符合預期的佈局結果
  4. 排列順序和大小要一致:在網格模板中,不同的網格項名稱代表不同的區域。確保網格項名稱在模板中的排列順序和大小與實際佈局中的要求一致。這樣可以確保網格項被正確地分配到相應的區域
  5. 使用點號佔位:如果有某個區域不需要被任何網格項佔據,可以使用點號 (.) 來佔位。這有助於確保網格模板佈局的正確性()
專案屬性

專案屬性,就是作用於專案上的屬性
所有的線(行/列)都是從1開始算

  1. grid-column-start/grid-column-end
    在一列上,從左到右,從start開始到end結束,類似於截斷
    它接受一個整數值或一個命名格線(line name)作為引數
    eg: 當網格項的起始列位置大於網格容器的列數時,網格項將自動跨越多個列

    .con{
      display: grid;
      grid-template-columns: 1fr 1fr 1fr 1fr;
    }
    .item>div{
      padding: 10px;
      border: 1px solid;
    }
    .item:first-child{
      /* 這代表在一列中,從第一個開始到第三個作為這個元素的容器大小 */
      grid-columns-start: 1;
      grid-columns-end: 3;
    }
    .item:first-child{
      /* 這代表在一列中,若沒有start,end為3代表從 ??? */
       /* 捉摸不透 */
      grid-columns-end: 3;
    }
    .item:first-child{
      /*這代表在一列中,當網格項的起始列位置大於網格容器的列數時,網格項將自動跨越多個列???  */
      /* 捉摸不透 */
      grid-columns-start: 4;
      grid-columns-end: 3;
    }
    .item:first-child{
      /* 在這一列中,代表從第二列之前的給隔出來,不合並,給空出來,可以看例子可知 */
      /* 當列數大於網格列樹時,最後一個會縮小 */
      grid-columns-start: 2;
    }
    .item:nth-child(2){
      /* 這個代表從第二列開始計算 */
      grid-column-start: 1;
      grid-column-end: 3;
    }
    .item:nth-child(2){
      /* 也是從第二列開始,因為在第一列擷取的寬度不夠,從第二列開始 */
      grid-column-start: 1;
      grid-column-end: 4;
    }
    

eg: 無效設定,最好不要這麼弄,我也沒搞清楚怎麼回事,後續再補充
2. grid-column
定義將專案放置在哪一列上。您可以定義專案的開始位置以及結束位置.
grid-column 屬性是 grid-column-start 和 grid-column-end 屬性的簡寫屬性

  .con{
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
  }
  .item>div{
    padding: 10px;
    border: 1px solid;
  }
  .item:first-child{
    /* 這代表在一列中,從第一個線開始到第三個線作為這個元素的容器大小 */
    grid-columns: 1 / 3;
  }
  .item:first-child{
    /* 這代表在一列中,從第一個開始,橫跨三列,就到第四個線的容器 */
    grid-columns: 1 / span 3;
  }
  1. grid-row-start/grid-row-end
    在一行上,從上到下,從start開始到end結束
  .con{
    display: grid;
    grid-template-row: 1fr 1fr 1fr 1fr;
  }
  .item>div{
    padding: 10px;
    border: 1px solid;
  }
  .item:first-child{
    /* 這代表在一列中,從第一個線開始到第三個線作為這個元素的容器大小 */
    grid-rows-start: 1;
    grid-rows-end: 3
  }
  1. grid-row
    定義了將專案放置在哪一行
    grid-row 屬性是 grid-row-start 和 grid-row-end 屬性的簡寫屬性。
    如需放置專案,您可以參照行號,或使用關鍵字 「span」 定義該專案將跨越多少行

    .con{
      display: grid;
      grid-template-rows: 1fr 1fr 1fr 1fr;
    }
    .item>div{
      padding: 10px;
      border: 1px solid;
    }
    .item:first-child{
      /* 這代表在一行中,從第一個線開始到第三個線作為這個元素的容器大小 */
      grid-rows: 1 / 3;
    }
    .item:first-child{
      /* 這代表在一行中,從第一個開始,橫跨三行,就到第四個線的容器 */
      grid-rows: 1 / span 3;
    }
    
  2. grid-area
    grid-area 屬性可以用作 grid-row-start、grid-column-start、grid-row-end 和 grid-column-end 屬性的簡寫屬性

    .item:nth-child(3){
      /* 從第一行線,第二列線開始 到 第三行線,第四列線結束 */
      grid-area: 1 / 2 / 3 / 4
    }
    .item:nth-child(3){
      /* 從第2行線,第二列線開始 到 橫化三行線,第四列線結束 */
      grid-area: 2 / 2 / span 3 / 4
    }
    

總結

網格佈局功能較多,想要完全理解必須得實踐才能明白其原理,這次筆記整理不是很全,有些部分很懵懂,需要下去再進去做demo進行練習
本文若有什麼不對的地方,歡迎大家提出來,一起進步,我把例子和檔案放到了GitHub上,歡迎查閱。

參考資料

https://www.w3school.com.cn/css/css_grid.asp