Skip to content

Commit 1370168

Browse files
committed
[css-scoping-1] First draft of the shadow-scoped constructs text.
1 parent 1a863a4 commit 1370168

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

css-scoping-1/Overview.bs

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,151 @@ Slots and Slotted Elements in a Shadow Tree</h4>
541541
and any deeper <a>slots</a> that their <a>slot</a> gets assigned to,
542542
don't affect inheritance.
543543

544+
545+
<h3 id='shadow-names'>
546+
Name-Defining Constructs and Inheritance</h3>
547+
548+
[=Shadow trees=] are meant to be an encapsulation boundary,
549+
allowing independent authors to share code
550+
without accidentally polluting each other's namespaces.
551+
For example, element IDs,
552+
which are generally meant to be unique within a document,
553+
can be validly used multiple times
554+
as long as each use is in a different [=shadow tree=].
555+
556+
Similarly, several [=at-rules=] in CSS,
557+
such as ''@keyframes'' or ''@font-face'',
558+
define a name that later at-rules or properties can refer to them by.
559+
Like IDs, these names are globally exposed and unique within a document;
560+
also like IDs,
561+
this restriction is now loosened to being unique within a given [=shadow tree=].
562+
563+
However, property inheritance can carry values from one tree to another,
564+
which complicates referencing the correct definition of a given name.
565+
Done naively, this can produce surprising and confusing results for authors.
566+
This section defines a set of concepts to use in defining and referencing "global" names
567+
in a way that respects encapsulation
568+
and doesn't give surprising results.
569+
570+
If an at-rule or property defines a name that other CSS constructs can refer to it by,
571+
such as a 'font-family!!descriptor' name
572+
or an ''@keyframes'' name,
573+
it must be defined as a <dfn export for=CSS>tree-scoped name</dfn>.
574+
[=Tree-scoped names=] are "global" within a particular [=node tree=];
575+
unless otherwise specified,
576+
they're associated with the [=root=] of the [=element=] hosting the stylesheet that the at-rule or property is defined in.
577+
578+
Properties or descriptors that reference a "global" name,
579+
such as the 'font-family!!property'
580+
or 'animation-name' properties,
581+
must define their value as a <dfn export for=CSS>tree-scoped reference</dfn>.
582+
[=Tree-scoped references=] implicitly capture
583+
a [=node tree=] [=root=]
584+
along with their specified value:
585+
unless otherwise specified,
586+
the [=root=] of the [=element=] hosting the stylesheet that the property or descriptor is defined in.
587+
This [=root=] reference stays with the [=tree-scoped reference=]
588+
as it is inherited.
589+
590+
Whenever a [=tree-scoped reference=] is dereferenced
591+
to find the CSS construct it is referencing,
592+
only the [=tree-scoped names=] associated with the same [=root=]
593+
as the [=tree-scoped reference=] must be searched.
594+
595+
<div class=issue>
596+
TODO: Fix all the at-rules that define global names,
597+
and the properties that reference them,
598+
to use these concepts.
599+
600+
* ''@font-face'', referenced by 'font-family!!property'
601+
* ''@font-feature-values'', referenced by 'font-family!!property'
602+
* ''@keyframes'', referenced by 'animation-name'
603+
* ''@counter-style'', referenced by 'list-style-type'
604+
* ''@color-profile'', referenced by the ''color()'' function
605+
* ''@font-palette-values'', referenced by 'font-palette'
606+
* others?
607+
</div>
608+
609+
<h4 id='shadow-names-serialization'>
610+
Serialized Tree-Scoped References</h4>
611+
612+
If a [=tree-scoped reference=] is [=serialized=],
613+
it serializes only its value;
614+
the associated [=root=] is lost.
615+
616+
<div class=example>
617+
618+
This implies that `el.style.foo = getComputedStyle(el).foo;`
619+
is not necessarily a no-op,
620+
like it typically was before [=shadow trees=] existed.
621+
622+
For example,
623+
given the following document
624+
(using the imaginary <::shadow></::shadow> markup
625+
to indicate an element's [=shadow tree=]):
626+
627+
<xmp highlight=markup>
628+
<p class=outer>Here's some text in the outer document's "foo" font.
629+
<style>
630+
@font-face {
631+
font-family: foo;
632+
src: url(foo.woff);
633+
}
634+
.outer { font-family: foo; }
635+
</style>
636+
637+
<my-component>
638+
<::shadow>
639+
<p class=inner-default>I'm inheriting the outer document's font-family.
640+
<p class=inner-styled>And I'm explicitly styled to be in the component's "foo" font.
641+
<style>
642+
@font-face {
643+
font-family: foo;
644+
src: url(https://example.com/foo.woff);
645+
}
646+
.inner-styled { font-family: foo; }
647+
</style>
648+
<script>
649+
const innerDefault = document.querySelector('.inner-default');
650+
const innerStyled = document.querySelector('.inner-styled');
651+
const defaultFont = getComputedStyle(innerDefault).fontFamily;
652+
const styledFont = getComputedStyle(innerStyled).fontFamily;
653+
654+
console.log(defaultFont == styledFont); // true!
655+
</script>
656+
</::shadow>
657+
</my-component>
658+
</xmp>
659+
660+
The <code>.outer</code> element is styled with the outer document's "foo" ''@font-face''.
661+
The <code>.inner-default</code> element inherits 'font-family' from the outer document,
662+
meaning it inherits a [=tree-scoped reference=]
663+
referencing that outer document,
664+
and so it's in the same font as <code>.outer</code>.
665+
666+
Meanwhile, <code>.inner-styled</code> is explicitly styled from inside the shadow root,
667+
so it receives a fresh [=tree-scoped reference=]
668+
referencing its shadow tree,
669+
and it is instead styled the shadow's own "foo" ''@font-face''.
670+
671+
Despite that, the script running inside the component
672+
sees the two elements as having the same value for 'font-family',
673+
because the [=root=]-reference part of a [=tree-scoped reference=]
674+
is not preserved by serialization.
675+
If it were to set <code highlight=js>innerDefault.style.fontFamily = defaultFont;</code>
676+
(thus setting the 'font-family' property of the element's attribute stylesheet,
677+
which lives in the shadow tree),
678+
the <code>.inner-default</code> element would suddenly switch
679+
to the same font as <code>.inner-styled</code>!
680+
</div>
681+
682+
Note: The [[css-typed-om-1]] is expected to reflect the [=root=] reference of a [=tree-scoped reference=]
683+
in its [=reification=] rules for values,
684+
allowing authors to tell what [=node tree=] the reference is taking its values from,
685+
and allowing values to be transported across [=node trees=]
686+
without changing their meaning.
687+
688+
544689
<h2 id="changes">
545690
Changes</h2>
546691

0 commit comments

Comments
 (0)