The CSS Podcast – 003: Specificity
נניח שאתם עובדים עם הקוד הבא ב-HTML וב-CSS:
<button class="branding">Hello, Specificity!</button>
.branding {
color: blue;
}
button {
color: red;
}
יש כאן שני כללים שמטרגטים את אותו אלמנט. כל כלל מכיל הצהרה שמנסה להגדיר את הצבע של הלחצן: אחד מנסה לצבוע את הלחצן באדום והשני מנסה לצבוע אותו בכחול. איזו הצהרה חלה על הרכיב?
כדי להבין איך המערכת של CSS מחליטה בין הצהרות מתחרות, צריך להבין את אלגוריתם הספציפיות של CSS.
מידת הספציפיות היא אחד מהשלבים הנפרדים של המפל, שתואר במודול הקודם, בנושא המפל.
ציון ספציפיות
כל כלל סלקטורים במקור מקבל ניקוד. אפשר להתייחס לרמת הספציפיות כציון כולל, וכל סוג של סלקטורים מקבל נקודות שתורמות לציון הזה. ההצהרות מכללי הספציפיות הגבוהה ביותר מנצחות.
כשמדובר בפרויקט ספציפי, צריך לשמור על איזון: לוודא שכללי ה-CSS שאתם מצפים שיחולו אכן חלים, תוך שמירה על ציונים נמוכים באופן כללי כדי למנוע מורכבות. רמת הספציפיות צריכה להיות גבוהה רק ככל שנדרש, ולא צריך לשאוף לרמת הספציפיות הגבוהה ביותר האפשרית. יכול להיות שבעתיד נצטרך להחיל קוד CSS חשוב יותר. אם תבחרו ברמת הספציפיות הגבוהה ביותר, תהיה לכם בעיה.
הספציפיות היא לא מספר עשרוני, אלא טריאדה שמכילה שלושה רכיבים: A
, B
ו-C
.
A
: ספציפיות כמו מזההB
: ספציפיות כשלכיתהC
: ספציפיות כמו רכיב
הוא מיוצג לעיתים קרובות באמצעות הסימון (A,B,C)
. לדוגמה: (1,0,2)
.
סימון חלופי נפוץ נוסף הוא A-B-C
.
השוואה בין ספציפיות
כדי להשוות בין רמות הספציפיות, משווים בין שלושת הרכיבים לפי הסדר: רמת הספציפיות עם הערך הגבוה יותר של A היא ספציפית יותר. אם שני הערכים של A זהים, רמת הספציפיות עם הערך הגבוה יותר של B היא ספציפית יותר. אם גם שני הערכים של B זהים, רמת הספציפיות עם הערך הגבוה יותר של C היא ספציפית יותר. אם כל הערכים זהים, שתי רמות הספציפיות שוות.
לדוגמה, (1,0,0)
נחשב לספציפי יותר מ-(0,4,3)
כי הערך של A
ב-(1,0,0)
(1
) גדול מהערך של A
ב-(0,4,3)
(0
).
הסלקטורים משפיעים על הספציפיות
כל חלק בטריאדה של רמת הספציפיות מתחיל בערך 0
, כך שרמת הספציפיות שמוגדרת כברירת מחדל היא (0,0,0)
.
כל חלק של הסלקטורים מגדיל את הספציפיות, וכך, בהתאם לסוג הסלקטורים, מגדיל את הערך של A
, B
או C
.
בורר אוניברסלי
סלקטורים אוניברסליים (*
) לא מוסיפים ספציפיות, והערך שלהם נשאר בספציפיות הראשונית של (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;
}
בורר מזהה
סלקטור מזהה מוסיף ספציפיות שדומה למזהה, שמגדילה את המרכיב C
ב-1, כל עוד משתמשים בסלקטור מזהה (#myID
) ולא בסלקטור מאפיין ([id="myID"]
).
בדוגמה הבאה, רמת הספציפיות היא (1,0,0)
#myID {
color: red;
}
בוררים אחרים
ב-CSS יש הרבה סלקטורים. לא כל המאפיינים האלה מוסיפים ספציפיות.
לדוגמה, פסאודו-הקלאס :not()
לא מוסיף דבר לחישוב הספציפיות.
עם זאת, הבוררים שהועברו כארגומנטים נוספים לחישוב הספציפיות.
div:not(.my-class) {
color: red;
}
לדוגמה הזו יש ספציפיות של (0,1,1) כי יש בה בורר סוג אחד (div
) וכיתה אחת בתוך ה-:not()
.
בדיקת ההבנה
בדיקת הידע שלכם בנושא ניקוד ספציפיות
מה מידת הספציפיות של a[href="#"]
?
(0,0,1)
a
הוא (0,0,1)
, אבל הערך של [href="#"]
הוא (0,1,0)
.(0,1,0)
a
הוא (0,0,1)
, אבל הערך של [href="#"]
הוא (0,1,0)
.(0,1,1)
a
הוא (0,0,1)
והערך של [href="#"]
הוא (0,1,1)
, כך שהספציפיות הכוללת היא (0,1,1)
.גורמים שלא משפיעים על הספציפיות
יש כמה תפיסות שגויות נפוצות לגבי הגורמים הבאים שמשפיעים על הספציפיות.
מאפייני סגנון בתוך השורה
CSS שחלה ישירות על המאפיין style
של רכיב לא משפיע על הספציפיות, כי זהו שלב אחר במפל שאותו מעריכים לפני הספציפיות.
<div style="color: red"></div>
כדי לשנות את ההצהרה הזו מתוך גיליון סגנונות, צריך לגרום להצהרה לנצח בשלב מוקדם יותר של הקטע.
לדוגמה, אפשר להוסיף אליו את !important
, כך שהוא יהפוך לחלק מהמקור !important
שנוצר על ידי המחבר.
!important
הצהרות
הערך !important
בסוף הצהרת CSS לא משפיע על הספציפיות, אבל הוא מעביר את ההצהרה למקור אחר, כלומר !important
שנוצר על ידי המחבר.
בדוגמה הבאה, הספציפיות של .my-class
לא רלוונטית כדי שההצהרה !important
תנצח.
.my-class {
color: red !important;
color: white;
}
כששתי ההצהרות הן !important
, הספציפיות נכנסת שוב לתמונה, כי שלב המקור מהמפל עדיין לא הצליח לקבוע מי המנצח.
.branding {
color: blue !important;
}
button {
color: red !important;
}
ספציפיות בהקשר
כשמשתמשים בבורר מורכב או משולב, כל חלק בבורר הזה מוסיף ספציפיות. הנה דוגמה לקוד HTML:
<a class="my-class another-class" href="#">A link</a>
הקישור הזה מכיל שתי כיתות.
לכלל בקוד ה-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,0,1)
) ובורר רמה (ערך (0,0,1)
). לכן, רמת הספציפיות הכוללת של הסלקטורים האלה היא (0,2,2)
.הגברת הספציפיות באופן פרגמטי
נניח שיש לכם קוד CSS שנראה כך:
.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
באמצעות קוד HTML שנראה כך:
<button class="my-button" onclick="alert('hello')">Click me</button>
הלחצן כולל רקע אפור כי לבורר השני יש ספציפיות של (0,1,1)
.
הסיבה לכך היא שיש לו בורר סוג אחד (button
), שהוא (0,0,1)
ובורר מאפיינים אחד ([onclick]
), שהוא (0,1,0)
.
הכלל הקודם – .my-button
– שווה ל-(0,1,0)
כי יש בו סלקטור של כיתה אחת, שהוא ספציפי פחות מ-(0,1,1)
.
כדי לשפר את הכלל הזה, אפשר לחזור על בורר הכיתה כך:
.my-button.my-button {
background: blue;
}
button[onclick] {
background: grey;
}
עכשיו הלחצן יהיה עם רקע כחול, כי לבורר החדש יש רמת ספציפיות (0,2,0)
במקרה של שוויון ברמת הספציפיות, המערכת חוזרת לשלב הבא ברצף
נמשיך בינתיים עם דוגמת הלחצן ונשנה את ה-CSS כך:
.my-button {
background: blue;
}
[onclick] {
background: grey;
}
הלחצן כולל רקע אפור כי לשני הבוררים יש ספציפיות זהה של (0,1,0)
.
אם מחליפים את סדר הכללים לפי מקור, הלחצן יהפוך לכחול.
[onclick] {
background: grey;
}
.my-button {
background: blue;
}
הסיבה לכך היא שלשני הבוררים יש את אותה רמת ספציפיות. במקרה כזה, התהליך יוגדר לפי סדר ההופעה.