CSS
Fundamentals
Pseudo-class Selectors
Pseudo-class เลือก element ตามสถานะและตำแหน่งที่ไม่ได้เขียนใน HTML โดยตรง — ตั้งแต่ :hover :focus สำหรับ interaction ไปจนถึง :nth-child() สำหรับ layout และ :checked :disabled สำหรับ form
Pseudo-class คืออะไร
Pseudo-class คือ selector พิเศษที่เริ่มต้นด้วยเครื่องหมาย : (colon เดียว) ใช้สำหรับเลือก element ตาม "สถานะ" หรือ "ตำแหน่ง" ที่ไม่ได้มีอยู่ใน HTML โดยตรง ตัวอย่างเช่น element ที่กำลังถูก hover หรือ li ตัวแรกในรายการ — ข้อมูลเหล่านี้มีอยู่ในบริบทของหน้าเว็บ แต่เราไม่ได้เพิ่ม class ไว้ใน HTML รูปแบบ: selector:pseudo-class { ... }
- State — ตอบสนองต่อการโต้ตอบ เช่น :hover :focus :active
- Structural — ตำแหน่งใน DOM เช่น :first-child :last-child :nth-child()
- Negation — ยกเว้น เช่น :not()
- Form — สถานะ input เช่น :checked :disabled :enabled
State Pseudo-classes — :hover, :focus, :active
:hover — ใช้งานเมื่อเมาส์ชี้อยู่บน element :focus — ใช้งานเมื่อ element กำลังถูก focus (กดแป้น Tab หรือคลิก) :active — ใช้งานขณะกด (mousedown ยังค้างอยู่) :focus สำคัญมากด้าน accessibility — อย่าลบออก แต่ปรับ style ได้
รวมกับ transition เพื่อให้ animation นุ่มนวล
button:hover {
background: #1d4ed8;
transform: translateY(-1px);
}
input:focus {
outline: 2px solid #3b82f6;
outline-offset: 2px;
border-color: #3b82f6;
}
button:active {
transform: translateY(0);
background: #1e3a8a;
}Structural Pseudo-classes — :first-child, :last-child, :nth-child()
Structural pseudo-class เลือก element ตามตำแหน่งใน parent :first-child — element ลูกตัวแรก :last-child — element ลูกตัวสุดท้าย :nth-child(n) — element ลูกตัวที่ n :nth-child(odd) — element ลอดตัวคี่ (1, 3, 5, ...) :nth-child(even) — element ลูกตัวคู่ (2, 4, 6, ...) :nth-child(2n+1) — รูปแบบ formula (เหมือน odd)
nth-child ใช้งานกับตาราง การ์ด และรายการบ่อยมาก
/* row แรกของตาราง */
tr:first-child {
background: #1e3a8a;
color: white;
}
/* row สลับสี (zebra striping) */
tr:nth-child(even) {
background: #f1f5f9;
}
/* item สุดท้ายไม่มี border */
li:last-child {
border-bottom: none;
}Negation Pseudo-class — :not()
:not(selector) เลือก element ทุกตัวที่ไม่ตรงกับ selector ที่ใส่ไว้ใน () มีประโยชน์มากเมื่อต้องการ style "ทุกตัวยกเว้นตัวนี้" โดยไม่ต้องเขียน class พิเศษ
:not() รับได้ทั้ง element, class, attribute, pseudo-class
/* button ทุกตัวยกเว้น disabled */
button:not([disabled]) {
cursor: pointer;
}
/* ทุก li ยกเว้นตัวสุดท้าย (ใช้แทน li:last-child { border: none }) */
li:not(:last-child) {
border-bottom: 1px solid #e5e7eb;
}
/* input ทุกตัวยกเว้น submit */
input:not([type="submit"]) {
border: 1px solid #d1d5db;
border-radius: 4px;
}Form State Pseudo-classes — :checked, :disabled, :enabled
:checked — checkbox หรือ radio ที่ถูกเลือก :disabled — input ที่มี disabled attribute :enabled — input ที่ใช้งานได้ (ตรงข้าม disabled) :required — input ที่มี required attribute :valid — input ที่ผ่าน validation :invalid — input ที่ไม่ผ่าน validation
รวมกับ adjacent sibling (+) ได้อย่างทรงพลัง
/* checkbox ที่ถูกเลือก */
input[type="checkbox"]:checked + label {
color: #16a34a;
font-weight: bold;
}
/* input ที่ disable */
input:disabled {
background: #f3f4f6;
color: #9ca3af;
cursor: not-allowed;
}
/* input email ที่ valid */
input[type="email"]:valid {
border-color: #16a34a;
}
input[type="email"]:invalid {
border-color: #dc2626;
}เปรียบเทียบ Pseudo-classes
| Pseudo-class | ประเภท | เงื่อนไข |
|---|---|---|
| :hover | State | เมาส์ชี้อยู่บน element |
| :focus | State | element ถูก focus |
| :active | State | element ถูกกดอยู่ |
| :first-child | Structural | ลูกตัวแรกของ parent |
| :last-child | Structural | ลูกตัวสุดท้ายของ parent |
| :nth-child(n) | Structural | ลูกตัวที่ n ของ parent |
| :not(sel) | Negation | ไม่ตรงกับ selector ที่กำหนด |
| :checked | Form | checkbox/radio ที่ถูกเลือก |
| :disabled | Form | input ที่ถูก disable |
| :valid / :invalid | Form | input ที่ผ่าน/ไม่ผ่าน validation |
สรุปท้ายบท
- Pseudo-class ขึ้นต้นด้วย : (colon เดียว) เสมอ
- :hover :focus :active ตอบสนองการโต้ตอบ — อย่าลืม :focus เพื่อ accessibility
- :nth-child() รับได้ทั้ง n, odd, even, หรือ formula เช่น 3n+1
- :not() มีประโยชน์มากสำหรับ 'ทุกตัวยกเว้น...'
- Form pseudo-classes ทำให้ UI ตอบสนองต่อสถานะ input โดยไม่ต้องใช้ JavaScript
- รวม pseudo-class กับ combinator ได้ เช่น li:not(:last-child) a:hover
Lab 1: Interactive Form Controls
เป้าหมาย: ฝึกใช้ state pseudo-class เพื่อทำให้ control สื่อสถานะกับผู้ใช้ได้ชัดขึ้น โจทย์: 1. ใช้ .submit:hover เพื่อให้ปุ่มส่งฟอร์มมี background-color: #1d4ed8 เมื่อ hover 2. ใช้ input:focus เพื่อให้ช่องกรอกมี outline: 2px solid #3b82f6 เมื่อ focus 3. ใช้ button:disabled เพื่อให้ปุ่มที่ปิดใช้งานมี opacity: 0.5
Lab 2: Menu State & Structure
เป้าหมาย: ฝึกใช้ structural pseudo-class และ :not() เพื่อจัดหน้าตาเมนูตามตำแหน่งของรายการ โจทย์: 1. ใช้ .menu li:first-child เพื่อให้รายการแรกมี font-weight: bold 2. ใช้ .menu li:last-child เพื่อให้รายการสุดท้ายมี border-bottom: none 3. ใช้ .menu li:nth-child(even) เพื่อให้รายการลำดับคู่มี background-color: #f9fafb 4. ใช้ .menu li:not(:last-child) เพื่อให้ทุกรายการยกเว้นรายการสุดท้ายมี border-bottom: 1px solid #e5e7eb