The CSS Podcast - 015: Pseudo-classes
สมมติว่าคุณมีแบบฟอร์มลงชื่อสมัครรับอีเมล และต้องการให้ช่องแบบฟอร์มอีเมลมีเส้นขอบสีแดงหากมีอีเมลที่ไม่ถูกต้อง คุณจะทำได้อย่างไร คุณสามารถใช้:invalid
คลาสสมมติ CSS ซึ่งเป็นหนึ่งในคลาสสมมติหลายรายการที่เบราว์เซอร์มีให้
คลาสจำลองช่วยให้คุณใช้สไตล์ตามการเปลี่ยนแปลงสถานะและปัจจัยภายนอกได้ ซึ่งหมายความว่าดีไซน์ของคุณสามารถตอบสนองต่อข้อมูลที่ผู้ใช้ป้อน เช่น อีเมลที่ไม่ถูกต้อง ซึ่งจะกล่าวถึงในโมดูลตัวเลือก และโมดูลนี้จะอธิบายรายละเอียดเพิ่มเติมให้คุณ
คลาสเสมือนจะเชื่อมต่อกับสถานะที่เฉพาะเจาะจงซึ่งองค์ประกอบอาจมี แทนที่จะจัดรูปแบบส่วนต่างๆ ขององค์ประกอบนั้นโดยทั่วไป ซึ่งแตกต่างจากองค์ประกอบเสมือน ซึ่งคุณดูข้อมูลเพิ่มเติมได้ในโมดูลก่อนหน้า
สถานะแบบอินเทอร์แอกทีฟ
Pseudo-class ต่อไปนี้จะมีผลเนื่องจากการโต้ตอบที่ผู้ใช้มีกับหน้าเว็บ
:hover
หากผู้ใช้มีอุปกรณ์ชี้ เช่น เมาส์หรือแทร็กแพด และวางอุปกรณ์ไว้เหนือองค์ประกอบ คุณสามารถเชื่อมต่อกับสถานะนั้นด้วย :hover
เพื่อใช้รูปแบบ ซึ่งเป็นวิธีที่มีประโยชน์ในการบอกเป็นนัยว่าโต้ตอบกับองค์ประกอบได้
:active
สถานะนี้จะทริกเกอร์เมื่อมีการโต้ตอบกับองค์ประกอบอยู่ เช่น การคลิก ก่อนที่จะปล่อยการคลิก หากใช้อุปกรณ์ชี้ เช่น เมาส์ สถานะนี้คือเมื่อการคลิกเริ่มต้นและยังไม่ได้ปล่อย
:focus
, :focus-within
และ :focus-visible
หากองค์ประกอบรับโฟกัสได้ เช่น <button>
คุณจะโต้ตอบกับสถานะนั้นได้ด้วย คลาสเสมือน :focus
นอกจากนี้ คุณยังโต้ตอบได้หากองค์ประกอบย่อยขององค์ประกอบได้รับโฟกัสด้วย :focus-within
องค์ประกอบที่โฟกัสได้ เช่น ปุ่ม จะแสดงวงแหวนโฟกัสเมื่ออยู่ในโฟกัส แม้ว่าจะคลิกแล้วก็ตาม ในสถานการณ์เช่นนี้ นักพัฒนาแอปจะใช้ CSS ต่อไปนี้
button:focus { outline: none; }
CSS นี้จะนำวงแหวนโฟกัสของเบราว์เซอร์เริ่มต้นออกเมื่อองค์ประกอบได้รับโฟกัส ซึ่งทำให้เกิดปัญหาด้านการช่วยเหลือพิเศษสำหรับผู้ใช้ที่ไปยังส่วนต่างๆ ของหน้าเว็บด้วยแป้นพิมพ์ หากไม่มีรูปแบบโฟกัส ผู้ใช้จะติดตามตำแหน่งที่โฟกัสอยู่ไม่ได้เมื่อใช้ปุ่ม Tab ด้วย :focus-visible
คุณสามารถนำเสนอรูปแบบโฟกัสเมื่อองค์ประกอบได้รับโฟกัสโดยใช้แป้นพิมพ์ ในขณะที่ใช้กฎ outline: none
เพื่อป้องกันไม่ให้เกิดขึ้นเมื่ออุปกรณ์พอยน์เตอร์โต้ตอบกับองค์ประกอบ
button:focus { outline: none; } button:focus-visible { outline: 1px solid black; }
:target
คลาสเทียม :target
จะเลือกองค์ประกอบที่มี id
ที่ตรงกับส่วนย่อยของ URL สมมติว่าคุณมี HTML ดังนี้
<article id="content"> <!-- ... --> </article>
คุณแนบสไตล์กับองค์ประกอบนั้นได้เมื่อ URL มี #content
#content:target { background: yellow; }
ซึ่งมีประโยชน์ในการไฮไลต์พื้นที่ที่อาจมีการลิงก์ถึงโดยเฉพาะ เช่น เนื้อหาหลักในเว็บไซต์ โดยใช้ลิงก์ข้าม
สถานะประวัติ
:link
คุณใช้:link
คลาสเสมือนกับองค์ประกอบ <a>
ใดก็ได้ที่มีค่า href
ซึ่งยังไม่ได้เข้าชม
:visited
คุณจัดรูปแบบลิงก์ที่ผู้ใช้เข้าชมแล้วได้โดยใช้คลาสเสมือน :visited
ซึ่งเป็นสถานะตรงข้ามกับ :link
แต่คุณจะมีพร็อพเพอร์ตี้ CSS ให้ใช้น้อยกว่าด้วยเหตุผลด้านความปลอดภัย คุณจัดรูปแบบได้เฉพาะ color
, background-color
, border-color
, outline-color
และสีของ SVG fill
และ stroke
ลำดับมีความสำคัญ
หากคุณกำหนด:visited
สไตล์ คลาสหลอกของลิงก์จะลบล้างสไตล์ดังกล่าวได้โดยมีความเฉพาะเจาะจงอย่างน้อยเท่ากัน ด้วยเหตุนี้ เราจึงขอแนะนำให้คุณใช้กฎ LVHA ในการจัดรูปแบบลิงก์ด้วยคลาสเสมือนตามลำดับต่อไปนี้ :link
, :visited
, :hover
, :active
a:link {} a:visited {} a:hover {} a:active {}
สถานะของแบบฟอร์ม
Pseudo-class ต่อไปนี้สามารถเลือกองค์ประกอบของแบบฟอร์ม ในสถานะต่างๆ ที่องค์ประกอบเหล่านี้อาจอยู่ในระหว่างการโต้ตอบกับองค์ประกอบเหล่านั้น
:disabled
และ :enabled
หากเบราว์เซอร์ปิดใช้องค์ประกอบของแบบฟอร์ม เช่น <button>
คุณสามารถเชื่อมต่อกับสถานะนั้นได้ด้วย คลาสเสมือน :disabled
:enabled
คลาสเสมือนพร้อมใช้งานสำหรับสถานะตรงข้าม แม้ว่าองค์ประกอบของแบบฟอร์มจะ:enabled
โดยค่าเริ่มต้น คุณจึงอาจไม่จำเป็นต้องใช้คลาสเสมือนนี้
:checked
และ :indeterminate
:checked
คลาสเทียมจะพร้อมใช้งานเมื่อองค์ประกอบแบบฟอร์มที่รองรับ เช่น ช่องทำเครื่องหมายหรือปุ่มตัวเลือกอยู่ในสถานะที่เลือก
:checked
สถานะเป็นสถานะไบนารี (จริงหรือเท็จ) แต่ช่องทำเครื่องหมายมีสถานะกลางเมื่อไม่ได้เลือกหรือยกเลิกการเลือก ซึ่งเรียกว่าสถานะ :indeterminate
ตัวอย่างของสถานะนี้คือเมื่อคุณมีตัวควบคุม "เลือกทั้งหมด" ที่เลือกช่องทําเครื่องหมายทั้งหมดในกลุ่ม หากผู้ใช้ยกเลิกการเลือกช่องทำเครื่องหมายใดช่องหนึ่ง ช่องทำเครื่องหมายรูทจะไม่แสดง "ทั้งหมด" ที่เลือกอีกต่อไป จึงควรเปลี่ยนเป็นสถานะไม่แน่นอน
องค์ประกอบ <progress>
ยังมีสถานะไม่แน่นอนที่จัดรูปแบบได้ด้วย Use Case ที่พบบ่อยคือการทำให้แถบมีลักษณะเป็นลายทางเพื่อระบุว่าไม่ทราบว่าต้องใช้เวลาอีกเท่าใด
:placeholder-shown
หากฟิลด์แบบฟอร์มมีแอตทริบิวต์ placeholder
และไม่มีค่า คุณจะใช้คลาสเทียม :placeholder-shown
เพื่อแนบสไตล์กับสถานะนั้นได้ ทันทีที่มีเนื้อหาในฟิลด์ ไม่ว่าจะมี placeholder
หรือไม่ก็ตาม สถานะนี้จะไม่มีผลอีกต่อไป
สถานะการตรวจสอบ
คุณตอบสนองต่อการตรวจสอบความถูกต้องของแบบฟอร์ม HTML ได้ด้วย Pseudo-classes เช่น :valid
:invalid
และ :in-range
คลาสเสมือน :valid
และ :invalid
มีประโยชน์สำหรับบริบท เช่น ช่องอีเมลที่มี pattern
ที่ต้องตรงกัน เพื่อให้เป็นช่องที่ถูกต้อง สถานะค่าที่ถูกต้องนี้จะแสดงต่อผู้ใช้ เพื่อช่วยให้ผู้ใช้ทราบว่าสามารถไปยังช่องถัดไปได้อย่างปลอดภัย
:in-range
คลาสจำลองจะพร้อมใช้งานหากอินพุตมี min
และ max
เช่น อินพุตตัวเลขและค่าอยู่ในขอบเขตเหล่านั้น
แบบฟอร์ม HTML ช่วยให้คุณกำหนดได้ว่าต้องกรอกฟิลด์ใดด้วยแอตทริบิวต์ required
:required
คลาสเสมือนจะใช้ได้กับช่องที่ต้องกรอก เลือกช่องที่ไม่บังคับได้ด้วยคลาสเทียม :optional
การเลือกองค์ประกอบตามดัชนี ลำดับ และการเกิด
มีกลุ่มคลาสเสมือนที่เลือกรายการตามตำแหน่งในเอกสาร
:first-child
และ :last-child
หากต้องการค้นหารายการแรกหรือรายการสุดท้าย คุณสามารถใช้ :first-child
และ :last-child
คลาสจำลองเหล่านี้จะแสดงผลองค์ประกอบแรกหรือองค์ประกอบสุดท้ายในกลุ่มขององค์ประกอบร่วม
:only-child
นอกจากนี้ คุณยังเลือกองค์ประกอบที่ไม่มีองค์ประกอบระดับเดียวกันได้ด้วย โดยใช้ :only-child
Pseudo-Class
:first-of-type
และ :last-of-type
คุณเลือก :first-of-type
และ :last-of-type
ได้ ซึ่งในตอนแรก อาจดูเหมือนว่าทำหน้าที่เดียวกันกับ :first-child
และ :last-child
แต่ลองพิจารณา HTML นี้
<div class="my-parent"> <p>A paragraph</p> <div>A div</div> <div>Another div</div> </div>
และ CSS นี้
.my-parent div:first-child { color: red; }
ไม่มีองค์ประกอบใดที่จะเป็นสีแดงเนื่องจากองค์ประกอบย่อยแรกเป็นย่อหน้า ไม่ใช่ div คลาสเสมือน :first-of-type
มีประโยชน์ในบริบทนี้
.my-parent div:first-of-type { color: red; }
แม้ว่า <div>
แรกจะเป็นองค์ประกอบย่อยที่ 2 แต่ก็ยังเป็นองค์ประกอบแรกของประเภทภายในองค์ประกอบ .my-parent
ดังนั้นกฎนี้จะทำให้องค์ประกอบดังกล่าวมีสีแดง
:nth-child
และ :nth-of-type
คุณไม่จำเป็นต้องจำกัดเฉพาะลูกคนแรกและคนสุดท้าย รวมถึงประเภทของลูก คลาสเสมือน :nth-child
และ :nth-of-type
ช่วยให้คุณระบุองค์ประกอบที่ดัชนีหนึ่งๆ ได้ การจัดทำดัชนีในตัวเลือก CSS จะเริ่มต้นที่ 1
คลาสเสมือน :nth-last-child()
และ :nth-last-of-type()
จะนับจากท้ายแทนที่จะนับจากต้น
คุณยังส่งค่ามากกว่าดัชนีไปยัง Pseudo-Class เหล่านี้ได้ด้วย หากต้องการเลือกองค์ประกอบคู่ทั้งหมด คุณสามารถใช้ :nth-child(even)
ได้
นอกจากนี้ คุณยังสร้างตัวเลือกที่ซับซ้อนมากขึ้นซึ่งค้นหารายการในช่วงเวลาที่เว้นระยะอย่างสม่ำเสมอได้ โดยใช้รูปแบบย่อย An+B
li:nth-child(3n+3) { background: yellow; }
ตัวเลือกนี้จะเลือกทุกๆ รายการที่ 3 โดยเริ่มจากรายการที่ 3 n
ในนิพจน์นี้คือดัชนี ซึ่งเริ่มต้นที่ 0 และ 3 (3n
) คือจำนวนที่คุณคูณดัชนีนั้น
สมมติว่าคุณมีไอเทม <li>
จำนวน 7 รายการ รายการแรกที่เลือกคือ 3 เนื่องจาก 3n+3
แปลงเป็น (3 * 0) + 3
การวนซ้ำครั้งถัดไปจะเลือกรายการที่ 6 เนื่องจากตอนนี้ n
เพิ่มขึ้นเป็น 1
จึงเป็น (3 * 1) + 3)
นิพจน์นี้ใช้ได้กับทั้ง :nth-child
และ :nth-of-type
:nth-child()
และ :nth-last-child()
ยังรองรับไวยากรณ์ "of S" ที่ช่วยให้คุณกรองการจับคู่ด้วยตัวเลือกได้เช่นเดียวกับ :nth-of-type()
li:nth-of-type(even)
มีค่าเท่ากับ :nth-child(even of li)
แม้ว่า :nth-of-type
จะอนุญาตให้คุณกรองตามประเภทองค์ประกอบเท่านั้น (เช่น li
หรือ p
) แต่ไวยากรณ์ "of S" จะอนุญาตให้คุณกรองในตัวเลือกใดก็ได้
หากมีตาราง คุณอาจต้องการเพิ่มแถบในทุกๆ แถว แม้ว่าคุณจะกำหนดเป้าหมายทุกๆ แถวด้วยtr:nth-child(even)
ได้ แต่จะใช้ไม่ได้หากคุณกรองบางแถวออก หากใช้การกรองโดยใช้แอตทริบิวต์ hidden
คุณจะเพิ่ม of :not([hidden])
ลงในตัวเลือกเพื่อกรองรายการที่ซ่อนไว้ล่วงหน้าก่อนที่จะเลือกแถวคู่ได้
tr:nth-child(even of :not([hidden])){ background: lightgrey; }
คุณลองใช้ตัวเลือกประเภทนี้ได้ในเครื่องมือทดสอบ nth-child หรือเครื่องมือเลือกจำนวน
:only-of-type
สุดท้ายนี้ คุณสามารถค้นหาองค์ประกอบเดียวของประเภทหนึ่งๆ ในกลุ่มองค์ประกอบที่อยู่ระดับเดียวกันได้ด้วย :only-of-type
ซึ่งจะมีประโยชน์หากคุณต้องการเลือกรายการที่มีเพียง 1 รายการ หรือหากต้องการค้นหาองค์ประกอบตัวหนาเพียงรายการเดียวในย่อหน้า
ค้นหาองค์ประกอบที่ว่างเปล่า
บางครั้งการระบุองค์ประกอบที่ว่างเปล่าโดยสมบูรณ์ก็มีประโยชน์ และมี Pseudo-Class สำหรับการดำเนินการดังกล่าวด้วย
:empty
หากองค์ประกอบไม่มีองค์ประกอบย่อย ระบบจะใช้เพชรโดคลาส :empty
กับองค์ประกอบนั้น อย่างไรก็ตาม องค์ประกอบย่อยไม่ได้เป็นเพียงองค์ประกอบ HTML หรือโหนดข้อความเท่านั้น แต่ยังเป็นช่องว่างได้ด้วย ซึ่งอาจทำให้สับสนเมื่อคุณกำลังแก้ไขข้อบกพร่องของ HTML ต่อไปนี้และสงสัยว่าเหตุใดจึงใช้กับ :empty
ไม่ได้
<div> </div>
เนื่องจากมีช่องว่างระหว่างแท็กเปิดและแท็กปิด <div>
:empty
จึงใช้งานไม่ได้
:empty
คลาสเสมือนอาจมีประโยชน์หากคุณควบคุม HTML ได้น้อยและต้องการซ่อนองค์ประกอบที่ว่างเปล่า เช่น เครื่องมือแก้ไขเนื้อหาแบบ WYSIWYG ในที่นี้ ผู้แก้ไขได้เพิ่มย่อหน้าที่ว่างเปล่า
<article class="post"> <p>Donec ullamcorper nulla non metus auctor fringilla.</p> <p></p> <p>Curabitur blandit tempus porttitor.</p> </article>
:empty
ช่วยให้คุณค้นหาและซ่อนข้อมูลดังกล่าวได้
.post :empty { display: none; }
การค้นหาและยกเว้นหลายองค์ประกอบ
คลาสเสมือนบางคลาสช่วยให้คุณเขียน CSS ได้กะทัดรัดยิ่งขึ้น
:is()
หากต้องการค้นหาองค์ประกอบย่อย h2
, li
และ img
ทั้งหมดในองค์ประกอบ .post
คุณอาจคิดที่จะเขียนรายการตัวเลือกดังนี้
.post h2, .post li, .post img { … }
คุณสามารถเขียนเวอร์ชันที่กระชับกว่าได้ด้วย:is()
คลาสหลอก
.post :is(h2, li, img) { /* ... */ }
คลาสเสมือน :is
ไม่เพียงกะทัดรัดกว่ารายการตัวเลือก แต่ยังมีความยืดหยุ่นมากกว่าด้วย ในกรณีส่วนใหญ่ หากมีข้อผิดพลาดหรือตัวเลือกที่ไม่รองรับในรายการตัวเลือก รายการตัวเลือกทั้งหมดจะใช้งานไม่ได้อีกต่อไป หากมีข้อผิดพลาดในตัวเลือกที่ส่งผ่านในคลาสเทียม :is
ระบบจะละเว้นตัวเลือกที่ไม่ถูกต้อง แต่จะใช้ตัวเลือกที่ถูกต้อง
:not()
นอกจากนี้ คุณยังยกเว้นรายการด้วยคลาสเทียม :not()
ได้ด้วย เช่น คุณสามารถใช้เพื่อจัดรูปแบบลิงก์ทั้งหมดที่ไม่มีแอตทริบิวต์ class
a:not([class]) { color: blue; }
:not
คลาสจำลองยังช่วยปรับปรุงการช่วยเหลือพิเศษได้ด้วย เช่น <img>
ต้องมี alt
แม้ว่าจะเป็นค่าว่างก็ตาม เพื่อให้คุณเขียนกฎ CSS ที่เพิ่มเส้นขอบสีแดงหนาให้กับรูปภาพที่ไม่ถูกต้องได้
img:not([alt]) { outline: 10px red; }
:has()
จะเกิดอะไรขึ้นหากคุณต้องการจัดรูปแบบองค์ประกอบตามสิ่งที่อยู่ภายในองค์ประกอบนั้น คุณใช้:has()
คลาสจำลองเพื่อทำสิ่งนั้นได้ เช่น คุณอาจต้องการใช้สไตล์กับปุ่มที่มีไอคอน
button:has(svg) { /* ... */ }
ในการกำหนดค่าพื้นฐานที่สุด เช่น ในตัวอย่างก่อนหน้า คุณสามารถคิดว่า :has()
เป็นตัวเลือกหลัก นอกจากนี้ คุณยังใช้ตัวเลือกองค์ประกอบหลักที่ตรงกันร่วมกับตัวเลือกอื่นๆ เพื่อกำหนดเป้าหมายองค์ประกอบอื่นๆ ได้ด้วย
form:has(input:valid) label { font-weight: bold; } form:has(input:valid) label::after { content: "✅"; }
ในตัวอย่างนี้ เราจะใช้สไตล์กับองค์ประกอบป้ายกำกับและองค์ประกอบเสมือน label::after
เมื่ออินพุตของแบบฟอร์มมีคลาสเสมือน valid
:has()
คลาสเสมือน:has()
จะซ้อนอยู่ภายใน:has()
คลาสเสมือน:has()
อื่นไม่ได้ แต่ใช้ร่วมกับคลาสเสมือนอื่นๆ ได้
:is(h1, h2, h3):has(a) { /* ... */ }
รายการตัวเลือกไม่ยอมให้มีข้อผิดพลาด ดังนั้นหากตัวเลือกใดในรายการไม่ถูกต้อง ระบบจะละเว้นกฎสไตล์ทั้งหมด
.my-element:has(img, ::before) { /* any styles here will be discarded since pseudo elements can't be included in the :has() selector list */ }
ทดสอบความเข้าใจ
ทดสอบความรู้เกี่ยวกับคลาสเสมือน
คลาสเสมือนจะทำหน้าที่ราวกับว่ามีการใช้คลาสกับองค์ประกอบแบบไดนามิก ในขณะที่องค์ประกอบเสมือนจะทำหน้าที่กับองค์ประกอบนั้นๆ เอง
:
แบบเดี่ยวหรือคู่เป็นอักขระสำคัญที่ใช้แยกความแตกต่างในตัวเลือกข้อใดต่อไปนี้เป็นคลาสเสมือนฟังก์ชัน
:is()
:target
()
ต่อท้ายเพื่อระบุว่ายอมรับพารามิเตอร์:empty
()
ต่อท้ายเพื่อระบุว่ายอมรับพารามิเตอร์:not()
Pseudo-class ใดต่อไปนี้เกิดจากการโต้ตอบของผู้ใช้
:hover
:press
:squeeze
:target
:focus-within
<form>
ใดต่อไปนี้คือคลาสเทียมของสถานะ
:enabled
:fresh
:indeterminate
:checked
:in-range
:loading
:valid