ไทย

สำรวจ CSS :has() selector ตัวเปลี่ยนเกมสำหรับการเลือก parent element เรียนรู้การใช้งานจริง ความเข้ากันได้ของเบราว์เซอร์ และเทคนิคขั้นสูงที่จะปฏิวัติการทำสไตล์ CSS ของคุณ

การใช้งาน CSS :has() Selector อย่างเชี่ยวชาญ: ปลดปล่อยพลังการเลือก Parent Element

เป็นเวลาหลายปีที่นักพัฒนา CSS ปรารถนาวิธีที่ง่ายและมีประสิทธิภาพในการเลือก parent element โดยอิงจาก child element ของมัน การรอคอยสิ้นสุดลงแล้ว! pseudo-class :has() มาถึงแล้ว และกำลังปฏิวัติวิธีการเขียน CSS ของเรา ตัวเลือกที่ทรงพลังนี้ช่วยให้คุณสามารถกำหนดเป้าหมายไปยัง parent element ได้หากมันมี child element ที่ระบุอยู่ ซึ่งเป็นการเปิดโลกแห่งความเป็นไปได้สำหรับการทำสไตล์แบบไดนามิกและตอบสนองได้ดี

:has() Selector คืออะไร?

:has() pseudo-class คือ CSS relational pseudo-class ที่รับรายการตัวเลือก (selector list) เป็นอาร์กิวเมนต์ มันจะเลือก element หากตัวเลือกใดๆ ในรายการตัวเลือกนั้นตรงกับ element อย่างน้อยหนึ่งตัวในบรรดา element ลูกหลาน (descendants) ของมัน พูดง่ายๆ ก็คือ มันจะตรวจสอบว่า parent element มี child ที่ระบุหรือไม่ และถ้ามี parent element นั้นก็จะถูกเลือก

ไวยากรณ์พื้นฐานคือ:

parent:has(child) { /* CSS rules */ }

โค้ดนี้จะเลือก parent element ก็ต่อเมื่อมันมี child element อย่างน้อยหนึ่งตัว

ทำไม :has() ถึงสำคัญมาก?

ตามปกติแล้ว CSS มีข้อจำกัดในความสามารถในการเลือก parent element โดยอิงจาก child element ของมัน ข้อจำกัดนี้มักต้องการวิธีแก้ปัญหาที่ซับซ้อนด้วย JavaScript หรือวิธีแก้ปัญหาเฉพาะหน้าเพื่อให้ได้สไตล์แบบไดนามิก :has() selector ช่วยลดความจำเป็นในการใช้วิธีที่ยุ่งยากเหล่านี้ ทำให้ได้โค้ด CSS ที่สะอาดขึ้น ดูแลรักษาง่ายขึ้น และมีประสิทธิภาพมากขึ้น

นี่คือเหตุผลว่าทำไม :has() ถึงเป็นตัวเปลี่ยนเกม:

ตัวอย่างพื้นฐานของ :has() Selector

เรามาเริ่มด้วยตัวอย่างง่ายๆ เพื่อแสดงให้เห็นถึงพลังของ :has() selector กัน

ตัวอย่างที่ 1: การทำสไตล์ Parent Div ตามการมีอยู่ของรูปภาพ

สมมติว่าคุณต้องการเพิ่มเส้นขอบให้กับ element <div> ก็ต่อเมื่อมันมี element <img> อยู่ข้างใน:

div:has(img) { border: 2px solid blue; }

กฎ CSS นี้จะใช้เส้นขอบสีน้ำเงินกับ <div> ใดๆ ที่มี element <img> อย่างน้อยหนึ่งตัว

ตัวอย่างที่ 2: การทำสไตล์รายการลิสต์ตามการมีอยู่ของ Span

สมมติว่าคุณมีรายการลิสต์ และคุณต้องการไฮไลท์รายการลิสต์นั้นหากมันมี element <span> ที่มีคลาสที่ระบุ:

li:has(span.highlight) { background-color: yellow; }

