[webkit-dev] Implementing <style scoped>

Roland Steiner rolandsteiner at chromium.org
Thu Sep 8 14:28:10 PDT 2011

Hi all,

After several discussions on the whatwg@ mailing list and others, we would
like to go forward with adding <style scoped> to WebKit.


Style rules within <style scoped> only apply to the parent element of <style
scoped> (the scoping element), as well as descendants of it. Any other nodes
are unaffected. This allows authors to style specific parts of a page
without requiring ID prefixes. It also has potential performance benefits,
as scoped rules do not need to be evaluated outside their scope.

As per discussion on
our implementation would diverge from the current HTML5 spec (
in that we would match selectors only up to, and including, the scoping
element. E.g.,:

<div id="bar" class="X">    <!-- A -->
    <div id="foo">   <!-- B -->
        <style scoped>
            div { ... } // applies to B, C, D
            .X { ... } // applies to C
            .Y { ... } // applies to D
            .X .Y { ... } // doesn't match
            #foo { ... } // applies to B
            #bar { ... } // doesn't match
            div div { ... } // applies to C, D
            div div div { ... } // doesn't match
            #foo div { ... } // applies to C, D
            div #foo div { ... } // doesn't match
            #bar .X { ... } // doesn't match
            .X div { ... } // doesn't match
            .X + div { ... } // apples to D
            .X + .Y { ... } // apples to D
        <div class="X">    <!-- C -->
        <div class="Y">    <!-- D -->
<div class="Y">    <!-- E -->

If authors want to have a selector be able to bridge this barrier (but still
only apply to elements within the scope), we propose that the selector must
explicitly contain :root or :scope. E.g., with above HTML example:

    :scope { ... } // applies to C
    div:scope { ... } // applies to C
    #foo:scope { ... } // applies to C
    #foo:scope div { ... } // applies to C, D
    #bar:scope div { ... } // doesn't match: match exceeds scope due to
presence of :scope, but A (#bar) isn't the scoping element
    div :scope div { ... }  // applies to C, D: match exceeds scope due to
presence of :scope
    :scope div div { ... } // doesn't match: no 2 nested divs beneath the
scoping element B
    :root div { ... } // applies to B, C, D: match exceeds scope due to
presence of :root, but still doesn't apply to elements outside the scope
    :root div div div { ... } // applies to C, D: match exceeds scope due to
presence of :root

However, this functionality (esp. implementation of :scope) would not be
part of the initial patch series.

The implementation plan is as follows:

1.) Add 'scoped' to HTMLStyleElement.idl and HTMLAttributeNames.in, as well
as adding the required plumbing for the attribute
2.) Implement registering with the scoping element. For efficient matching
it is necessary that an element can quickly discern whether or not it has
<style scoped> as direct child(ren).
3.) Implement the meat of the matching (see below)
4.) Add support for scoped @keyframes and @font-face

Note: https://bugs.webkit.org/show_bug.cgi?id=49142 already has a patch for
steps 1-3 that works as advertised. In order to make it easier to review, I
would just break it up into smaller chunks as outlined above.

ad 3.) Implementation of scoped selector matching works as follows:

.) scoped style sheet rules are contained in a separate map <scoping element
address> -> RuleSet
.) add a field to ParentStackFrame that identifies the
closest ParentStackFrame that refers to a scoping element
.) during matching only check RuleSets that are thusly identified in
ParentStackFrame (plus a slow path that climbs the tree in case
ParentStackFrame isn't applicable), plus global rules
.) add a 'scope' parameter to the matching functions that identifies the
scoping element that limits the matching.

Note that with this implementation rules in scoped RuleSets that are not "in
scope" aren't even looked at. Also note that the actual selector data is NOT
modified for this. I.e., a selector in a scoped style sheet is not different
from a global selector. This has several benefits:

.) no updating necessary if a <style> element is inserted or removed from
the document, nor when the 'scoped' attribute is set/unset.
.) paves the way for a trivial implementation of a similarly scoped
.) for components: several component instantiations can re-use the same
template style sheet without the need to clone its rules.

Please let me know your thoughts,

- Roland
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-dev/attachments/20110908/0e2d0baa/attachment.html>

More information about the webkit-dev mailing list