พอดแคสต์ CSS - 003: ความเฉพาะเจาะจง
สมมติว่าคุณกำลังทำงานกับ HTML และ CSS ต่อไปนี้
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
ในที่นี้มีกฎ 2 ข้อที่กำหนดเป้าหมายเป็นองค์ประกอบเดียวกัน กฎแต่ละข้อมีการประกาศที่ต้องการกำหนดสีของปุ่ม โดยกฎหนึ่งพยายามกำหนดสีปุ่มเป็นสีแดง และอีกกฎหนึ่งพยายามกำหนดสีปุ่มเป็นสีน้ำเงิน การประกาศใดที่จะนำไปใช้กับองค์ประกอบ
การทำความเข้าใจอัลกอริทึมความเฉพาะเจาะจงของ CSS เป็นกุญแจสำคัญในการทำความเข้าใจวิธีที่ CSS ตัดสินใจเลือกการประกาศที่แข่งขันกัน
ความเฉพาะเจาะจงเป็นหนึ่งในขั้นตอนที่แตกต่างกันของ Cascade ซึ่งเราได้กล่าวถึงในโมดูลที่แล้วในหัวข้อ Cascade
การให้คะแนนความเฉพาะเจาะจง
กฎตัวเลือกแต่ละข้อภายใน ต้นทาง จะได้รับการให้คะแนน คุณสามารถคิดว่าความเฉพาะเจาะจงเป็นคะแนนรวม และตัวเลือกแต่ละประเภทจะได้รับคะแนนสำหรับคะแนนรวมนั้น การประกาศจากกฎที่มีความเฉพาะเจาะจงสูงสุดจะเป็นผู้ชนะ
ความเฉพาะเจาะจงในโปรเจ็กต์จริงคือการสร้างความสมดุลเพื่อให้แน่ใจว่ากฎ CSS ที่คุณต้องการนำไปใช้ จะถูกนำไปใช้จริง ในขณะเดียวกันก็พยายามรักษาระดับคะแนนให้ต่ำเพื่อป้องกันความซับซ้อน ความเฉพาะเจาะจงควรสูงเท่าที่เราต้องการเท่านั้น ไม่ใช่พยายามให้มีความเฉพาะเจาะจงสูงสุดเท่าที่จะเป็นไปได้ เนื่องจากในอนาคตอาจต้องนำ CSS ที่สำคัญกว่ามาใช้ หากคุณเลือกความเฉพาะเจาะจงสูงสุด คุณจะทำให้งานนั้นยากขึ้น
ความเฉพาะเจาะจงไม่ใช่เลขทศนิยม แต่เป็นสามสิ่งประกอบด้วย 3 องค์ประกอบ ได้แก่ A, B และ C
A: ความเฉพาะเจาะจงแบบรหัสB: ความเฉพาะเจาะจงแบบคลาสC: ความเฉพาะเจาะจงแบบองค์ประกอบ
โดยมักแสดงด้วยสัญกรณ์ (A,B,C) เช่น (1,0,2)
นอกจากนี้ยังมีการใช้สัญกรณ์ A-B-C เป็นทางเลือกแทนกันโดยทั่วไป
วิธีเปรียบเทียบความเฉพาะเจาะจง
ความเฉพาะเจาะจงจะเปรียบเทียบโดยการเปรียบเทียบองค์ประกอบทั้ง 3 ตามลำดับ ความเฉพาะเจาะจงที่มีค่า A มากกว่าจะมีความเฉพาะเจาะจงมากกว่า หากค่า A ทั้ง 2 ค่าเท่ากัน ความเฉพาะเจาะจงที่มีค่า B มากกว่าจะมีความเฉพาะเจาะจงมากกว่า หากค่า B ทั้ง 2 ค่าเท่ากัน ความเฉพาะเจาะจงที่มีค่า C มากกว่าจะมีความเฉพาะเจาะจงมากกว่า หากค่าทั้งหมดเท่ากัน ความเฉพาะเจาะจงทั้ง 2 จะเท่ากัน
ตัวอย่างเช่น (1,0,0) ถือว่ามีความเฉพาะเจาะจงสูงกว่า (0,4,3)
เนื่องจากค่า A ใน (1,0,0) (ซึ่งคือ 1)
มากกว่าค่า A จาก (0,4,3) (ซึ่งคือ 0)
ตัวเลือกส่งผลต่อความเฉพาะเจาะจง
แต่ละส่วนในสามสิ่งประกอบของความเฉพาะเจาะจงเริ่มต้นด้วยค่า 0,
ดังนั้นความเฉพาะเจาะจงเริ่มต้นคือ (0,0,0).
แต่ละส่วนของตัวเลือกจะเพิ่มความเฉพาะเจาะจง ซึ่งจะเพิ่มค่าของ A, B หรือ C ขึ้นอยู่กับประเภทของตัวเลือก
Universal selector
ตัวเลือกส่วนกลาง universal selector (*)
ไม่เพิ่มความเฉพาะเจาะจง โดยจะคงค่าไว้ที่ความเฉพาะเจาะจงเริ่มต้น (0,0,0)
* {
color: red;
}
ตัวเลือกองค์ประกอบหรือตัวเลือกองค์ประกอบเสมือน
ตัวเลือก องค์ประกอบ (ประเภท)
หรือ องค์ประกอบเสมือน
จะเพิ่มความเฉพาะเจาะจงแบบองค์ประกอบ ซึ่งจะเพิ่มองค์ประกอบ C ขึ้น 1
ตัวอย่างต่อไปนี้มีความเฉพาะเจาะจงโดยรวม (0,0,1)
ตัวเลือกประเภท
div {
color: red;
}
ตัวเลือกองค์ประกอบเสมือน
::selection {
color: red;
}
ตัวเลือกคลาส ตัวเลือกคลาสเสมือน หรือตัวเลือกแอตทริบิวต์
ตัวเลือก คลาส
คลาสเสมือน หรือ
แอตทริบิวต์จะเพิ่มความเฉพาะเจาะจงแบบคลาส
ซึ่งจะเพิ่มองค์ประกอบ B ขึ้น 1
ตัวอย่างต่อไปนี้มีความเฉพาะเจาะจง (0,1,0)
ตัวเลือกคลาส
.my-class {
color: red;
}
ตัวเลือกคลาสเสมือน
:hover {
color: red;
}
ตัวเลือกแอตทริบิวต์
[href='#'] {
color: red;
}
ตัวเลือกรหัส
ตัวเลือกรหัส
จะเพิ่มความเฉพาะเจาะจงแบบรหัส ซึ่งจะเพิ่มองค์ประกอบ A ขึ้น 1
ตราบใดที่คุณใช้ตัวเลือกรหัส (#myID) ไม่ใช่ตัวเลือกแอตทริบิวต์ ([id="myID"])
ในตัวอย่างต่อไปนี้ ความเฉพาะเจาะจงคือ (1,0,0)
#myID {
color: red;
}
ตัวเลือกอื่นๆ
CSS มีตัวเลือกมากมาย แต่ไม่ใช่ทุกตัวเลือกที่จะเพิ่มความเฉพาะเจาะจง
ตัวอย่างเช่น คลาสเสมือน :not()
เองจะไม่เพิ่มอะไรลงในการคำนวณความเฉพาะเจาะจง
ความเฉพาะเจาะจงของคลาสเสมือน :not() จะถูกแทนที่ด้วยความเฉพาะเจาะจงของตัวเลือกที่เฉพาะเจาะจงที่สุดในอาร์กิวเมนต์ตัวเลือกที่คั่นด้วยคอมมา ซึ่งจะมีความเฉพาะเจาะจงเหมือนกับเขียนเป็น :not(:is(argument))
div:not(.my-class) {
color: red;
}
คลาสเสมือน :is()
เองก็ไม่เพิ่มอะไรลงในการคำนวณความเฉพาะเจาะจงเช่นกัน โดยจะใช้ความเฉพาะเจาะจงของอาร์กิวเมนต์ที่เฉพาะเจาะจงที่สุดเช่นเดียวกับ :not()
:is(h1, h2, h3) {
color: blue;
}
ตัวอย่างนี้มีความเฉพาะเจาะจง (0,0,1) เนื่องจากมีตัวเลือกเพียงประเภทเดียว (type)
เมื่อเพิ่ม id ความเฉพาะเจาะจงจะเพิ่มขึ้นเป็น (1,0,0)
:is(h1, h2, h3, #my-heading) {
color: blue;
}
คลาสเสมือน :where() แตกต่างออกไป
โดยจะมีความเฉพาะเจาะจง (0,0,0) เสมอ ไม่ว่าอาร์กิวเมนต์ใดๆ จะมีความเฉพาะเจาะจงเท่าใดก็ตาม
:where(h1, h2, h3, #my-heading) {
color: blue;
}
รูปแบบความเฉพาะเจาะจงต่ำที่ใช้ :where() ช่วยให้คุณลบล้างรูปแบบเหล่านี้ด้วยตัวเลือกพื้นฐานในสไตล์ชีตได้ในภายหลัง
:where(#my-content) {
color: red;
}
p {
color: blue;
}
แม้ว่า :where() จะมี id ในรายการอาร์กิวเมนต์ แต่ก็ยังมีความเฉพาะเจาะจงเพียง (0, 0, 0) ดังนั้นตัวเลือก p พื้นฐานจะลบล้างตัวเลือกนี้ และข้อความจะเป็น blue
ทดสอบความเข้าใจ
ทดสอบความรู้เกี่ยวกับการให้คะแนนความเฉพาะเจาะจง
a[href=/learn/css/%22#%22%5D%3C%2Fcode> มีความเฉพาะเจาะจงเท่าใด
(0,0,1)a มีค่า (0,0,1) แต่ [href=/learn/css/%22#%22%5D%3C%2Fcode> มีค่า (0,1,0)(0,1,0)a มีค่า (0,0,1) แต่ [href=/learn/css/%22#%22%5D%3C%2Fcode> มีค่า (0,1,0)(0,1,1)a มีค่า (0,0,1) และ [href=/learn/css/%22#%22%5D%3C%2Fcode> มีค่า (0,1,0) ทำให้ความเฉพาะเจาะจงรวมเป็น (0,1,1)ปัจจัยที่ไม่มีผลต่อความเฉพาะเจาะจง
มีสิ่งที่ผู้คนมักเข้าใจผิดเกี่ยวกับปัจจัยต่อไปนี้ที่ส่งผลต่อความเฉพาะเจาะจง
แอตทริบิวต์ของสไตล์แบบอินไลน์
CSS ที่ใช้กับแอตทริบิวต์ style ขององค์ประกอบ
โดยตรงจะไม่มีผลต่อความเฉพาะเจาะจง เนื่องจากเป็นขั้นตอนอื่นใน Cascade
ที่มีการประเมินก่อนความเฉพาะเจาะจง
<div style="color: red"></div>
หากต้องการลบล้างการประกาศนี้จากภายในสไตล์ชีต คุณต้องใช้การประกาศที่ชนะในขั้นตอนก่อนหน้าของ Cascade
ตัวอย่างเช่น คุณสามารถเพิ่ม !important ลงในการประกาศนี้
เพื่อให้การประกาศนี้เป็นส่วนหนึ่งของ ต้นทาง !important ที่เขียนขึ้น
การประกาศ !important
!important ที่ส่วนท้ายของการประกาศ CSS จะไม่มีผลต่อความเฉพาะเจาะจง
แต่จะวางการประกาศไว้ในต้นทางอื่น
นั่นคือ ต้นทาง !important ที่เขียนขึ้น
ในตัวอย่างต่อไปนี้ ความเฉพาะเจาะจงของ .my-class ไม่เกี่ยวข้องกับการประกาศ !important ที่จะชนะ
.my-class {
color: red !important;
color: white;
}
เมื่อการประกาศ 2 รายการเป็น !important ความเฉพาะเจาะจงจะมีบทบาทอีกครั้ง เนื่องจากขั้นตอนต้นทางจาก Cascade ยังไม่สามารถกำหนดผู้ชนะได้
.branding {
color: blue !important;
}
button {
color: red !important;
}
ความเฉพาะเจาะจงตามบริบท
เมื่อใช้ตัวเลือกที่ซับซ้อนหรือตัวเลือกผสม แต่ละส่วนของตัวเลือกนั้นจะรวมกันเป็นความเฉพาะเจาะจง ดูตัวอย่าง HTML นี้
<a class="my-class another-class" href="#">A link</a>
ลิงก์นี้มี 2 คลาส
กฎใน CSS ต่อไปนี้มีความเฉพาะเจาะจง(0,0,1)
a {
color: red;
}
หากคุณอ้างอิงคลาสใดคลาสหนึ่งในตัวเลือก
ตอนนี้ตัวเลือกนั้นจะมีความเฉพาะเจาะจง(0,1,1)
a.my-class {
color: green;
}
เพิ่มคลาสอื่นลงในตัวเลือก
ตอนนี้ตัวเลือกนั้นจะมี ความเฉพาะเจาะจง (0,2,1)
a.my-class.another-class {
color: rebeccapurple;
}
เพิ่มแอตทริบิวต์ href ลงในตัวเลือก
ตอนนี้ตัวเลือกนั้นจะมี ความเฉพาะเจาะจง (0,3,1)
a.my-class.another-class[href] {
color: goldenrod;
}
สุดท้าย ให้เพิ่มคลาสเสมือน :hover ลงในตัวเลือกทั้งหมด
ตัวเลือกนั้นจะมี ความเฉพาะเจาะจง (0,4,1)
a.my-class.another-class[href]:hover {
color: lightgrey;
}
ทดสอบความเข้าใจ
ทดสอบความรู้เกี่ยวกับการให้คะแนนความเฉพาะเจาะจง
ตัวเลือกใดต่อไปนี้มีความเฉพาะเจาะจง (0,2,1)
article > section(0,0,2)article.card.dark(0,2,1)article:hover a[href](0,0,1)) ตัวเลือกแอตทริบิวต์ (มีค่า (0,1,0)) และตัวเลือกคลาส (มีค่า (0,1,0)) ทำให้ตัวเลือกนี้มีความเฉพาะเจาะจงรวมเป็น (0,2,2)การเพิ่มความเฉพาะเจาะจงอย่างมีเหตุผล
สมมติว่าคุณมี CSS ที่มีลักษณะดังนี้
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
และ HTML ที่มีลักษณะดังนี้
<button class="my-button" onclick="alert('hello')">Click me</button>
ปุ่มมีพื้นหลังสีเทา,
เนื่องจากตัวเลือกที่ 2 มี ความเฉพาะเจาะจง (0,1,1)
เนื่องจากมีตัวเลือกประเภท 1 รายการ (button) ซึ่งมีค่า (0,0,1) และตัวเลือกแอตทริบิวต์ ([onclick]) ซึ่งมีค่า (0,1,0)
กฎก่อนหน้าอย่าง .my-button มีค่าเท่ากับ (0,1,0) เนื่องจากมีตัวเลือกคลาส 1 รายการ ซึ่งมีความเฉพาะเจาะจงต่ำกว่า (0,1,1)
หากต้องการเพิ่มความเฉพาะเจาะจงให้กับกฎนี้ คุณสามารถทำซ้ำตัวเลือกคลาสได้ดังนี้
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
ตอนนี้ปุ่มจะมีพื้นหลังสีน้ำเงิน เนื่องจากตัวเลือกใหม่มีความเฉพาะเจาะจง (0,2,0)
หากความเฉพาะเจาะจงเท่ากัน ระบบจะย้อนกลับไปใช้ขั้นตอนถัดไปใน Cascade
กลับมาดูตัวอย่างปุ่มกันก่อน แล้วเปลี่ยน CSS เป็นดังนี้
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
ปุ่มมีพื้นหลังสีเทา เนื่องจากตัวเลือกทั้ง 2 มีความเฉพาะเจาะจงเหมือนกัน คือ (0,1,0)
หากคุณเปลี่ยนกฎตามลำดับที่ปรากฏในแหล่งที่มา ปุ่มจะเป็นสีน้ำเงิน
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
เนื่องจากตัวเลือกทั้ง 2 มีความเฉพาะเจาะจงเหมือนกัน ในกรณีนี้ Cascade จะย้อนกลับไปใช้ขั้นตอนลำดับที่ปรากฏ