กฎ CSS นี้จะเปลี่ยนสีพื้นหลังของ <li> ใดๆ ที่มี <span> ที่มีคลาส "highlight" เป็นสีเหลือง

ตัวอย่างที่ 3: การทำสไตล์ Label ของฟอร์มตามความถูกต้องของ Input

คุณสามารถใช้ :has() เพื่อทำสไตล์ label ของฟอร์มโดยอิงจากว่าช่อง input ที่เกี่ยวข้องนั้นถูกต้องหรือไม่ (ใช้ร่วมกับ :invalid pseudo-class):

label:has(+ input:invalid) { color: red; font-weight: bold; }

โค้ดนี้จะทำให้ label เป็นสีแดงและตัวหนาหากช่อง input ที่อยู่ถัดไปทันทีไม่ถูกต้อง

การใช้งาน :has() Selector ขั้นสูง

:has() selector จะทรงพลังยิ่งขึ้นเมื่อใช้ร่วมกับ CSS selector และ pseudo-class อื่นๆ นี่คือกรณีการใช้งานขั้นสูงบางส่วน:

ตัวอย่างที่ 4: การกำหนดเป้าหมายไปยัง Element ที่ไม่มี Child ที่ต้องการ

คุณสามารถใช้ :not() pseudo-class ร่วมกับ :has() เพื่อกำหนดเป้าหมาย element ที่ *ไม่มี* child ที่ระบุ ตัวอย่างเช่น การทำสไตล์ div ที่ *ไม่มี* รูปภาพ:

