:scope
מוגדר ב-CSS Selectors 4 בתור:
פסאודו-סיווג שמייצג כל רכיב שנמצא בקבוצת רכיבי ההפניה לפי הקשר. זוהי קבוצה של אלמנטים (שעשויה להיות ריקה) שצוינה במפורש, כמו זו שצוינה על ידי
querySelector()
, או הרכיב ההורה של רכיב<style scoped>
, שמשמשת ל'הגדרת ההיקף' של סלקטור כך שהוא יתאים רק בתוך עץ משנה.
דוגמה לשימוש ב-<style scoped>
(מידע נוסף):
<style>
li {
color: blue;
}
</style>
<ul>
<style scoped>
li {
color: red;
}
:scope {
border: 1px solid red;
}
</style>
<li>abc</li>
<li>def</li>
<li>efg</li>
</ul>
<ul>
<li>hij</li>
<li>klm</li>
<li>nop</li>
</ul>
צבע הרכיבים li
בצבע ul
הראשון בצבע אדום, ובגלל הכלל :scope
, מוסיף גבול מסביב ל-ul
. הסיבה לכך היא שבהקשר של <style scoped>
הזה, ה-ul
תואם ל-:scope
. זהו ההקשר המקומי. אם נוסיף כלל :scope
ב-<style>
החיצוני, הוא יתאים לכל המסמך. בעיקרון, זה שווה ל-:root
.
אלמנטים לפי הקשר
סביר להניח שאתם מודעים לגרסה Element
של querySelector()
ו-querySelectorAll()
. במקום לבדוק את כל המסמך, ניתן להגביל את קבוצת התוצאה לאלמנט הקשרי:
<ul>
<li id="scope"><a>abc</a></li>
<li>def</li>
<li><a>efg</a></li>
</ul>
<script>
document.querySelectorAll('ul a').length; // 2
var scope = document.querySelector('#scope');
scope.querySelectorAll('a').length; // 1
</script>
כשמפעילים אותם, הדפדפן מחזיר NodeList
שעבר סינון כך שיכלול רק את קבוצת הצמתים ש-א) תואמים לבורר ו-ב) הם גם הצאצאים של רכיב ההקשר. בדוגמה השנייה, הדפדפן מוצא את כל הרכיבים של a
ואז מסנן את אלה שלא נמצאים ברכיב scope
. הפתרון הזה עובד, אבל אם לא תהיו זהירים, הוא עלול להוביל להתנהגות מוזרה. המשך לקרוא.
כש-querySelector משתבש
יש נקודה חשובה במפרט של הבוררים שאנשים לרוב לא שמים לב אליה. גם כשמפעילים את querySelector[All]()
על רכיב, בוררי ה-CSS עדיין מבצעים הערכה בהקשר של כל המסמך. כלומר, יכולים לקרות דברים בלתי צפויים:
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
WTF! בדוגמה הראשונה, ul
הוא הרכיב שלי, אבל עדיין אפשר להשתמש בו והוא תואם לצמתים. באפשרות השנייה, body
הוא אפילו לא צאצא של הרכיב שלי, אבל "body ul a
" עדיין תואם. שתי התוצאות האלה מבלבלות ולא תואמות לציפיות.
כדאי להשוות את הקוד הזה ל-jQuery, שבו הגישות נכונות והקוד עושה את מה שציפיתם:
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
…יש להזין :scope
כדי לפתור את הבעיות הסמנטיות האלה.
תיקון querySelector באמצעות :scope
WebKit קיבלת לאחרונה תמיכה בשימוש בפסאודו-מחלקה :scope
ב-querySelector[All]()
. אפשר לבדוק את התכונה ב-Chrome Canary 27.
אפשר להשתמש בו כדי להגביל את הבוררים לרכיב הקשר. נראה דוגמה. בהמשך, :scope
משמש כדי 'להגדיר את ההיקף' של הסלקטור ל-subtree של רכיב ההיקף. כן, אמרתי 'היקף' שלוש פעמים!
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
השימוש ב-:scope
הופך את הסמנטיקה של השיטות querySelector()
לקצת יותר צפויה ותואמת למה שספריות אחרות כמו jQuery כבר עושות.
שיפור בביצועים?
עדיין לא :(
רציתי לדעת אם השימוש ב-:scope
ב-qS/qSA משפיע על הביצועים. אז… כמו מהנדס טוב, הרכבת בדיקה. הנימוק שלי: פחות שטח פנים שבו הדפדפן מבצע התאמת סלקטור מאפשר חיפושים מהירים יותר.
בניסוי שלי, ל-WebKit נדרש כרגע פי 1.5-2 יותר זמן מאשר ללא שימוש ב-:scope
. ציורים! אחרי שהבעיה ב-crbug.com/222028 תטופל, שימוש בה אמורה להניב תיאורטית שיפור קל בביצועים בהשוואה לשימוש ללא האפשרות הזו.