:scope
מוגדר ב-סלקטורים ב-CSS 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
שמסונן כך שיכלול רק את קבוצת הצמתים א.) שתואמים לבורר ו-b.) שהם גם צאצאים של רכיב ההקשר. בדוגמה השנייה הדפדפן מוצא את כל רכיבי a
, ואז מסנן את אלה שלא נכללים ברכיב scope
. זה עובד, אבל אם לא תקפידו על כך זה עלול להוביל להתנהגות מוזרה. המשיכו לקרוא.
כאשר ה-querySelector משתבש
יש ממש נקודה חשובה במפרט הסלקטורים שהרבה אנשים מתעלמים מהם. גם כאשר querySelector[All]()
מופעלת ברכיב מסוים, הבוררים עדיין מבצעים הערכה בהקשר של המסמך כולו. המשמעות היא שדברים בלתי צפויים יכולים לקרות:
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
משמש כדי 'להיקף' את הבורר לעץ המשנה של רכיב ההיקף. נכון, אמרתי 'היקף' שלוש פעמים!
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 תתוקן, השימוש בו אמור לשפר באופן תיאורטי את הביצועים הטובים ביותר בהשוואה לאי-שימוש.