Fundamentals
Combination Selectors
ใช้ combinator ทั้ง 4 ตัว — descendant, child, adjacent sibling และ general sibling — เพื่อเลือก element ตามความสัมพันธ์ในโครงสร้าง HTML โดยไม่ต้องเพิ่ม class
1) บทบาท: เมื่อ style ต้องขึ้นกับ "ตำแหน่งในโครงสร้าง" ไม่ใช่ชื่อ
selector ที่เรียนมา (element, class, id) เลือก element ได้ "ตัวเดียวหรือกลุ่มเดียว" แต่หน้าเว็บจริงมักต้องการ style ที่ขึ้นกับความสัมพันธ์ในโครงสร้าง HTML เช่น เฉพาะหัวข้อเมนูชั้นแรก เฉพาะย่อหน้าในบทความ หรือเฉพาะย่อหน้าที่ตามหัวข้อทันที element เหล่านั้นไม่มี class พิเศษ และการไปเติม class ให้ทุกจุดก็รก — combinator คือเครื่องหมายที่เชื่อม selector สองตัว เพื่อเลือก element ตามความสัมพันธ์นั้น
- เฉพาะ <li> ที่เป็นลูกโดยตรงของเมนู — ไม่รวม <li> ในเมนูย่อย
- เฉพาะ <p> ที่อยู่ภายในบทความ — ไม่รวม <p> ในส่วนอื่นของหน้า
- เฉพาะย่อหน้าแรกที่ตามหลังหัวข้อ — ใช้กับเนื้อหาทุกตอนโดยไม่ต้องเพิ่ม class
2) รูปแบบ: combinator 4 ตัวที่ใช้บ่อย
combinator เขียนคั่นระหว่าง selector สองตัว: A (เครื่องหมาย) B — A คือ "จุดอ้างอิง" และ B คือ "เป้าหมายที่ต้องสัมพันธ์กับ A"
| Combinator | เครื่องหมาย | ความหมาย | ตัวอย่าง |
|---|---|---|---|
| Descendant | ช่องว่าง (A B) | B อยู่ภายใน A กี่ชั้นก็ได้ | article p |
| Child | > (A > B) | B เป็นลูกโดยตรงของ A เท่านั้น | ul > li |
| Adjacent sibling | + (A + B) | B อยู่ถัดจาก A ทันที ใน parent เดียวกัน | h2 + p |
| General sibling | ~ (A ~ B) | B ตามหลัง A ใน parent เดียวกัน ไม่ต้องติดกัน | .note ~ p |
selector ฝั่งซ้ายคือจุดอ้างอิง ฝั่งขวาคือเป้าหมาย — อ่านว่า "B ที่...ของ A" เสมอ (หมายเหตุ: property อย่าง font-weight และ text-decoration ที่ใช้ในตัวอย่างและแบบฝึกหัด จะเรียนเต็มในบท Typography & Colors — บทนี้เน้นความสัมพันธ์ของ selector)
3) เขียนผิด vs เขียนถูก: descendant กับ child ใช้สลับกันไม่ได้
**ทายก่อนดูเฉลย:** โค้ดฝั่งซ้ายและฝั่งขวาใช้ HTML ชุดเดียวกัน — เมนูที่มีเมนูย่อยซ้อนอยู่ ต่างกันที่เครื่องหมายระหว่าง .menu กับ li ฝั่งไหนจะทำให้ "หน้าแรก", "สินค้า" และ "ติดต่อ" ตัวหนา แต่ "เสื้อผ้า" กับ "รองเท้า" ในเมนูย่อยไม่หนา?
ใช้ descendant ทั้งที่ต้องการแค่ลูกตรง
ช่องว่างกับ > ให้ผลต่างกันเมื่อ HTML ซ้อนหลายชั้น — เลือกผิด = style รั่วไปโดนชั้นลึก
.menu li จับ li ทุกตัวที่อยู่ข้างใน .menu — รวม "เสื้อผ้า" และ "รองเท้า" ในเมนูย่อยด้วย
> จำกัดให้เป็นลูกโดยตรงของ .menu เท่านั้น — เมนูย่อยที่ซ้อนลึกลงไปจึงไม่โดน
Lab 1 — ทำตาม: ใช้ descendant และ child ตามโครงสร้างที่ให้
หน้าเอกสารมีสารบัญ (กล่อง .toc) และเนื้อหาใน .article — ให้เขียน rule สองข้อตามโจทย์ในแท็บ CSS: ข้อแรกเป็น descendant เพื่อจับทุก <p> ในบทความ ข้อที่สองเป็น child เพื่อจับเฉพาะหัวข้อสารบัญชั้นแรก
Lab 2 — ปรับ: แก้ descendant ที่กว้างเกินให้เป็น child
เมนู .menu มี 2 ชั้น แต่ rule ที่เขียนไว้ใช้ .menu ul li (descendant) ทำให้ style รั่วไปโดน "เสื้อผ้า" กับ "รองเท้า" ในเมนูย่อยด้วย — ให้แก้ selector ของ rule แรกให้เลือกเฉพาะหัวข้อชั้นแรก และเพิ่ม rule ที่สองเพื่อลบขีดเส้นใต้เฉพาะลิงก์ชั้นแรก
Lab 3 — แก้เอง: เลือก combinator ให้ตรงความสัมพันธ์ทั้ง 3 โซน
หน้านี้มี 3 โซน แต่ละโซนต้องการความสัมพันธ์คนละแบบ: (1) สารบัญที่ต้องโดนเฉพาะหัวข้อชั้นแรก (2) บทความที่ต้องเน้นย่อหน้าแรกหลังแต่ละหัวข้อ และ (3) เนื้อหาที่ให้ทุกย่อหน้าหลังกล่องหมายเหตุย่อขอบ — HTML มีโครงสร้างครบแล้ว ให้เลือก combinator ให้ถูกโจทย์แต่ละข้อ แล้วเขียน rule ในแท็บ CSS
ตรวจความเข้าใจและก้าวต่อไป
ตอบคำถามสั้น ๆ เพื่อเช็กว่าคุณเลือก combinator ให้ตรงกับความสัมพันธ์ในโครงสร้าง HTML และแยก descendant ออกจาก child ได้หรือยัง
ตรวจความเข้าใจ: Combination Selectors
HTML มีเมนู 2 ชั้น: <ul class="nav"> ที่ข้างในมี <li> และ <li> บางตัวซ้อน <ul> เมนูย่อย — อยากให้เฉพาะ <li> ที่เป็นลูกโดยตรงของ .nav เปลี่ยนสี ควรใช้ selector ข้อใด?
HTML: <h2>หัวข้อ</h2><p>ย่อหน้าแรก</p><p>ย่อหน้าที่สอง</p> — selector ใดจับ "ย่อหน้าแรก" เพียงตัวเดียว?
ข้อใดเป็นจริงเกี่ยวกับ combinator (เลือกทุกข้อที่ถูก)
combinator ที่เลือก element พี่น้องทุกตัวที่ตามหลัง A ใน parent เดียวกัน คือ A ____ B — เติมเครื่องหมาย
- combinator เชื่อม selector สองตัวเพื่อเลือกตามความสัมพันธ์: A B / A > B / A + B / A ~ B
- ช่องว่าง (descendant) ลึกกี่ชั้นก็ได้ · > (child) เฉพาะลูกตรง · + ตัวถัดไปทันที · ~ ทุกตัวที่ตามมา
- combinator ใช้โครงสร้าง HTML ที่มีอยู่ — ไม่ต้องเพิ่ม class ให้ element ทุกจุด
- ก้าวต่อไป: ในบทถัดไป 'Pseudo-class Selectors' เราจะเรียนการเลือก element ตามสถานะของผู้ใช้ เช่น ตอนเมาส์ชี้หรือตอนคลิก — ซึ่งต่อยอดจาก selector และ combinator ที่รู้จักแล้ว (สมมติฐานความรู้ก่อนหน้า: เขียน combinator ทั้ง 4 ตัวและแยก descendant ออกจาก child ได้จากบทนี้ เพราะ pseudo-class มักประกอบกับ selector แบบผสมที่ใช้ combinator คั่น)