CSS
Advanced & Best Practices
CSS variables (--var)
CSS variables หรือ custom properties ใช้เก็บค่าที่ต้องการนำกลับมาใช้ซ้ำ เช่น สี spacing หรือ radius — ทำให้โค้ดดูแลง่ายขึ้น เปลี่ยนแปลงได้จากจุดเดียว และรองรับการทำ theme
หัวข้อนี้คืออะไร
CSS variables หรือชื่อทางการว่า "custom properties" คือตัวแปรใน CSS ที่คุณประกาศเองและนำกลับมาใช้ได้ทั่วทั้ง stylesheet syntax มี 2 ส่วน: - ประกาศค่า: --ชื่อ: ค่า; - ใช้งานค่า: var(--ชื่อ)
ประกาศใน :root เพื่อให้ใช้ได้ทั่วหน้า — เรียกใช้ด้วย var(--ชื่อ) ในทุก property ที่ต้องการ
/* ประกาศ CSS variable */
:root {
--color-primary: #3b82f6;
--spacing-md: 16px;
--radius-card: 12px;
}
/* นำไปใช้งาน */
.button {
background: var(--color-primary);
padding: var(--spacing-md);
border-radius: var(--radius-card);
}ทำไมหัวข้อนี้สำคัญ
ลองนึกภาพ project ที่ใช้สีน้ำเงิน #3b82f6 ซ้ำ 50 จุดทั่วไฟล์ CSS วันนึงต้องเปลี่ยนเป็นสีอื่น — ต้องไล่แก้ 50 จุด CSS variables แก้ปัญหานี้: แก้จุดเดียว ทั่วหน้าเปลี่ยนตาม — เปลี่ยนที่ :root จุดเดียว ทุกที่ที่ใช้ var(--color-primary) อัปเดตอัตโนมัติ ความสม่ำเสมอ — ทุก component ใช้ค่าเดียวกันจาก variable ไม่มีสีเพี้ยนเล็กน้อยหรือ spacing ต่างกันนิดหน่อย ทำ theme ได้ — เปลี่ยนชุดค่าใน :root เพื่อเปลี่ยน light/dark mode หรือ brand theme ทั้งหน้าได้เลย อ่านโค้ดง่ายขึ้น — var(--color-danger) เข้าใจได้ทันที vs #ef4444 ที่ต้องเดาว่าคือสีอะไร
ตัวอย่างจากชีวิตจริง
ลองนึกถึงระบบ design system ของบริษัทใหญ่: Google Material Design — กำหนด --md-sys-color-primary ไว้ที่เดียว ทุก component ใช้ variable เดียวกัน เปลี่ยน brand color ทำได้ในไฟล์เดียว Tailwind CSS — ใช้ CSS variables เป็นพื้นฐานตั้งแต่ v4 เช่น --color-blue-500 เพื่อให้ปรับ theme ได้ง่าย GitHub — ใช้ --color-accent-fg, --color-canvas-default ฯลฯ เพื่อรองรับ light/dark mode โดยแค่ swap ค่าของ variables แม้แต่ project เล็กๆ ก็ได้ประโยชน์ — เก็บ color, spacing, font-size ไว้ที่เดียว แก้ไขทีเดียว ทั้งไฟล์เปลี่ยนตาม
แนวคิดหลักที่ต้องเข้าใจ
CSS variables ทำงาน 3 เรื่องที่ต้องเข้าใจ: 1. Scope — ประกาศที่ไหน ใช้ได้ในขอบเขตนั้นและลูกหลาน (:root คือ global) 2. Cascade & Override — scope ย่อยสามารถ override ค่าจาก parent ได้ 3. Fallback — var(--name, ค่าสำรอง) ใช้ค่าสำรองถ้า variable ไม่มี ลองปรับค่าใน :root ด้านล่าง — สังเกตว่าทุก component เปลี่ยนพร้อมกัน:
| แนวคิด | ตัวอย่าง | ผล |
|---|---|---|
| ประกาศ global ใน :root | --color-primary: #3b82f6 | ใช้ได้ทุกที่ในหน้า |
| ใช้งานด้วย var() | background: var(--color-primary) | ดึงค่าจาก variable มาใช้ |
| Override ใน scope ย่อย | .dark { --color-primary: #93c5fd } | เฉพาะใน .dark ค่าจะต่างออกไป |
| Fallback value | var(--color-accent, #f59e0b) | ถ้าไม่มี variable ใช้ #f59e0b แทน |
การทำงานทีละขั้นตอน
วิธีใช้ CSS variables ใน project จริง:
- 1. ระบุค่าที่ใช้ซ้ำบ่อย — มองหา สี, spacing, radius, font-size ที่ปรากฏหลายครั้งในไฟล์ CSS
- 2. ตั้งชื่อให้สื่อความหมาย — ใช้รูปแบบ --หมวดหมู่-ชื่อ เช่น --color-primary, --spacing-md, --radius-card
- 3. ประกาศใน :root — ทำให้ใช้ได้ทั่วทั้งหน้า หรือประกาศใน selector ถ้าต้องการ scope เฉพาะ
- 4. แทนที่ค่า hard-coded ด้วย var() — เปลี่ยน background: #3b82f6 เป็น background: var(--color-primary)
- 5. Override ใน component ที่ต้องการ — ถ้า .card-dark ต้องการสีต่าง ก็ประกาศ --color-primary ซ้ำใน .card-dark
ตัวอย่างที่ 1 — Color tokens ใน :root
วิธีกำหนด color system ทั้งหน้าด้วย CSS variables — เปลี่ยนแค่ที่ :root ทั้งหน้าตาม:
ตัวอย่างที่ 2 — Override ค่าใน scope ย่อย
scope ย่อยสามารถ override CSS variable ได้โดยไม่กระทบ global — ทำให้ component เดียวกันมีหน้าตาต่างกันตาม context:
ตัวอย่างที่ 3 — Fallback value
var() รับ argument ที่สอง เป็น fallback ถ้า variable ไม่ถูกประกาศหรือ invalid:
fallback ไม่ได้แปลว่าโค้ดผิด — ใช้เป็น default ให้ component ทำงานได้แม้ไม่มีการกำหนด variable
/* Fallback พื้นฐาน */
.button {
/* ถ้า --btn-color ไม่มี → ใช้ #3b82f6 แทน */
background: var(--btn-color, #3b82f6);
}
/* Fallback chain — fallback ซ้อน fallback */
.text {
/* ลองใช้ --color-brand ก่อน ถ้าไม่มีลอง --color-primary ถ้ายังไม่มีใช้ black */
color: var(--color-brand, var(--color-primary, black));
}
/* ใช้งานจริง — component ที่รองรับ theme แต่มี default */
.card {
background: var(--card-bg, white);
border-color: var(--card-border, #e2e8f0);
border-radius: var(--card-radius, 12px);
}
/* ถ้า .dark-theme กำหนดค่า ก็ใช้ค่านั้น */
.dark-theme {
--card-bg: #1e293b;
--card-border: #334155;
}จุดที่ผู้เริ่มต้นมักสับสน
- ชื่อต้องขึ้นต้นด้วย -- เสมอ — --color-primary ถูก, -color-primary หรือ color-primary ผิด CSS จะไม่รู้จัก
- var() ใช้ได้เฉพาะกับ value ไม่ใช่ property name — background: var(--color) ถูก แต่ var(--prop-name): red ผิดทั้งหมด
- CSS variables ไม่เหมือน Sass variables — CSS variables มีอยู่ใน browser จริง เปลี่ยนได้ด้วย JavaScript ตอน runtime, Sass variables แปลงเป็นค่าตายตัวตอน compile
- scope ทำงานผ่าน DOM ไม่ใช่ไฟล์ — ถ้าประกาศ --color ใน .parent ทุก element ลูกใน DOM จะใช้ค่านั้นได้ ไม่ใช่แค่ element ใน block CSS เดียวกัน
เปรียบเทียบ CSS Variables กับ Sass Variables
| CSS Variables (--var) | Sass Variables ($var) | |
|---|---|---|
| ทำงานตอน | Browser runtime — มีจริงใน DOM | Compile time — แปลงเป็น CSS ปกติ |
| เปลี่ยนด้วย JS ได้ | ได้ — el.style.setProperty() | ไม่ได้ — ถูกแปลงแล้ว |
| Scope | DOM-based — ตาม HTML structure | Block-based — ตาม SCSS file |
| Override ใน scope ย่อย | ได้ — เพียงประกาศซ้ำ | ไม่ได้ — ค่าตายตัวหลัง compile |
| ต้องการ preprocessor | ไม่ — CSS ล้วน | ต้องการ Sass compiler |
| Browser support | IE ไม่รองรับ, อื่นๆ ครบ | ขึ้นอยู่กับ output CSS |
สรุปท้ายบทแบบจำง่าย
CSS variables = ประกาศด้วย -- ใช้ด้วย var() สูตรจำ: :root { --ชื่อ: ค่า; } → property: var(--ชื่อ);
- ประกาศใน :root สำหรับค่ากลาง — เข้าถึงได้ทั่วทั้งหน้า
- Override ใน scope ย่อยได้เสมอ — ประกาศซ้ำใน selector นั้น ค่าใหม่มีผลเฉพาะใน scope
- ใช้ fallback เป็น default — var(--name, ค่าสำรอง) ป้องกัน component พังถ้า variable ไม่ถูกกำหนด
Lab 1 — ประกาศ CSS variables พื้นฐาน
โจทย์: ประกาศ CSS variables ใน :root ดังนี้: - --color-primary: #6366f1 - --spacing-base: 16px - --radius-base: 8px แล้วใช้งานใน .box: - background: var(--color-primary) - padding: var(--spacing-base) - border-radius: var(--radius-base)
Lab 2 — ใช้ var() กับหลาย property
โจทย์: ประกาศ variables ใน :root ให้ครบ แล้วแทนที่ค่า hard-coded ใน .card, .card-title, .card-tag ด้วย var() Variables ที่ต้องประกาศ: - --color-brand: #0ea5e9 - --color-brand-light: #e0f2fe - --spacing-card: 20px - --radius-card: 12px
Lab 3 — แก้โค้ด hard-coded ให้ใช้ variables
โจทย์: โค้ดด้านล่างใช้สีและค่าตายตัวซ้ำหลายจุด ทำให้ดูแลยาก แปลงให้ใช้ CSS variables: 1. ประกาศ --color-accent: #f59e0b และ --color-accent-dark: #d97706 ใน :root 2. แทนที่ #f59e0b และ #d97706 ทุกที่ด้วย var() ที่เหมาะสม