:scope is defined in CSS Selectors 4 as:
A pseudo-class which represents any element that is in the contextual reference element set. This is is a (potentially empty) explicitly-specified set of elements, such as that specified by the
querySelector(), or the parent element of a<style scoped>element, which is used to "scope" a selector so that it only matches within a subtree.
An example of using this guy is within a <style scoped> (more info):
<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>
Note: <style scoped> can be enabled in Chrome using the "Enable experimental WebKit features" flag in about:flags.
This colors the li elements in the first ul red and, because of the :scope rule, puts a border around the ul. That's because in the context of this <style scoped>, the ul matches :scope. It's the local context. If we were to add a :scope rule in the outer <style> it would match the entire document. Essentially, equivalent to :root.
You're probably aware of the Element version of querySelector() and querySelectorAll(). Instead of querying the entire document, you can restrict the result set to a contextual element:
<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>
When these are called, the browser returns a NodeList that's filtered to only include the set of nodes that a.) match the selector and b.) which are also descendants of the context element. So in the the second example, the browser finds all a elements, then filters out the ones not in the scope element. This works, but it can lead to some bizarre behavior if you're not careful. Read on.
There's a really important point in the Selectors spec that people often overlook. Even when querySelector[All]() is invoked on an element, selectors still evaluate in the context of the entire document. This means unanticipated things can happen:
scope.querySelectorAll('ul a').length); // 1
scope.querySelectorAll('body ul a').length); // 1
WTF! In the first example, ul is my element, yet I'm still able to use it and matches nodes. In the second, body isn't even a descendant of my element, but "body ul a" still matches. Both of these are confusing and not what you'd expect.
It's worth making the comparison to jQuery here, which takes the right approach and does what you'd expect:
$(scope).find('ul a').length // 0
$(scope).find('body ul a').length // 0
...enter :scope to solve these semantic shenanigans.
WebKit recently landed support for using the :scope pseudo-class in querySelector[All](). You can test it in Chrome Canary 27.
You can use it restrict selectors to a context element. Let's see an example. In the following, :scope is used to "scope" the selector to the scope element's subtree. That's right, I said scope three times!
scope.querySelectorAll(':scope ul a').length); // 0
scope.querySelectorAll(':scope body ul a').length); // 0
scope.querySelectorAll(':scope a').length); // 1
Using :scope makes the semantics of the querySelector() methods a little more predictable and inline with what others like jQuery are already doing.
Not yet :(
I was curious if using :scope in qS/qSA gives a performance boost. So...like a good engineer I threw together a test. My rationale: less surface area for the browser to do selector matching means speedier lookups.
In my experiment, WebKit currently takes ~1.5-2x longer than not using :scope. Drats! When crbug.com/222028 gets fixed, using it should theoretically give you a slight performance boost over not using it.
Shadow DOM is a difficult topic to wrap your head around. It's just complex. It introduces unfamiliar concepts that we're not used to on the web. Shadow boundaries, styling scoping, event retargeting, insertion points, shadow insertion points, host nodes, distributed nodes,...the lingo goes on and on.
One thing that's conceptually taxing about Shadow DOM is the way your final product (DOM) is rendered by the browser. Nodes from the host node are magically swizzled into a ShadowRoot's insertion points, yet logically, still remain in the host node. Weird! So at render time, they appear as part of the shadow tree and not the original host. How this rendering takes place is one of the most confusing pieces of Shadow DOM.
A few days ago, I released a tool I've been working on called Shadow DOM Visualizer to help lessen the learning curve.
It allows you to visually see how Shadow DOM renders in the browser, something DevTools lacks today. Both black code blocks on the left are editable. Try changing the <content> insertion points, removing, or adding new ones to see how the composited (rendered) tree is affected on the right.
Mouse over the nodes in the graph to highlight the relevant markup on the left. Yay for d3.js! Blue nodes are coming from the host node. Yellow nodes come from the Shadow DOM. <content> insertion points are the bridge
between the two worlds. Because they're logically in the Shadow DOM, they're colored yellow. Their blue border indicates that they invite blue host nodes into the rendering party.
Shadow DOM is available in Chrome 25 and the <template> element is available in Chrome 26 (although you only need the first to try the demo).
Filling out forms sometimes feel like cumbersome thing. Giving users multiple choice yet enabling them to type freely is important. The datalist element (which just landed on Chrome Canary (M20) makes this a breeze.
By using datalist, your app can define a list of suggested results users should select from. They can either select an option from the list or enter freeform text.
Live demo:
http://demo.agektmr.com/datalist/
Options can be paired with a datalist by specifying its id in an input element’s list attribute:
<input type="text" value="" list="fruits" />
<datalist id="fruits">
<option value="Apple"></option>
<option value="Orange"></option>
<option value="Peach"></option>
</datalist>
datalist is widely available on latest Firefox, Opera and Internet Explorer after version 10. So you don’t have to worry about compatibility too much, but if you want to make sure it works across browsers, try the following:
<datalist id="fruits">
Pick your favorite fruit
<select name="fruit_sel">
<option value="Apple">Apple</option>
<option value="Orange">Orange</option>
<option value="Peach">Peach</option>
</select>
or type one.
</datalist>
<input type="text" name="fruit" value="" list="fruits" />
If datalist is available on your browser, everything under the datalist except the option elements will be hidden. If you use this fallback mechanism, make sure your server catches both “fruit_sel” and “fruit” as query parameters.