CSS
Grid
grid-template-columns / rows
เรียนรู้วิธีกำหนดจำนวนและขนาดของคอลัมน์ใน CSS Grid ด้วย grid-template-columns พร้อมทำความเข้าใจหน่วย fr และ repeat() ที่ทำให้การสร้าง layout เป็นช่อง ๆ ง่ายและยืดหยุ่น
หัวข้อนี้คืออะไร
ในบทที่แล้วเราเรียนว่า display: grid สร้าง grid context ให้ parent แต่ items ยังเรียงเป็นคอลัมน์เดียวอยู่ grid-template-columns คือ property ที่บอก browser ว่า "กริดนี้มีกี่คอลัมน์ และแต่ละคอลัมน์กว้างแค่ไหน" เมื่อคุณกำหนด grid-template-columns browser จะแบ่งพื้นที่ออกเป็นช่องคอลัมน์ตามที่ระบุ และ grid items จะถูกวางเรียงลงในช่องเหล่านั้นจากซ้ายไปขวา แถวต่อแถว โดยอัตโนมัติ สิ่งสำคัญที่ต้องจำ: - grid-template-columns กำหนดที่ parent (Grid Container) - ค่าที่ระบุแต่ละตัวคือขนาดของคอลัมน์หนึ่งช่อง - จำนวนค่าที่ระบุ = จำนวนคอลัมน์ - ใช้ร่วมกับ display: grid เสมอ
- grid-template-columns กำหนดจำนวนและขนาดของคอลัมน์ในกริด
- จำนวนค่าที่ระบุ = จำนวนคอลัมน์ เช่น 3 ค่า = 3 คอลัมน์
- หน่วยพื้นฐานที่ใช้ได้: px, %, fr, auto
- หน่วย fr คือการแบ่งพื้นที่ที่เหลือตามสัดส่วน
- repeat() ช่วยย่อโค้ดเมื่อคอลัมน์มีขนาดซ้ำกัน
ทำไมหัวข้อนี้จึงสำคัญ
display: grid เป็นเพียงการ "เปิดโหมด" — แต่ grid-template-columns คือสิ่งที่ทำให้กริดมีรูปร่างจริง หากไม่กำหนด grid-template-columns items จะเรียงเป็นคอลัมน์เดียวซ้อนกัน ซึ่งไม่ต่างจาก block layout ทั่วไป เมื่อกำหนด grid-template-columns คุณจะได้ layout ที่ต้องการได้ทันที:
- สร้างกริด 2 คอลัมน์เท่ากัน — เหมาะกับ card row, comparison layout
- สร้างกริด 3 คอลัมน์เท่ากัน — เหมาะกับ photo gallery, product grid
- สร้างกริด sidebar + main — คอลัมน์ fixed + คอลัมน์ยืดหยุ่น
- สร้างกริด 4 หรือ 5 คอลัมน์ด้วย repeat() — เหมาะกับ e-commerce catalog
- เป็นพื้นฐานก่อนเรียน gap, grid-area และ responsive grid
ตัวอย่างจากชีวิตจริง
ลองนึกถึงการออกแบบชั้นวางหนังสือ ก่อนวางหนังสือ คุณต้องตัดสินใจก่อนว่า "ชั้นนี้จะแบ่งเป็นกี่ช่อง และแต่ละช่องกว้างเท่าไร" ถ้าต้องการ 3 ช่องเท่ากัน — แบ่งความกว้างออกเป็นสามส่วนเท่า ๆ กัน ถ้าต้องการช่องซ้ายแคบสำหรับป้ายชื่อ และช่องขวาใหญ่สำหรับหนังสือ — ช่องซ้าย 80px ช่องขวาใช้พื้นที่ที่เหลือทั้งหมด นั่นคือสิ่งที่ grid-template-columns ทำ คุณกำหนดโครงช่องก่อน แล้ว grid items จะถูกวางลงในช่องเหล่านั้นตามลำดับ หน่วย fr (fraction) คือการบอกว่า "ให้ช่องนี้ได้ส่วนแบ่งของพื้นที่ที่เหลือ" เหมือนบอกว่า "แบ่งที่ว่างที่เหลือออกเป็นสองส่วนเท่ากัน" แทนที่จะระบุ pixel ตายตัว
แนวคิดหลักที่ต้องเข้าใจ
มีสามเรื่องหลักที่ต้องรู้: ① จำนวนค่า = จำนวนคอลัมน์ grid-template-columns: 100px 200px 100px; → 3 คอลัมน์ ค่าแรกคือขนาดคอลัมน์ที่ 1, ค่าที่สองคือคอลัมน์ที่ 2, ค่าที่สามคือคอลัมน์ที่ 3 ② หน่วย fr (fraction unit) fr คือหน่วยพิเศษของ CSS Grid ที่หมายถึง "ส่วนแบ่งของพื้นที่ว่างที่เหลือ" ตัวอย่าง: grid-template-columns: 1fr 1fr; — browser แบ่งพื้นที่ที่เหลือออกเป็น 2 ส่วนเท่ากัน ตัวอย่าง: grid-template-columns: 1fr 2fr; — browser แบ่งพื้นที่ออกเป็น 3 ส่วน คอลัมน์แรกได้ 1 ส่วน คอลัมน์สองได้ 2 ส่วน ตัวอย่าง: grid-template-columns: 200px 1fr; — คอลัมน์แรก 200px คงที่ คอลัมน์สองได้พื้นที่ที่เหลือทั้งหมด ③ repeat() เมื่อหลายคอลัมน์มีขนาดเท่ากัน ใช้ repeat() เพื่อย่อโค้ด repeat(3, 1fr) = 1fr 1fr 1fr repeat(4, 150px) = 150px 150px 150px 150px
grid-template-columns กำหนดจำนวนและขนาดคอลัมน์ | fr = ส่วนแบ่งพื้นที่ที่เหลือ | repeat() = ย่อค่าซ้ำ
การทำงานทีละขั้นตอน
นี่คือขั้นตอนการสร้างกริดที่มีคอลัมน์ชัดเจน:
- 1. กำหนด display: grid ที่ parent ก่อนเสมอ — ไม่มีขั้นตอนนี้ grid-template-columns จะไม่มีผล
- 2. นับว่าต้องการกี่คอลัมน์ — เช่น ต้องการ 3 คอลัมน์ก็ต้องระบุค่า 3 ตัว
- 3. ตัดสินใจว่าแต่ละคอลัมน์ใช้หน่วยอะไร — px สำหรับขนาดตายตัว, fr สำหรับขนาดยืดหยุ่น
- 4. เขียน grid-template-columns ที่ parent — เช่น grid-template-columns: 1fr 1fr 1fr;
- 5. browser จัดวาง grid items ลงในช่องคอลัมน์อัตโนมัติ — ไม่ต้องแตะ CSS ของ child เลย
ตัวอย่างเชิงเทคนิค — รูปแบบคอลัมน์ที่ใช้บ่อย
ตัวอย่างด้านล่างแสดง 4 รูปแบบคอลัมน์ที่พบบ่อยที่สุด ลองแก้ค่าใน .grid-a, .grid-b, .grid-c, .grid-d แล้วสังเกตความเปลี่ยนแปลง
จุดที่ผู้เริ่มต้นมักสับสน
ตรวจสอบว่าคุณเข้าใจถูกต้องหรือยัง:
- ❌ ลืมใส่ display: grid ก่อน — grid-template-columns จะไม่มีผลเลยถ้าไม่มี display: grid ที่ parent เดียวกัน ต้องมีทั้งคู่
- ❌ คิดว่า fr คือ percent — fr ไม่ใช่ % fr คือส่วนแบ่งของ พื้นที่ที่เหลือ ไม่ใช่ % ของความกว้างทั้งหมด เช่น ถ้ามี padding หรือ gap fr จะคำนวณจากพื้นที่หลังหักสิ่งเหล่านั้นออก
- ❌ ใส่ค่าไม่ครบจำนวนคอลัมน์ที่ต้องการ — ถ้าต้องการ 3 คอลัมน์ต้องระบุค่า 3 ตัว เช่น 1fr 1fr 1fr ไม่ใช่แค่ 1fr
- ❌ สับสน repeat(3, 1fr) กับ repeat(1fr, 3) — syntax ที่ถูกคือ repeat(จำนวน, ขนาด) ไม่ใช่สลับกัน repeat(3, 1fr) = 3 คอลัมน์ขนาด 1fr แต่ละคอลัมน์
- ❌ กำหนด grid-template-columns ที่ child แทน parent — property นี้ต้องกำหนดที่ Grid Container (parent) ไม่ใช่ที่ Grid Item (child)
เปรียบเทียบหน่วยที่ใช้ใน grid-template-columns
แต่ละหน่วยมีพฤติกรรมต่างกัน — เลือกให้ถูกกับงาน:
| หน่วย | ความหมาย | ยืดหยุ่น? | เหมาะกับ |
|---|---|---|---|
| px | ขนาดตายตัวในหน่วย pixel | ไม่ยืดหยุ่น | sidebar, icon column, ขนาดคงที่ |
| fr | ส่วนแบ่งของพื้นที่ว่างที่เหลือ | ยืดหยุ่น | คอลัมน์หลัก, layout ที่ต้องการเต็มความกว้าง |
| % | เปอร์เซ็นต์ของความกว้าง parent | ยืดหยุ่น | ใช้ได้แต่ fr มักดีกว่าใน grid |
| auto | ขนาดพอดีกับเนื้อหา | ยืดหยุ่นตามเนื้อหา | คอลัมน์ที่ต้องการขนาดพอดีกับ content |
| repeat(n, size) | ย่อการเขียนค่าซ้ำ n ครั้ง | ขึ้นอยู่กับ size ที่ใช้ | กริดที่มีคอลัมน์ขนาดเท่ากันหลายคอลัมน์ |
สรุปท้ายบท
จำง่าย ๆ แบบนี้: "grid-template-columns = กำหนดจำนวนและขนาดคอลัมน์ ที่ parent"
- grid-template-columns กำหนดที่ Grid Container ร่วมกับ display: grid เสมอ
- จำนวนค่าที่ระบุ = จำนวนคอลัมน์ เช่น 1fr 1fr = 2 คอลัมน์
- fr = ส่วนแบ่งของพื้นที่ที่เหลือ — ยืดหยุ่นและใช้บ่อยที่สุด
- 1fr 1fr = 2 คอลัมน์เท่ากัน | 1fr 2fr = คอลัมน์ซ้ายแคบกว่าสองเท่า
- 200px 1fr = sidebar คงที่ 200px + main ยืดเต็มพื้นที่ที่เหลือ
- repeat(3, 1fr) = เขียนย่อแทน 1fr 1fr 1fr
Lab 1: สร้างกริด 2 คอลัมน์เท่ากัน
ชื่อ Lab: สร้าง Card Grid 2 คอลัมน์ เป้าหมาย: กำหนด display: grid และ grid-template-columns: 1fr 1fr ที่ .card-grid เพื่อให้ card 4 ใบเรียงเป็น 2 คอลัมน์เท่ากัน โจทย์: ตอนนี้ .card-grid มี card อยู่ 4 ใบแต่ยังซ้อนกันเป็นคอลัมน์เดียว เพิ่ม display: grid และ grid-template-columns: 1fr 1fr ให้ .card-grid เงื่อนไข: - ต้องกำหนด display: grid ที่ .card-grid - ต้องกำหนด grid-template-columns: 1fr 1fr ที่ .card-grid - ห้ามแตะ CSS ของ .card ระบบจะตรวจ: 1. .card-grid มี display: grid ใน CSS 2. .card-grid มี grid-template-columns ที่มีค่า 1fr ใน CSS 3. computed display ของ .card-grid = grid 4. card ทุกใบเรียงเป็น 2 คอลัมน์ (คอลัมน์ที่ 1 และ 2 อยู่แถวเดียวกัน) แนวทางการคิด: กำหนดที่ parent เสมอ ต้องมีทั้ง display: grid และ grid-template-columns ในกฎ CSS เดียวกัน
Lab 2: สร้างกริด sidebar + main
ชื่อ Lab: Layout แบบ Sidebar + Main Content เป้าหมาย: ใช้ grid-template-columns: 220px 1fr เพื่อสร้าง layout 2 คอลัมน์ที่ไม่เท่ากัน โจทย์: .page-layout มี .sidebar และ .main-content อยู่ภายใน ตอนนี้ทั้งสองซ้อนกัน ให้กำหนด grid เพื่อให้ sidebar อยู่ซ้ายกว้าง 220px และ main content ใช้พื้นที่ที่เหลือ เงื่อนไข: - ต้องกำหนด display: grid ที่ .page-layout - ต้องกำหนด grid-template-columns: 220px 1fr ที่ .page-layout - ห้ามแก้ CSS ของ .sidebar หรือ .main-content ระบบจะตรวจ: 1. .page-layout มี display: grid 2. .page-layout มี grid-template-columns ที่มีค่า 220px 3. .sidebar และ .main-content อยู่แถวเดียวกัน 4. .sidebar กว้างประมาณ 220px แนวทางการคิด: ใช้ px สำหรับ sidebar ที่ต้องการขนาดตายตัว และ fr สำหรับ main content ที่ต้องการยืดเต็มพื้นที่ที่เหลือ
Lab 3: ใช้ repeat() สร้างกริด 3 คอลัมน์
ชื่อ Lab: Photo Gallery ด้วย repeat() เป้าหมาย: ใช้ repeat(3, 1fr) ใน grid-template-columns เพื่อสร้าง gallery 3 คอลัมน์ที่เท่ากัน โจทย์: .photo-gallery มีรูปภาพ 6 ช่อง กำหนด display: grid และ grid-template-columns ด้วย repeat(3, 1fr) เพื่อให้ได้ layout 3 คอลัมน์เท่ากัน เงื่อนไข: - ต้องกำหนด display: grid ที่ .photo-gallery - ต้องใช้ repeat() ใน grid-template-columns ของ .photo-gallery - ผลลัพธ์ต้องได้ 3 คอลัมน์ (รูปที่ 1, 2, 3 อยู่แถวเดียวกัน) ระบบจะตรวจ: 1. .photo-gallery มี display: grid 2. source code มีคำว่า repeat ใน CSS 3. รูปที่ 1, 2, 3 อยู่แถวเดียวกัน 4. .photo ทั้ง 6 ช่องอยู่ใน .photo-gallery แนวทางการคิด: repeat(3, 1fr) เหมือนกับเขียน 1fr 1fr 1fr แต่กระชับกว่า