ข้ามไปเนื้อหาหลัก

Category: guide

CSS Grid Advanced — Subgrid, Template Areas, Named Lines

เทคนิค Grid ระดับสูง: subgrid, named grid areas, auto-placement algorithm, และ grid ซ้อน grid

· อ่านประมาณ 4 นาที

สารบัญ

ทบทวนพื้นฐานก่อน

Grid container สร้างด้วย display: grid ส่วน children จะกลายเป็น grid items อัตโนมัติ — ไม่ต้องทำอะไรเพิ่ม

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}

Named Grid Lines

แทนที่จะนับ line number ตั้งชื่อได้:

.grid {
  display: grid;
  grid-template-columns:
    [sidebar-start] 240px
    [sidebar-end content-start] 1fr
    [content-end];
}

.sidebar { grid-column: sidebar-start / sidebar-end; }
.content  { grid-column: content-start / content-end; }

ชื่อ *-start / *-end ช่วย grid-area อ่านง่าย และ resize ง่ายกว่าการนับ column number


Grid Template Areas

.layout {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header"
    "sidebar content"
    "footer  footer";
  min-height: 100svh;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer  { grid-area: footer; }

ข้อดี: เปลี่ยน layout responsive แค่เปลี่ยน grid-template-areas:

@media (max-width: 640px) {
  .layout {
    grid-template-columns: 1fr;
    grid-template-areas:
      "header"
      "content"
      "sidebar"
      "footer";
  }
}

Subgrid

ปัญหาเก่า: ถ้า children มี grid ของตัวเอง column alignment จะไม่ตรงกับ parent

/* ❌ ก่อน subgrid */
.card { display: grid; grid-template-rows: auto 1fr auto; }
/* แต่ละ card มี row height ต่างกัน — alignment พัง */

Subgrid แก้ปัญหานี้:

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
}

.card {
  display: grid;
  grid-row: span 3;
  grid-template-rows: subgrid; /* ใช้ row tracks ของ parent */
}

.card-title   { /* ใช้ row 1 ของ parent */ }
.card-body    { /* ใช้ row 2 — stretch เท่ากันทุก card */ }
.card-footer  { /* ใช้ row 3 — อยู่บรรทัดเดียวกันทุก card */ }

Browser support: Chrome 117+, Firefox 71+, Safari 16+ — ใช้ได้แล้วในปี 2024+


Auto-placement Algorithm

Grid วาง items โดยอัตโนมัติตาม grid-auto-flow:

/* default: row — เติมแนวนอน */
.grid { grid-auto-flow: row; }

/* column — เติมแนวตั้ง */
.grid { grid-auto-flow: column; }

/* dense — เติมช่องว่างด้วย items ที่เล็กกว่า */
.grid { grid-auto-flow: row dense; }

dense มีประโยชน์กับ gallery ที่ items มี span ต่างกัน:

.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-auto-flow: row dense;
  gap: 1rem;
}

.featured { grid-column: span 2; grid-row: span 2; }

auto-fill vs auto-fit

/* auto-fill: สร้าง track แม้ไม่มี item */
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));

/* auto-fit: ยุบ track ที่ว่าง ทำให้ items stretch เต็ม container */
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  • auto-fill → items อยู่ตำแหน่งเดิม ถ้าน้อยกว่า column จะมีช่องว่าง
  • auto-fit → items stretch เต็ม แนะนำสำหรับ card grid ทั่วไป

Grid ซ้อน Grid

.outer {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 1.5rem;
}

.inner {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.75rem;
  /* inner grid ไม่เกี่ยวกับ outer grid เลย — independent */
}

ใช้ subgrid ถ้าต้องการ alignment ข้าม nesting level:

.inner {
  display: grid;
  grid-column: 1 / -1; /* span ทุก column ของ parent */
  grid-template-columns: subgrid;
}

Implicit vs Explicit Grid

  • Explicit grid = tracks ที่กำหนดด้วย grid-template-columns/rows
  • Implicit grid = tracks ที่ browser สร้างอัตโนมัติเมื่อ items เกิน

ควบคุม implicit tracks ด้วย:

.grid {
  grid-template-columns: repeat(3, 1fr); /* explicit: 3 columns */
  grid-auto-rows: minmax(120px, auto);   /* implicit rows: ขั้นต่ำ 120px */
}

Alignment ใน Grid

.grid {
  /* ทั้ง grid */
  justify-content: center;  /* แนวนอน: ทั้ง grid ใน container */
  align-content: start;     /* แนวตั้ง: ทั้ง grid ใน container */

  /* แต่ละ cell */
  justify-items: stretch;   /* items ใน cell แนวนอน */
  align-items: center;      /* items ใน cell แนวตั้ง */
}

.item {
  /* override สำหรับ item เดียว */
  justify-self: end;
  align-self: start;
}

Pattern: Holy Grail Layout

.page {
  display: grid;
  grid-template:
    "header" auto
    "main"   1fr
    "footer" auto
    / 1fr;
  min-height: 100dvh;
}

@media (min-width: 900px) {
  .page {
    grid-template:
      "header  header  header"  auto
      "nav     main    aside"   1fr
      "footer  footer  footer"  auto
      / 200px  1fr     200px;
  }
}

Pattern: Masonry (CSS-native, experimental)

Chrome 125+ รองรับ masonry layout ผ่าน Grid:

.masonry {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: masonry; /* experimental */
  gap: 1rem;
}

ยังต้องใช้ @supports จนกว่า browser support จะครบ


Debugging Grid

Chrome/Firefox DevTools มี grid overlay:

  • คลิก grid badge ข้างๆ element ใน Elements panel
  • เปิด line numbers, area names, track sizes overlay
  • ใช้ “Computed” tab ดู final grid track values
/* ช่วย visualize ตอน debug */
.grid * { outline: 1px dashed rgba(0, 128, 255, 0.3); }