CSS
Advanced & Best Practices
Clean & Maintainable CSS
เรียนรู้การเขียน CSS ที่อ่านง่าย แก้ง่าย และทีมอื่นต่อได้ทันที — ตั้งชื่อชัด จัดโครงสร้างดี และลดค่าซ้ำด้วย variables
หัวข้อนี้คืออะไร
Clean & Maintainable CSS คือการเขียน CSS ที่ไม่ใช่แค่ "ทำงานได้" แต่ทีมอื่นหยิบต่อได้ทันที และตัวเองกลับมาอ่านอีกครึ่งปีต่อมาก็ยังเข้าใจ CSS ที่ดีมี 3 ลักษณะหลัก: - **อ่านง่าย** — ชื่อ class สื่อความหมาย, จัดกลุ่ม rule มีระเบียบ - **แก้ง่าย** — เปลี่ยนค่าจุดเดียวแล้วทุกที่อัปเดต (ด้วย custom properties) - **นำกลับมาใช้ซ้ำได้** — ไม่เขียนสิ่งเดิมซ้ำ 10 ครั้ง CSS ที่รกเรื้อมักมาจากการเพิ่ม rule เข้าไปเรื่อย ๆ โดยไม่มีโครงสร้าง จนท้ายที่สุดไม่มีใครกล้าลบ rule เก่าเพราะกลัวพัง
/* ❌ CSS ที่รก — อ่านยาก แก้ยาก */
.b1 { color: #3b82f6; padding: 8px 16px; border-radius: 4px; }
.s2 { font-size: 14px; color: #6b7280; margin-top: 8px; }
.red-box { background: #ef4444; color: white; padding: 8px; }
.fix99 { margin-top: -4px !important; }
/* ✅ CSS ที่สะอาด — ชัด จัดกลุ่ม มี variable */
/* Custom Properties */
:root {
--color-primary: #3b82f6;
--color-danger: #ef4444;
--color-muted: #6b7280;
--space-2: 0.5rem;
--space-4: 1rem;
--radius-sm: 4px;
}
/* Components */
.btn-primary {
color: var(--color-primary);
padding: var(--space-2) var(--space-4);
border-radius: var(--radius-sm);
}
.card__subtitle {
font-size: 0.875rem;
color: var(--color-muted);
margin-top: var(--space-2);
}
.alert-banner {
background: var(--color-danger);
color: white;
padding: var(--space-2);
}ทำไมหัวข้อนี้สำคัญ
CSS ที่รกเรื้อเพิ่ม technical debt ที่มองไม่เห็น — ทุกครั้งที่นักพัฒนาไม่กล้าลบ rule เก่า หรือต้องเพิ่ม !important เพื่อ override ที่ไม่เข้าใจ นั่นคือต้นทุนที่สะสมไปเรื่อย ๆ ปัญหาจริงที่เกิดขึ้นบ่อย: - **เขียน rule ซ้ำ** เพราะหาไม่เจอว่ามีอยู่แล้วตรงไหน - **แก้สีผิดที่** เพราะค่าสีฝังตรงกระจายใน 40 บรรทัด - **onboard ช้า** นักพัฒนาใหม่ไม่รู้ว่า class ชื่อแปลก ๆ ทำอะไร - **specificity สงคราม** เพิ่ม !important → ต้องเพิ่มอีก → วงจรไม่จบ การลงทุนเวลา 30 นาทีในการจัดโครงสร้าง CSS ตั้งแต่ต้นสามารถประหยัดชั่วโมงได้มากในระยะยาว
ตัวอย่างจากชีวิตจริง
โปรเจกต์จริงเกือบทุกแห่งเริ่มสะอาด แต่พอเดือนผ่านไป feature เพิ่มขึ้น นักพัฒนาหมุนเวียน CSS ก็เริ่มยุ่ง บริษัทใหญ่จึงแก้ปัญหานี้ด้วย CSS style guide: **Google** มีแนวทางเรื่องการตั้งชื่อและ indentation ที่ทีมต้องทำตาม **Airbnb** มี CSS style guide ที่บอกเรื่องลำดับ property, naming convention, และ comment format **Bootstrap** แยก utility, component, และ layout ออกจากกันชัดเจน ทำให้นักพัฒนาที่ไม่เคยเห็น codebase นี้มาก่อนก็หาที่ถูกต้องได้เร็ว สิ่งเหล่านี้ไม่ใช่ "กฎที่ต้องทำตาม 100%" แต่คือหลักการที่ทีมตกลงกันเพื่อให้ทำงานร่วมกันได้โดยไม่ขัดกัน
แนวคิดหลักที่ต้องเข้าใจ
Clean CSS ยืนอยู่บน 3 เสาหลักที่เสริมกัน: **1. ตั้งชื่อชัด** — ชื่อ class บอก "หน้าที่" ไม่ใช่ "หน้าตา" - ❌ .blue-btn, .big-text, .right-side - ✅ .btn-primary, .hero-title, .sidebar-nav **2. จัดโครงสร้างดี** — แบ่ง CSS เป็นกลุ่มตามหน้าที่ - Custom Properties → Base/Reset → Layout → Components → Utilities **3. ลดค่าซ้ำ** — ค่าที่ใช้บ่อยกลายเป็น variable - สี, spacing, border-radius, font-size ที่ซ้ำ → :root { --xxx: value } ดูตัวอย่างด้านล่าง — card เดียวกัน เขียน 2 แบบ:
| สัญญาณ CSS ไม่ Maintainable | วิธีแก้ |
|---|---|
| ชื่อ class เช่น .b1, .fix3, .style99 | ตั้งชื่อสื่อหน้าที่ .btn-primary, .card__title |
| ค่าสีและ spacing ฝังตรงซ้ำหลายที่ | ย้ายเข้า :root เป็น custom properties |
| rule กระจัดกระจาย ไม่มีกลุ่ม | แบ่งกลุ่มด้วย comment เช่น /* Components */ |
| ใช้ !important บ่อย | แก้ specificity ที่ต้นเหตุ ไม่ใช่ override ทับ |
| CSS ยาว 1,000+ บรรทัดไม่มี comment | เพิ่ม comment อธิบาย 'ทำไม' จุดที่ซับซ้อน |
การทำงานทีละขั้นตอน
- **ตรวจหา property ที่ซ้ำกัน** — ค้นหาสีและ spacing ที่ปรากฏหลายครั้งในไฟล์ เช่น #3b82f6 หรือ 1rem นั่นคือตัวแทน variable ที่รอเกิด
- **ย้ายค่าซ้ำเข้า :root** — สร้าง custom properties เช่น --color-primary: #3b82f6 แล้วแทนที่ทุกที่ด้วย var(--color-primary)
- **จัดกลุ่ม rule ด้วย comment** — แบ่ง CSS เป็นส่วน: Custom Properties → Base → Layout → Components → Utilities
- **ตั้งชื่อ class ใหม่ให้สื่อความหมาย** — เปลี่ยนชื่อที่ไม่สื่อ เช่น .b1 → .btn-primary, .card-t → .card__title ชื่อควรบอก 'หน้าที่' ไม่ใช่ 'หน้าตา'
- **เพิ่ม comment เฉพาะจุดที่ซับซ้อน** — ไม่ต้อง comment ทุก line แค่อธิบาย 'ทำไม' ในจุดที่คนอื่นอาจสงสัย
ตัวอย่างที่ 1 — จัดโครงสร้าง CSS ให้อ่านง่าย
CSS ที่ดีแบ่งเป็นกลุ่มชัดเจน ทำให้หาที่แก้ได้ทันที ไม่ต้องไล่ scroll หาทั้งไฟล์ ลำดับที่แนะนำ: Custom Properties → Base/Reset → Layout → Components → Utilities
ตัวอย่างที่ 2 — ใช้ Variables แทนค่าซ้ำ
เมื่อค่าเดิมปรากฏหลายครั้ง การเปลี่ยน theme หรือแก้ไขต้องไล่แก้ทุกจุด แต่ถ้าใช้ custom properties แก้จุดเดียวทุกที่เปลี่ยนพร้อมกัน ลองดูตัวอย่าง — ทุก element ข้างล่างใช้ var(--color-primary) จาก :root จุดเดียว:
ตัวอย่างที่ 3 — ตั้งชื่อ Class ให้สื่อความหมาย
ชื่อ class ที่ดีบอก "หน้าที่" ของ element ไม่ใช่ "หน้าตา" — เพราะหน้าตาเปลี่ยนได้ แต่หน้าที่มักคงที่ ตัวอย่างการ refactor ชื่อ class: - .red-box → .alert-banner (บอกว่าคือ alert ไม่ใช่แค่กล่องสีแดง) - .left-thing → .sidebar-nav (บอกว่าคือ navigation ในแถบซ้าย) - .style2 → .card--featured (บอกว่าเป็น card variant พิเศษ)
จุดที่ผู้เริ่มต้นมักสับสน
- **Comment ไม่ใช่ทุก line ต้องมี** — Comment ที่ดีอธิบาย 'ทำไม' ไม่ใช่ 'ทำอะไร' — /* z-index สูงเพราะต้องทะลุ modal */ มีประโยชน์, /* set color */ ไม่มีประโยชน์เพราะโค้ดพูดแทนตัวเองได้อยู่แล้ว
- **ชื่อ class สื่อ 'role' ไม่ใช่ 'appearance'** — .primary-btn ดีกว่า .blue-btn เพราะวันนึงอาจเปลี่ยนสีเป็นเขียว แต่ยังเป็น primary button อยู่ ถ้าชื่อบอก 'หน้าตา' พอแก้ design ชื่อก็โกหก
- **ไม่ต้องสมบูรณ์แบบตั้งแต่แรก** — การ refactor CSS ทำได้ทีละส่วน เริ่มจากไฟล์หรือ component ที่แตะบ่อยที่สุด แล้วค่อย ๆ ขยาย ไม่จำเป็นต้อง refactor ทั้งโปรเจกต์ในคราวเดียว
- **Variable ไม่ใช่ทุกค่าต้องเป็น variable** — ถ้าค่านั้นใช้แค่ครั้งเดียว ไม่จำเป็นต้องทำเป็น variable แต่ถ้าใช้ซ้ำ 3+ ที่ขึ้นไปควรพิจารณาย้ายเข้า :root ทันที
เปรียบเทียบ CSS ที่ดีกับ CSS ที่แย่
| หัวข้อ | CSS ที่แย่ | CSS ที่ดี |
|---|---|---|
| ชื่อ class | .b1, .fix99, .style2, .red-box | .btn-primary, .alert-banner, .card--featured |
| ค่าสี/spacing | #3b82f6 กระจาย 20 บรรทัด | var(--color-primary) จาก :root |
| การจัดกลุ่ม | rule ปะปนกัน ไม่มีระเบียบ | แบ่งกลุ่มด้วย comment ชัดเจน |
| Comment | ไม่มีเลย หรือ comment ทุก line | เฉพาะจุดที่ซับซ้อนและอธิบาย 'ทำไม' |
| ความซ้ำซ้อน | copy-paste rule เดิมหลายที่ | ใช้ utility class หรือ variable แทน |
สรุปท้ายบทแบบจำง่าย
CSS ที่ดีไม่ได้แปลว่าสั้นที่สุด — แต่แปลว่าคนอื่น (และตัวเองในอีก 6 เดือน) อ่านแล้วเข้าใจทันทีว่าโค้ดส่วนนี้ทำอะไรและทำไมถึงเขียนแบบนี้ 5 หลักการที่ควรจำ:
- **ตั้งชื่อสื่อหน้าที่ ไม่ใช่หน้าตา** — .nav-link ดีกว่า .white-text-small
- **ค่าซ้ำ 3+ ที่ → ย้ายเข้า :root** — สี, spacing, radius ที่ซ้ำควรเป็น custom property
- **จัดกลุ่มด้วย comment section** — Properties → Base → Layout → Components → Utilities
- **Comment อธิบาย 'ทำไม' ไม่ใช่ 'ทำอะไร'** — โค้ดพูดแทนตัวเองได้ แต่ context พูดเองไม่ได้
- **Refactor ทีละส่วน ไม่ต้องครั้งเดียวจบ** — เริ่มจาก component ที่แตะบ่อย แล้วขยายออกไปเรื่อย ๆ
Lab 1 — จัดโครง CSS ให้อ่านง่ายขึ้น
CSS ด้านล่างมี rule ระเกะระกะ ไม่มีกลุ่ม และชื่อ class ไม่สื่อความหมาย **งานของคุณ:** 1. เพิ่ม comment กลุ่ม /* Layout */ และ /* Components */ ใน CSS 2. จัดย้าย rule เข้าหมวดที่ถูกต้อง 3. เปลี่ยนชื่อ .b1 เป็น .btn แล้วอัปเดตใน HTML ด้วย
Lab 2 — เปลี่ยนค่าซ้ำให้เป็น Variables
CSS ด้านล่างมีสี #3b82f6 และ spacing 1rem ซ้ำกันหลายจุด **งานของคุณ:** 1. เพิ่ม :root พร้อม --color-primary: #3b82f6 และ --space-4: 1rem 2. แทนที่ค่าที่ซ้ำทุกจุดด้วย var(--color-primary) และ var(--space-4)
Lab 3 — รีแฟกเตอร์ Component CSS ให้สะอาดขึ้น
CSS ของ card component ด้านล่างมีปัญหา 3 อย่าง: - ชื่อ class ไม่สื่อ (.card-t, .card-b) - ค่า padding ซ้ำหลายจุด (ทั้งใน .card, .card-t, .card-b) - ไม่มีโครงสร้างชัดเจน **งานของคุณ:** 1. เปลี่ยนชื่อ .card-t เป็น .card__title และ .card-b เป็น .card__body (อัปเดต HTML ด้วย) 2. สร้าง --card-padding ใน :root แล้วใช้แทนค่า padding ที่ซ้ำ 3. ใช้ var(--card-padding) ในที่ที่เหมาะสม