div:not(:has(img)) { background-color: #f0f0f0; }

โค้ดนี้จะใช้พื้นหลังสีเทาอ่อนกับ <div> ใดๆ ที่ไม่มี element <img>

ตัวอย่างที่ 5: การสร้างเลย์เอาต์ที่ซับซ้อน

สามารถใช้ :has() selector เพื่อสร้างเลย์เอาต์แบบไดนามิกตามเนื้อหาของคอนเทนเนอร์ได้ ตัวอย่างเช่น คุณสามารถเปลี่ยนเลย์เอาต์ของกริดตามการมีอยู่ของ element ประเภทที่ระบุภายในเซลล์กริด

.grid-container { display: grid; grid-template-columns: repeat(3, 1fr); } .grid-item:has(img) { grid-column: span 2; }

โค้ดนี้จะทำให้ grid item ขยายขนาดครอบคลุมสองคอลัมน์หากมันมีรูปภาพอยู่ข้างใน

ตัวอย่างที่ 6: การทำสไตล์ฟอร์มแบบไดนามิก

คุณสามารถใช้ :has() เพื่อทำสไตล์องค์ประกอบของฟอร์มแบบไดนามิกตามสถานะของมัน (เช่น ไม่ว่าจะเป็น focused, filled หรือ valid)

.form-group:has(input:focus) { box-shadow: 0 0 5px rgba(0, 0, 255, 0.5); } .form-group:has(input:valid) { border-color: green; } .form-group:has(input:invalid) { border-color: red; }

โค้ดนี้จะเพิ่มเงาสีน้ำเงินเมื่อ input ถูก focus, เส้นขอบสีเขียวถ้า input ถูกต้อง และเส้นขอบสีแดงถ้า input ไม่ถูกต้อง

ตัวอย่างที่ 7: การทำสไตล์ตามจำนวน Child

แม้ว่า :has() จะไม่สามารถนับจำนวน child ได้โดยตรง แต่คุณสามารถใช้ร่วมกับ selector และคุณสมบัติ CSS อื่นๆ เพื่อให้ได้ผลลัพธ์ที่คล้ายกัน ตัวอย่างเช่น คุณสามารถใช้ :only-child เพื่อทำสไตล์ parent หากมี child ประเภทที่ระบุเพียงตัวเดียว

div:has(> p:only-child) { background-color: lightgreen; }

โค้ดนี้จะทำสไตล์ <div> ด้วยพื้นหลังสีเขียวอ่อนก็ต่อเมื่อมันมี element <p> เพียงตัวเดียวเป็น child โดยตรง

ความเข้ากันได้ระหว่างเบราว์เซอร์และ Fallbacks

ณ ปลายปี 2023 :has() selector ได้รับการรองรับอย่างยอดเยี่ยมในเบราว์เซอร์สมัยใหม่ รวมถึง Chrome, Firefox, Safari และ Edge อย่างไรก็ตาม สิ่งสำคัญคือต้องตรวจสอบความเข้ากันได้บน Can I use ก่อนนำไปใช้งานจริง โดยเฉพาะอย่างยิ่งหากคุณต้องการรองรับเบราว์เซอร์รุ่นเก่า

นี่คือรายละเอียดข้อควรพิจารณาเกี่ยวกับความเข้ากันได้:

การเตรียม Fallbacks

หากคุณจำเป็นต้องรองรับเบราว์เซอร์รุ่นเก่า คุณจะต้องเตรียม fallback ไว้ นี่คือกลยุทธ์บางส่วน:

นี่คือตัวอย่างการใช้ feature query:

.parent { /* Basic styling for all browsers */ border: 1px solid black; } @supports selector(:has(img)) { .parent:has(img) { /* Enhanced styling for browsers that support :has() */ border: 3px solid blue; } }

โค้ดนี้จะใช้เส้นขอบสีดำกับ element .parent ในทุกเบราว์เซอร์ ในเบราว์เซอร์ที่รองรับ :has() มันจะใช้เส้นขอบสีน้ำเงินหาก element .parent มีรูปภาพอยู่ข้างใน

ข้อควรพิจารณาด้านประสิทธิภาพ

แม้ว่า :has() จะมีข้อดีมากมาย แต่ก็จำเป็นต้องพิจารณาถึงผลกระทบที่อาจเกิดขึ้นกับประสิทธิภาพ โดยเฉพาะอย่างยิ่งเมื่อใช้กันอย่างแพร่หลายหรือใช้กับ selector ที่ซับซ้อน เบราว์เซอร์จำเป็นต้องประเมิน selector สำหรับทุก element บนหน้าเว็บ ซึ่งอาจทำให้สิ้นเปลืองพลังการประมวลผล

นี่คือเคล็ดลับบางประการในการเพิ่มประสิทธิภาพการทำงานของ :has():

ข้อผิดพลาดที่ควรหลีกเลี่ยง

เมื่อทำงานกับ :has() selector อาจเกิดข้อผิดพลาดที่นำไปสู่ผลลัพธ์ที่ไม่คาดคิดได้ง่าย นี่คือข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง:

แนวทางปฏิบัติที่ดีที่สุดสำหรับการใช้ :has()

เพื่อเพิ่มประโยชน์สูงสุดของ :has() selector และหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น ให้ปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:

ตัวอย่างและการใช้งานจริง

เรามาสำรวจตัวอย่างการใช้งานจริงบางส่วนของ :has() selector ในการแก้ปัญหาความท้าทายด้านการออกแบบทั่วไปกัน

ตัวอย่างที่ 8: การสร้างเมนูนำทางที่ตอบสนอง (Responsive)

คุณสามารถใช้ :has() เพื่อสร้างเมนูนำทางที่ตอบสนองซึ่งปรับเปลี่ยนตามขนาดหน้าจอต่างๆ โดยอิงตามการมีอยู่ของรายการเมนูที่ระบุ

ลองนึกภาพสถานการณ์ที่คุณต้องการแสดงเมนูนำทางที่แตกต่างกัน ขึ้นอยู่กับว่าผู้ใช้ล็อกอินอยู่หรือไม่ หากล็อกอินอยู่ คุณอาจแสดงโปรไฟล์และการดำเนินการออกจากระบบ หากไม่ได้ล็อกอิน คุณอาจแสดงการเข้าสู่ระบบ/ลงทะเบียน

nav:has(.user-profile) { /* Styles for logged-in users */ } nav:not(:has(.user-profile)) { /* Styles for logged-out users */ }

ตัวอย่างที่ 9: การทำสไตล์ส่วนประกอบการ์ด (Card Components)

:has() selector สามารถใช้เพื่อทำสไตล์ส่วนประกอบการ์ดตามเนื้อหาของมันได้ ตัวอย่างเช่น คุณสามารถเพิ่มเงาให้กับการ์ดได้ก็ต่อเมื่อมันมีรูปภาพอยู่ข้างใน

.card:has(img) { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); }

