คำแนะนำสำหรับ CSS Pseudo-Class Selectors ที่ทันสมัยและรองรับใหม่
เผยแพร่แล้ว: 2022-03-10 ตัวเลือกคลาสหลอกคือตัวเลือกที่ขึ้นต้นด้วยอักขระโคลอน “ : ” และจับคู่ตาม สถานะ ขององค์ประกอบปัจจุบัน สถานะอาจสัมพันธ์กับแผนผังเอกสาร หรือเพื่อตอบสนองต่อการเปลี่ยนแปลงสถานะ เช่น :hover หรือ :checked
:any-link
แม้ว่าจะกำหนดไว้ใน Selectors ระดับ 4 แต่คลาสหลอกนี้มีการสนับสนุนข้ามเบราว์เซอร์มาระยะหนึ่งแล้ว pseudo-class ของ any-link จะจับคู่กับ anchor hyperlink ตราบใดที่มี href มันจะจับคู่ในลักษณะที่เทียบเท่ากับการจับคู่ทั้ง :link และ :visited พร้อมกัน โดยพื้นฐานแล้ว การทำเช่นนี้อาจลดสไตล์ของคุณลงได้เพียงตัวเลือกเดียว หากคุณกำลังเพิ่มคุณสมบัติพื้นฐาน เช่น color ที่คุณต้องการใช้กับลิงก์ทั้งหมดโดยไม่คำนึงถึงสถานะที่เข้าชม
:any-link { color: blue; text-underline-offset: 0.05em; } หมายเหตุสำคัญเกี่ยวกับความจำเพาะคือ :any-link จะชนะ a เป็นตัวเลือก แม้ว่า a จะถูกวางไว้ที่ต่ำกว่าในคาสเคด เนื่องจากมีความเฉพาะเจาะจงของคลาส ในตัวอย่างต่อไปนี้ ลิงก์จะเป็นสีม่วง:
:any-link { color: purple; } a { color: red; } ดังนั้น หากคุณแนะนำ :any-link โปรดทราบว่าคุณจะต้องรวมไว้ในอินสแตนซ์ของ a เป็นตัวเลือก หากพวกเขาจะอยู่ในการแข่งขันโดยตรงสำหรับความเฉพาะเจาะจง
:focus-visible
ฉันพนันได้เลยว่าการละเมิดการช่วยสำหรับการเข้าถึงที่พบบ่อยที่สุดอย่างหนึ่งในเว็บคือการลบ outline ขององค์ประกอบเชิงโต้ตอบ เช่น ลิงก์ ปุ่ม และอินพุตของแบบฟอร์มสำหรับสถานะ :focus จุดประสงค์หลักประการหนึ่งของ outline นั้นคือเพื่อใช้เป็นตัวบ่งชี้ที่มองเห็นได้สำหรับผู้ใช้ที่ใช้แป้นพิมพ์เป็นหลักในการนำทาง สถานะการโฟกัสที่มองเห็นได้นั้นมีความสำคัญ ในฐานะเครื่องมือในการค้นหาเส้นทาง เนื่องจากผู้ใช้เหล่านั้นแท็บผ่านอินเทอร์เฟซ และเพื่อช่วยเสริมว่าองค์ประกอบแบบโต้ตอบคืออะไร โดยเฉพาะอย่างยิ่ง การโฟกัสที่มองเห็นได้ครอบคลุมอยู่ในเกณฑ์ความสำเร็จ WCAG 2.4.11: ลักษณะที่ปรากฏของโฟกัส (ขั้นต่ำ)
คลาสหลอก :focus-visible มีวัตถุประสงค์เพื่อแสดงเฉพาะวงแหวนโฟกัสเมื่อตัวแทนผู้ใช้กำหนดผ่านฮิวริสติกว่าควรมองเห็นได้ กล่าวอีกนัยหนึ่ง: เบราว์เซอร์จะกำหนดว่า เมื่อใดควรใช้ :focus-visible ตามวิธีการป้อนข้อมูล ประเภทขององค์ประกอบ และบริบทของการโต้ตอบ สำหรับวัตถุประสงค์ในการทดสอบผ่านคอมพิวเตอร์เดสก์ท็อปที่มีการป้อนข้อมูลด้วยแป้นพิมพ์และเมาส์ คุณควรเห็น :focus-visible styles แนบมาเมื่อคุณแท็บในองค์ประกอบแบบโต้ตอบ แต่ไม่ใช่เมื่อคุณคลิก ยกเว้นการป้อนข้อความและ textareas ซึ่งควรแสดง :focus-visible สำหรับอินพุตโฟกัสทุกประเภท
หมายเหตุ : สำหรับรายละเอียดเพิ่มเติม ตรวจสอบร่างการทำงานของ :focus-visible spec
เวอร์ชันล่าสุดของเบราว์เซอร์ Firefox และ Chromium ดูเหมือนจะจัดการ :focus-visible บนอินพุตของฟอร์มตามข้อกำหนดที่ระบุว่า UA ควรลบ :focus styles เมื่อ :focus-visible ตรงกัน Safari ยังไม่รองรับ :focus-visible ดังนั้นเราจำเป็นต้องตรวจสอบให้แน่ใจว่าสไตล์ :focus ถูกรวมไว้เป็นทางเลือกเพื่อหลีกเลี่ยงการลบ outline สำหรับการช่วยสำหรับการเข้าถึง
ด้วยปุ่มและการป้อนข้อความที่มีชุดสไตล์ต่อไปนี้ มาดูกันว่าจะเกิดอะไรขึ้น:
input:focus, button:focus { outline: 2px solid blue; outline-offset: 0.25em; } input:focus-visible { outline: 2px solid transparent; border-color: blue; } button:focus:not(:focus-visible) { outline: none; } button:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 2px #fff, 0 0 0 4px blue; }Chromium และ Firefox
-
input
ลบ:focusstyles อย่างถูกต้องเมื่อองค์ประกอบถูกโฟกัสผ่านการป้อนข้อมูลด้วยเมาส์:focus-visibleส่งผลให้เปลี่ยนborder-colorและซ่อนoutlineในการป้อนข้อมูลด้วยแป้นพิมพ์ -
button
ไม่เพียงใช้:focus-visibleโดยไม่มีกฎเพิ่มเติมสำหรับbutton:focus:not(:focus-visible)ที่จะลบโครงร่างบน:focusแต่จะอนุญาตให้มองเห็นbox-shadowเฉพาะเมื่อป้อนข้อมูลด้วยแป้นพิมพ์
ซาฟารี
-
input
ใช้เฉพาะ:focusstyles . เท่านั้น -
button
ดูเหมือนว่า ตอนนี้จะเคารพจุดประสงค์ของ:focus-visibleบนปุ่มบางส่วนโดยการซ่อน:focusลักษณะเมื่อคลิก แต่ยังคงแสดง:focusลักษณะในการโต้ตอบของแป้นพิมพ์
ดังนั้น สำหรับตอนนี้ คำแนะนำคือให้ดำเนินการต่อโดยใส่ :focus styles แล้วค่อยๆ ปรับปรุงเป็น :focus-visible ซึ่งโค้ดสาธิตอนุญาต นี่คือ CodePen สำหรับคุณในการทดสอบต่อ:
ดู Pen [การทดสอบแอปพลิเคชันของ :focus-visible](https://codepen.io/smashingmag/pen/MWJZbew) โดย Stephanie Eckles
:focus-within
:focus-within pseudo-class รองรับเบราว์เซอร์สมัยใหม่ทั้งหมด และทำหน้าที่ เกือบจะ เหมือนกับตัวเลือกพาเรนต์ แต่สำหรับเงื่อนไขที่เฉพาะเจาะจงมากเท่านั้น เมื่อแนบกับองค์ประกอบที่มีและองค์ประกอบย่อยตรงกับ :focus คุณสามารถเพิ่มสไตล์ไปยังองค์ประกอบที่มี และ/หรือ องค์ประกอบอื่นๆ ภายในคอนเทนเนอร์ได้
การปรับปรุงที่ใช้งานได้จริงเพื่อใช้ลักษณะการทำงานนี้คือ การกำหนดสไตล์ป้ายชื่อแบบฟอร์ม เมื่ออินพุตที่เกี่ยวข้องมีโฟกัส เพื่อให้ใช้งานได้ เราห่อป้ายกำกับและป้อนข้อมูลในคอนเทนเนอร์ จากนั้นแนบ :focus-within คอนเทนเนอร์นั้นรวมถึงการเลือกป้ายกำกับ:
.form-group:focus-within label { color: blue; }ส่งผลให้ป้ายกำกับเปลี่ยนเป็นสีน้ำเงินเมื่ออินพุตมีโฟกัส
การสาธิต CodePen นี้ยังรวมถึงการเพิ่มโครงร่างโดยตรงไปยัง .form-group :
ดู Pen [การทดสอบแอปพลิเคชันของ :focus-within](https://codepen.io/smashingmag/pen/xxgmREq) โดย Stephanie Eckles
:is()
ยังเป็นที่รู้จักกันในนาม "ตรงกับคลาสหลอก" ใด ๆ :is() สามารถใช้รายการตัวเลือกเพื่อพยายามจับคู่ ตัวอย่างเช่น แทนที่จะแสดงรายการสไตล์ส่วนหัวทีละรายการ คุณสามารถจัดกลุ่มไว้ใต้ตัวเลือกของ :is(h1, h2, h3)
พฤติกรรมเฉพาะสองสามอย่างเกี่ยวกับรายการตัวเลือก :is() :
- หากตัวเลือกที่ระบุไม่ถูกต้อง กฎจะยังคงตรงกับตัวเลือกที่ถูกต้อง ให้
:is(-ua-invalid, article, p)กฎจะจับคู่articleและp - ความจำเพาะที่คำนวณได้จะเท่ากับตัวเลือกที่ผ่านด้วยความจำเพาะสูงสุด ตัวอย่างเช่น
:is(#id, p)จะมีความจำเพาะของ#id— 1.0.0 — ในขณะที่:is(p, a)จะมีความจำเพาะที่ 0.0.1
พฤติกรรมแรกของการละเว้นตัวเลือกที่ไม่ถูกต้องคือข้อดีหลัก เมื่อใช้ตัวเลือกอื่นในกลุ่มที่ตัวเลือกหนึ่งไม่ถูกต้อง เบราว์เซอร์จะลบกฎทั้งหมดออก สิ่งนี้มีผลบังคับใช้ในบางกรณีที่คำนำหน้าผู้ขายยังคงจำเป็น และการจัดกลุ่มตัวเลือกคำนำหน้าและตัวเลือกที่ไม่ใช่คำนำหน้าจะทำให้กฎล้มเหลวในทุกเบราว์เซอร์ ด้วย :is() คุณสามารถจัดกลุ่มสไตล์เหล่านั้นได้อย่างปลอดภัย และจะนำไปใช้เมื่อจับคู่และจะถูกละเว้นเมื่อไม่ตรงกัน
สำหรับฉัน การจัดกลุ่มสไตล์ส่วนหัว ตามที่กล่าวไว้ก่อนหน้านี้ถือเป็นชัยชนะครั้งใหญ่สำหรับตัวเลือกนี้ นอกจากนี้ยังเป็นประเภทของกฎที่ฉันรู้สึกสบายใจที่จะใช้โดยไม่มีทางเลือกเมื่อใช้รูปแบบที่ไม่สำคัญ เช่น:

:is(h1, h2, h3) { line-height: 1.2; } :is(h2, h3):not(:first-child) { margin-top: 2em; } ในตัวอย่างนี้ (ซึ่งมาจากรูปแบบเอกสารในโปรเจ็กต์ SmolCSS ของฉัน) การมีความสูงของ line-height สืบทอดมาจากสไตล์พื้นฐานหรือการไม่มี margin-top นั้นไม่ใช่ปัญหาสำหรับเบราว์เซอร์ที่ไม่รองรับ มันน้อยกว่าอุดมคติ สิ่งที่คุณไม่ต้องการใช้ :is() สำหรับค่อนข้างจะเป็น สไตล์เลย์เอาต์ที่สำคัญ เช่น Grid หรือ Flex ที่ควบคุมอินเทอร์เฟซของคุณอย่างมาก
นอกจากนี้ เมื่อเชื่อมโยงกับตัวเลือกอื่น คุณสามารถทดสอบว่าตัวเลือกฐานตรงกับตัวเลือกสืบทอดภายใน :is() หรือไม่ ตัวอย่างเช่น กฎต่อไปนี้จะเลือกเฉพาะย่อหน้าที่เป็นทายาทโดยตรงของบทความ ใช้ตัวเลือกสากลเพื่ออ้างอิงถึงตัวเลือกฐาน p
p:is(article > *) สำหรับการสนับสนุนในปัจจุบันที่ดีที่สุด หากคุณต้องการเริ่มใช้งาน คุณจะต้อง เพิ่มสไตล์เป็นสองเท่า โดยใส่กฎที่ซ้ำกันโดยใช้ :-webkit-any() และ :matches() อย่าลืมสร้างกฎแต่ละข้อเหล่านี้ หรือแม้แต่เบราว์เซอร์ที่รองรับก็ปล่อยมันไป! กล่าวอีกนัยหนึ่ง ให้รวมสิ่งต่อไปนี้ทั้งหมด:
:matches(h1, h2, h3) { } :-webkit-any(h1, h2, h3) { } :is(h1, h2, h3) { } มูลค่าการกล่าวขวัญ ณ จุดนี้ก็คือว่าพร้อมกับตัวเลือกที่ใหม่กว่านั้นคือรูปแบบที่อัปเดตของ @supports ซึ่งก็คือ @supports selector สิ่งนี้มีให้เช่นกันเนื่องจาก @supports not selector
หมายเหตุ : ในปัจจุบัน (ของเบราว์เซอร์รุ่นใหม่) มีเพียง Safari เท่านั้นที่ไม่รองรับ at-rule
คุณสามารถตรวจสอบ :is() support ด้วยสิ่งต่อไปนี้ แต่จริง ๆ แล้วคุณจะสูญเสียการสนับสนุน Safari เนื่องจาก Safari รองรับ :is() แต่ไม่รองรับ @supports selector
@supports selector(:is(h1)) { :is(h1, h2, h3) { line-height: 1.1; } } :where()
pseudo-class :where() เกือบจะเหมือนกับ :is() ยกเว้นข้อแตกต่างที่สำคัญอย่างหนึ่ง: มันจะมีความเฉพาะเจาะจงเป็นศูนย์ เสมอ สิ่งนี้มีความหมายที่เหลือเชื่อสำหรับ ผู้ที่กำลังสร้างเฟรมเวิร์ก ธีม และระบบการออกแบบ การใช้ :where() ผู้เขียนสามารถตั้งค่าเริ่มต้น และนักพัฒนาดาวน์สตรีมสามารถรวมการแทนที่หรือส่วนขยายได้โดยไม่ขัดแย้งกันเฉพาะเจาะจง
พิจารณาชุดสไตล์ img ต่อไปนี้ การใช้ :where() แม้จะมีตัวเลือกความจำเพาะสูง ความจำเพาะก็ยังเป็นศูนย์ ในตัวอย่างต่อไปนี้ คุณคิดว่าภาพจะมีเส้นขอบสีใด
:where(article img:not(:first-child)) { border: 5px solid red; } :where(article) img { border: 5px solid green; } img { border: 5px solid orange; } กฎข้อแรกมีความเฉพาะเจาะจงเป็นศูนย์ เนื่องจากมีทั้งหมดอยู่ภายใน :where() ดังนั้นตรงข้ามกฎข้อที่สองโดยตรง กฎข้อที่สองชนะ ขอแนะนำตัวเลือกเฉพาะองค์ประกอบ img ตามกฎสุดท้าย มันจะชนะเนื่องจากการเรียงซ้อน นี่เป็นเพราะมันจะคำนวณให้มีความจำเพาะเช่นเดียวกับกฎ :where(article) img เนื่องจากส่วน :where() ไม่เพิ่มความเฉพาะเจาะจง
การใช้ :where() ควบคู่ไปกับทางเลือกจะยากขึ้นเล็กน้อยเนื่องจากคุณลักษณะที่ไม่เฉพาะเจาะจงเป็นศูนย์ เนื่องจากคุณลักษณะดังกล่าวมีแนวโน้มว่าเหตุใดคุณจึง ต้องการ ใช้แทน :is() และหากคุณเพิ่มกฎทางเลือก กฎเหล่านั้นมีแนวโน้มที่จะเอาชนะ :where() เนื่องจากธรรมชาติของมันเอง และมี การสนับสนุนโดยรวมที่ดี กว่า @supports selector ดังนั้นการพยายามใช้สิ่งนั้นเพื่อสร้างทางเลือกสำรองไม่น่าจะให้ผลกำไรมากนัก (ถ้ามี) โดยพื้นฐานแล้ว ให้ระวังการไม่สามารถสร้างทางเลือกสำหรับ :where() ได้อย่างถูกต้อง และตรวจสอบข้อมูลของคุณเองอย่างถี่ถ้วนเพื่อพิจารณาว่าการเริ่มใช้สำหรับผู้ชมเฉพาะของคุณนั้นปลอดภัยหรือไม่
คุณสามารถทดสอบเพิ่มเติม :where() ด้วย CodePen ต่อไปนี้ซึ่งใช้ตัวเลือก img จากด้านบน:
ดูปากกา [การทดสอบ `:where()` ความจำเพาะ](https://codepen.io/smashingmag/pen/jOyXVMg) โดย Stephanie Eckles
:where() โดย Stephanie Eckles ปรับปรุง :not()
ตัวเลือกพื้นฐาน :not() ได้รับการสนับสนุนตั้งแต่ Internet Explorer 9 แต่ตัวเลือกระดับ 4 ปรับปรุง :not() โดยอนุญาตให้ใช้รายการตัวเลือก เช่นเดียวกับ :is() และ :where()
กฎต่อไปนี้ให้ผลลัพธ์เดียวกันในการสนับสนุนเบราว์เซอร์:
article :not(h2):not(h3):not(h4) { margin-bottom: 1.5em; } article :not(h2, h3, h4) { margin-bottom: 1.5em; } ความสามารถของ :not() ในการยอมรับรายการตัวเลือกมีการสนับสนุนเบราว์เซอร์ที่ทันสมัยอย่างมาก
ตามที่เราเห็นด้วย :is() ที่ปรับปรุงแล้ว :not() สามารถมีการอ้างอิงไปยังตัวเลือกฐานในฐานะผู้สืบทอดโดยใช้ * CodePen นี้แสดงให้เห็นถึงความสามารถนี้โดยการเลือกลิงก์ที่ ไม่ใช่ ลูกหลานของ nav
ดูปากกา [การทดสอบ :not() ด้วยตัวเลือกสืบทอด](https://codepen.io/smashingmag/pen/BapvQQv) โดย Stephanie Eckles
โบนัส : ตัวอย่างก่อนหน้านี้ยังรวมถึงตัวอย่างของการเชื่อมโยง :not() และ :is() เพื่อเลือกรูปภาพที่ไม่ใช่พี่น้องที่อยู่ติดกันขององค์ประกอบ h2 หรือ h3
เสนอแต่ “เสี่ยง” — :has()
pseudo-class สุดท้ายที่เป็นข้อเสนอที่น่าตื่นเต้นมาก แต่ไม่มีเบราว์เซอร์ปัจจุบันที่ใช้งานแม้ในวิธีทดลองคือ :has() อันที่จริง มันถูกระบุไว้ในตัวเลือกระดับ 4 Editor's Draft ว่า "มีความเสี่ยง" ซึ่งหมายความว่าเป็นที่ยอมรับว่ามีปัญหาในการดำเนินการให้เสร็จสิ้น ดังนั้นจึง อาจ ถูกละทิ้งจากคำแนะนำ
หากนำไปใช้งาน :has() จะเป็น "ตัวเลือกหลัก" ที่ CSS หลายคนปรารถนาจะมีให้ใช้งาน มันจะทำงานด้วยตรรกะที่คล้ายกับการรวมกันของทั้ง :focus-within และ :is() กับตัวเลือกการสืบทอด ซึ่งคุณกำลังมองหาการ ปรากฏตัวของผู้สืบทอด แต่สไตล์ที่ปรับใช้จะเป็นองค์ประกอบหลัก
จากกฎต่อไปนี้ หากการนำทางมีปุ่ม การนำทางจะลดช่องว่างด้านบนและด้านล่าง:
nav { padding: 0.75rem 0.25rem; nav:has(button) { padding-top: 0.25rem; padding-bottom: 0.25rem; }ขอย้ำอีกครั้งว่า ฟีเจอร์นี้ยัง ไม่ได้ ใช้งานในเบราว์เซอร์ใด ๆ แม้แต่ในการทดลอง — แต่ก็สนุกที่จะลองคิดดู! Robin Rendle ให้ข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับตัวเลือกในอนาคตนี้ใน CSS-Tricks
รางวัลชมเชยจากระดับ 3: :empty
คลาสหลอกที่มีประโยชน์ที่คุณอาจพลาดจากตัวเลือกระดับ 3 คือ :empty ซึ่งตรงกับองค์ประกอบเมื่อ ไม่มี องค์ประกอบย่อย ซึ่งรวมถึงโหนดข้อความ
กฎ p:empty จะจับคู่ <p></p> แต่ไม่ตรงกับ <p>Hello</p>
วิธีหนึ่งที่คุณสามารถใช้ :empty คือการซ่อนองค์ประกอบที่อาจเป็นตัวยึดตำแหน่งสำหรับเนื้อหาแบบไดนามิกที่เติมด้วย JavaScript บางทีคุณอาจมี div ที่จะได้รับผลการค้นหา และเมื่อมีการเติมข้อมูลแล้ว ก็จะมีเส้นขอบและช่องว่างภายในบางส่วน แต่หากยังไม่มีผลลัพธ์ คุณคงไม่ต้องการให้ใช้พื้นที่บนหน้า การใช้ :empty คุณสามารถซ่อนด้วย:
.search-results:empty { display: none; } คุณอาจกำลังคิดที่จะเพิ่มข้อความในสถานะว่างและต้องการเพิ่มข้อความด้วยองค์ประกอบหลอกและ content ข้อผิดพลาดในที่นี้คือ ข้อความอาจไม่พร้อมใช้งานสำหรับผู้ใช้เทคโนโลยีอำนวยความสะดวก ซึ่งไม่สอดคล้องกับว่าพวกเขาสามารถเข้าถึง content ได้หรือไม่ กล่าวอีกนัยหนึ่ง เพื่อ ให้แน่ใจว่าข้อความประเภท "ไม่มีผลลัพธ์" สามารถเข้าถึงได้ คุณจะต้องเพิ่มสิ่งนั้นเป็นองค์ประกอบจริง เช่น ย่อหน้า (จะไม่สามารถเข้าถึง aria-label สำหรับ div ที่ซ่อนอยู่ได้อีกต่อไป)
แหล่งข้อมูลสำหรับการเรียนรู้เกี่ยวกับ Selectors
CSS มีตัวเลือกอีกมากมายรวมถึงคลาสหลอก ต่อไปนี้เป็นสถานที่เพิ่มเติมสองสามแห่งเพื่อเรียนรู้เพิ่มเติมเกี่ยวกับสิ่งที่มีอยู่:
- เอกสารประกอบตัวเลือก MDN CSS มีรายการหมวดหมู่ที่ครอบคลุม
- ฉันได้เขียนคู่มือสองส่วนสำหรับตัวเลือก CSS ขั้นสูง คุณสามารถเริ่มต้นด้วยส่วนที่หนึ่ง
- สนุกกับการเรียนรู้เกี่ยวกับตัวเลือก CSS กับเกม CSS Diner;
- Kitty Giraudel ได้สร้างเครื่องมือคำอธิบายตัวเลือกที่จะแยกย่อยและอธิบายส่วนต่างๆ ของตัวเลือกที่ให้มา