ตัวอย่างที่ 10: การใช้ธีมแบบไดนามิก

คุณสามารถใช้ :has() เพื่อใช้ธีมแบบไดนามิกตามความต้องการของผู้ใช้หรือการตั้งค่าของระบบ ตัวอย่างเช่น คุณสามารถเปลี่ยนสีพื้นหลังของหน้าเว็บโดยขึ้นอยู่กับว่าผู้ใช้เปิดใช้งานโหมดมืดหรือไม่

body:has(.dark-mode) { background-color: #333; color: #fff; }

ตัวอย่างเหล่านี้แสดงให้เห็นถึงความหลากหลายของ :has() selector และความสามารถในการแก้ปัญหาความท้าทายด้านการออกแบบที่หลากหลาย

อนาคตของ CSS: ก้าวต่อไปคืออะไร?

การมาถึงของ :has() selector ถือเป็นก้าวสำคัญในวิวัฒนาการของ CSS มันช่วยให้นักพัฒนาสามารถสร้างสไตล์ชีตที่มีไดนามิก ตอบสนองได้ดี และบำรุงรักษาง่ายขึ้น โดยพึ่งพา JavaScript น้อยลง ในขณะที่การรองรับ :has() ในเบราว์เซอร์ยังคงเติบโตอย่างต่อเนื่อง เราคาดหวังว่าจะได้เห็นการใช้งานที่สร้างสรรค์และแปลกใหม่ของ selector ที่ทรงพลังนี้มากยิ่งขึ้น

เมื่อมองไปข้างหน้า CSS Working Group กำลังสำรวจคุณสมบัติและการปรับปรุงที่น่าตื่นเต้นอื่นๆ ที่จะขยายขีดความสามารถของ CSS ต่อไป ซึ่งรวมถึง:

ด้วยการติดตามการพัฒนา CSS ล่าสุดและยอมรับคุณสมบัติใหม่ๆ เช่น :has() นักพัฒนาสามารถปลดล็อกศักยภาพสูงสุดของ CSS และสร้างประสบการณ์เว็บที่ยอดเยี่ยมอย่างแท้จริงได้

บทสรุป

:has() selector เป็นเครื่องมือที่ทรงพลังที่เพิ่มเข้ามาในกล่องเครื่องมือ CSS ช่วยให้สามารถเลือก parent element และเปิดโอกาสใหม่ๆ สำหรับการทำสไตล์แบบไดนามิกและตอบสนองได้ดี แม้ว่าการพิจารณาความเข้ากันได้ของเบราว์เซอร์และผลกระทบด้านประสิทธิภาพจะเป็นสิ่งสำคัญ แต่ประโยชน์ของการใช้ :has() เพื่อโค้ด CSS ที่สะอาดขึ้น บำรุงรักษาง่ายขึ้น และมีประสิทธิภาพมากขึ้นนั้นไม่อาจปฏิเสธได้ ยอมรับ selector ที่จะเปลี่ยนเกมนี้และปฏิวัติการทำสไตล์ CSS ของคุณวันนี้!

อย่าลืมคำนึงถึงการเข้าถึงและเตรียมกลไกสำรอง (fallback) สำหรับเบราว์เซอร์รุ่นเก่า ด้วยการปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดที่ระบุไว้ในคู่มือนี้ คุณสามารถใช้ประโยชน์จากศักยภาพสูงสุดของ :has() selector และสร้างประสบการณ์เว็บที่ยอดเยี่ยมอย่างแท้จริงสำหรับผู้ใช้ทั่วโลก