Closed Rich-Harris closed 9 months ago
I like it.
It mimics the KISS paradigm of :
e.classList.add('...')
... which I love to use.
In webcomponents, I probably would like to do :
this.css.add(sheet);
To add global stylesheets, I might do :
globalThis.css.add(sheet);
'Adopted' is confusing I'm not aware of any other places in the DOM where this verb is used.
It's defined here and can be seen in a few APIs such as document.adoptNode
and the CE callback adoptedCallback
.
Step 2 from that spec page:
If node’s parent is not null, remove node from its parent.
In other words, a node cannot be adopted by multiple parents. It feels like it's being used incorrectly here.
There is a namespace object named CSS
, though I think it's more for utility functions like CSS.escape(s)
rather than managing stylesheets. Just something to keep in mind to not end up with a confusing API, like if there's globalThis.css
and globalThis.CSS
.
Wouldn't globalThis.css
not work since the adoptedStyleSheets
currently sits on DocumentOrShadowRoot
? I agree we should be weary of collisions, but this fact might mitigate your concern.
One thing about "css", is that it specifies the exact technology used today for style sheets. If there were to ever be another styling type, other than CSS (that could be mixed into this array along with css), at that point "css" would become a bad name.
I like "styles" (plural) for the name because it reminds me that this is an array of styles even if [onlyOneStyleIsUsed]
and the list could potential hold any future technology-type for styling if that ever happens. "styles" is also pretty short (to type) compared to "adoptedStyleSheets". "styleSheets" also comes to mind too as a better choice. "sheets" is another option. "adopted" needs to be removed at the very least.
We definitely need some array-like structure for the API, since the underlying semantics are array based. I see the need for these operations:
For what it's worth, I think the initial idea was to use moreStyleSheets
to draw a parallel with DocumentOrShadowRoot.prototype.styleSheets
. I just want to make sure this fact wasn't overlooked, the initial goal was to maintain an association between the two property names. I definitely see value in that, but also realize it isn't strictly necessary, but wanted to make sure that point isn't overlooked moving forward.
The casing is hard to remember
It's the exact same casing already used in document.styleSheets
. I agree it's confusing and I don't like it, but it would be much worse to adopt something different.
'Adopted' is confusing
Legit. Our usage of 'adopted' elsewhere in the platform does indeed imply ownership that's not present here. My original suggestion was, iirc, .moreStyleSheets
, which wasn't great either. ^_^
...The acronym is unfortunate
lol, good point
It's long
I get you, but I really think it's important to keep this name close to the existing document.styleSheets
, since it's doing essentially the exact same thing. If we're still using "styleSheets", we can't get too much shorter than "adopted".
One thing about "css", is that it specifies the exact technology used today for style sheets.
That's not really a big deal here; we're long, long past the point where a new styling language is a particular concern.
We definitely need some array-like structure for the API,
Yup, need basically all the functionality of an Array here. If we could convincingly fake an Array on the platform, that would be something else, but we can't. :/
I see the need for these operations
As an app developer I would file the following under YAGNI:
I'm also sceptical that I would need to prepend, in practice. I appreciate that there may be some contrived situations in which those operations are necessary, but it doesn't seem to me that the API needs to optimise for them.
I really think it's important to keep this name close to the existing
document.styleSheets
I'm not sure I've ever seen anyone use document.styleSheets
in the wild. Again, I'm sure it has its uses, but it's not part of most web developers' lived experience, whereas document.adoptedStyleSheets
would be. And most usage examples of adoptedStyleSheets
I've seen focus on the custom element case, rather than document
. So I'm not sure I agree that that's a priority.
Moreover, document.styleSheets
is a StyleSheetList
rather than a frozen array, so if consistency is a goal then it still falls short.
As an app developer I would file the following under YAGNI:
As someone who maintains code that already uses adoptedStyleSheets
I have to disagree.
Managing the list directly is extremely important for app and component-set theming mechanisms and polyfills that might rely on adoptedStyleSheets. Given that multiple actors may be managing the list, being able to tell if the sheets you care about are already in the list, and what precedence they're at is important.
Hum, so you want to be able to test a key, then decide if you insert before of after this key.
If the word adopted
is confusing as per multiple parents adopting a child. Maybe .appliedStyleSheets
would be a better name.
If the acronym is really considered regrettable, .extraStyleSheets
is another option.
Why not simply .constructedStyleSheets
?
The name is a bit longer than .adoptedStyleSheets
, but it is clear about exactly what this is for: the structure that holds the style sheets that were created using the constructor.
The only thing I dislike about .appliedStyleSheets
is that any of the sheets can be disabled, in which case, they are not applicable.
.extraStyleSheets
would probably be fine, but it doesn't communicate any inherent restrictions, especially in the case of getting a NotAllowedError
when you try to add a non-constructed sheet.
If I were a developer exploring a new feature called Constructable StyleSheets, I think I would find it intuitive that there is a new attribute called .constructedStyleSheets
.
Ostensibly this API will be used for CSS modules as well, so .constructedStyleSheets
doesn't quite fit.
Just putting some thoughts here, the purpose of this API is to share stylesheets across multiple DocumentOrShadowRoot
s and to assume styles from CSS modules. If we want to keep the -StyleSheets
suffix, perhaps something along the lines of sharedStyleSheets
.
connectedStyleSheets
could also work (the acronym might be confusing), but the language relates to Node.isConnected
which is a property on the Node
object that illustrates whether or not the node in question is connected to a context object. In this instance the adjective connected
is relating to which style sheets are currently connected to the relevant DocumentOrShadowRoot
with an understanding that each sheet that can be connected can also be connected elsewhere (where the analogy fails alongside the analogy for adopted
).
I think the name should describe what the author intends to do with the stylesheets, not how they were made. One could imagine future ways to create detached stylesheets that don't involve a constructor, but which might still be desirable to attach to a document at some point. So we should not lock in how they are made IMO.
I am not sure why adding non-constructed stylesheets is not allowed currently. Is it because all other current ways of making stylesheets already start out attached to a document? In which case the error isn't that it's not constructed, it's that it is already attached.
I think it's reasonable to not tie the name to how the sheets are created in case that were to change in the future.
I am just referring to the spec's description of adoptedStyleSheets
:
If any entry of adopted has its constructed flag not set, or its constructor document is not equal to this
DocumentOrShadowRoot
's node document, throw a "NotAllowedError
"DOMException
.
Alright, I've tired to summarize the list of suggestions made so far with the corresponding concerns.
css
Concerns: Confusing with CSS. Does not sound related to document.styleSheets
.moreStyleSheets
extraStyleSheets
Concerns: It doesn't communicate any inherent restrictions, especially in the case of getting a NotAllowedError when you try to add a non-constructed sheet.appliedStyleSheets
Concerns: any of the sheets can be disabled, in which case, they are not applicable.constructedStyleSheets
Concerns: Naming how they were created is strange; we may want to allow CSS moduels or StyleSheet from style element in the future.connectedStyleSheets
sharedStyleSheets
Concerns: These style sheets are not always shared.What about something like cssList
? Like a classList
, but for style sheets.
What about something like
cssList
? Like aclassList
, but for style sheets.
I think that has the same concern mentioned earlier that it sounds not related at all to document.styleSheets
or shadowRoot.styleSheets
.
To me the essence of these things are that "each style sheet listed" is in the form of a javascript variable that points directly to the style in memory and NOT some URL that has to be downloaded and cached from a web server.
This makes me think of names like:
By now, isn't just going to stay adoptedStyleSheets anyway? Verbosity!
I'd be cool with styles, styleSheets, or shadowStyleSheets.
So long as it's not misleading as to the relationship between the stylesheets and the document/shadow root in a problematic way, I think it's nice that a web component's shadow root connectedStyleSheets
and a web component's custom element connectedCallback
would both use "connected."
...despite them being slightly different senses of connected.
Those are different senses of the word connected, I think.
@othermaciej I disagree. isConnected
reports if a particular node is attached to some point in a DOM tree. The true analog would be to let stylesheets (constructed or modules) have an isConnected
feature as well, let's pretend for a minute they do:
const sheet = new CSSStyleSheet();
someShadowRoot.adoptedStyleSheets = [ sheet ]; // using the old naming convention on purpose here
console.log(sheet.isConnected); // if the feature exists, I would presume this to be true
Therefore we can ask to what is sheet
connected? In this instance it is connected to someShadowRoot
. Therefore I do think it makes sense to call this API DocumentOrShadowRoot.prototype.connectedStyleSheets
and perhaps introduce the CSSStyleSheet.prototype.isConnected
(which I can see being useful, but don't have a hard use case for so I won't push it) or even CSSStyleSheet.prototype.connectedTo
which could be a NodeList
of every tree the sheet is connected to.
I don’t think the analogy with node’s connectedness quite works because a single node can be associated with at most one document whereas a style sheet can be associated with multiple shadow trees / documents; this is actually problematic though... We probably want to limit it to the same document somehow. Otherwise we’d end up with global object leaks.
@rniwa, That makes sense, but unless I've missed something (which is possible, you are certainly better prepared to make that sort of statement than I am), there's nothing about connected
that necessarily implies a one-to-one relationship; a Node
instance, however, does have that implication, but a CSSStyleSheet
and a Node
are different beasts, but both can feasibly be connected to some context. That's all I'll say about it, thanks for all the hard work on making this API work for everyone.
@rniwa the suggestion in https://github.com/WICG/construct-stylesheets/issues/97#issuecomment-521299640 was not in your list: sheets
.
Though I think the concerns against moreStyleSheets
and extraStyleSheets
also apply to sheets
, but, if a short name is deemed more important, this one seems better than css
.
There is some precedent: https://drafts.csswg.org/cssom/#the-linkstyle-interface
@zcorpan That actually makes a lot of sense. If you do let style = document.createElement('style')
, the style
object will have a property called sheet
that is the CSSStyleSheet
(or StyleSheet
in Firefox) object that would be created here. Calling the API sheets
literally makes it a list of sheet objects.
@rniwa, That makes sense, but unless I've missed something (which is possible, you are certainly better prepared to make that sort of statement than I am), there's nothing about
connected
that necessarily implies a one-to-one relationship; aNode
instance, however, does have that implication, but aCSSStyleSheet
and aNode
are different beasts, but both can feasibly be connected to some context.
Even if we took that argument, there is another issue with connectedStyleSheets
, which is that a ShadowRoot
isn't necessarily always connected to a document yet you can still add a stylesheet to such a disconnected ShadowRoot
.
That's all I'll say about it, thanks for all the hard work on making this API work for everyone.
What about a name that evokes their position in the cascade?
firstStyleSheets
/ lastStyleSheets
, or any pair of respective synonyms. early
/late
, start
/end
, before
/after
, etc...styleSheetsPrologue
and styleSheetsEpilogue
also fit and add the nuance that they are there in addition to the document.styleSheets
which form, metaphorically, the "main body" of the style story.
Edit: minor usability concern, epilogueStyles
or epilogueStyleSheets
give nicer tab completions (ep<tab>
, vs styleSheetsEpilogue
clashes with styleSheetSets
), but prologueStyles
needs four keystrokes to differentiate it from propertyIsEnumerable
.
Of the various names suggested, I think sheets
and css
are not good. It would suggest it's all of the Document
's or ShadowRoot
's stylesheets, but it's not; only the ones attached in ways other than processing of <style>
or <link rel=stylesheet>
elements.
Furthermore, the DocumentOrShadowRoot
interface has a styleSheets
IDL attribute, which contains the stylesheets attached in these other ways.
To be a good name, the new property for sheets added programmatically must at minimum be clear on the distinction between it and the styleSheets
property. Incidentally, per the current Constructible Stylesheets spec, adopted stylesheets are included in the base styleSheets
property, via a monkeypatch of CSSOM.
With all that in mind, here's some potential names:
extraStyleSheets
, moreStyleSheets
, additionalStyleSheets
or short versions extraSheets
, moreSheets
. But these names would suggest sheets that are in addition to styleSheets
, when they are actually a subset.attached
, connected
, dynamic
, added
before StyleSheets
or Sheets
.override
, highPriority
, lowPriority
, again with the same suffixes.After reviewing the specs, I like the names from group 2 the best, as the direct addition/removal of these stylesheets without appearing in the DOM is the thing that's most different about them from other stylesheets. And these names correctly suggest that they are a subset of styleSheets
, not an addition.
@othermaciej in literature, the prologue and epilogue are part of the story, but usually with a different pace and/or mood than the main body of text. That doesn't clash semantically with having them readable in the styleSheets
list, or having them being StyleSheets...
Also, when discussing them, their dynamic nature will be impllied (they can't be created in any other way), but being able to unambiguously and quickly tell their priority is important.
Also, assuming a "before" variant is added later on, it would end up with an awkward addedBeforeStyleSheets
, or whatever derivative of a "dynamic"-based name we would end up choosing...
To be a good name, the new property for sheets added programmatically must at minimum be clear on the distinction between it and the styleSheets property. Incidentally, per the current Constructible Stylesheets spec, adopted stylesheets are included in the base styleSheets property, via a monkeypatch of CSSOM.
Hmm... That's not how Chrome's implementation behaves, fwiw. @rakina / @tabatkins, is that intentional?
(seems a bit weird to me to mix up the two lists of stylesheets like that, fwiw)
If we make a successor to adoptedStyleSheets
under a new name with better semantics (readonly property to a mutable container, instead of assignable property that freezes anything assigned to it), it doesn't have to inherit the spec language for adoptedStyleSheets
. Especially if that language was never actually implemented.
I don't really have an opinion on which is better, except that it should be specified, and ideally tested by WPT tests.
It's also possible that I'm misreading the CSSOM or Constructible Style Sheets specs. There's a remote chance that the authors of the spec did not realize that adding to "document or shadow root CSS style sheets" causes the sheets to eb exposed in the styleSheets
property. Or it might be very intentional, but the Chrome implementors overlooked this subtlety. Would appreciate clarity from the spec authors. Inclusion in styleSheets
or not suggests different choices for naming.
Maybe we can have it both ways? dynamicCSSEpilogue
Throwing other shades of the literary metaphor: foreword
/afterword
(germanic roots, rather than french/greek), or preamble
/postamble
(latin, though the latter is a recent addition to the English language).
So, dynamicCSSAfterword
? Or dynamicAfterwordCSS
, which is more readable in CamelCase IMO.
edit introduction
/conclusion
also fits.
@rniwa, According to the spec
An element is connected if its shadow-including root is a document.
Since that definition is specifically about an element, couldn't a CSSStyleSheet
's definition be something like: "A stylesheet is connected if it is referenced by one or many DocumentOrShadowRoot
s?"
@rniwa, According to the spec
An element is connected if its shadow-including root is a document.
Since that definition is specifically about an element, couldn't a
CSSStyleSheet
's definition be something like: "A stylesheet is connected if it is referenced by one or manyDocumentOrShadowRoot
s?"
Having a slightly different semantics for connectedness between nodes and style sheets would be too confusing.
How about localStyleSheets
in contrast with the "global" document.styleSheets
?
It does not imply the connect state or if is shared or not. Just the scope/locality of the style sheets
The only real-world analogy for this feature I can think of is when two atoms share an electron and that's just bond. So bound
or bonded
might work with the suffixes @othermaciej mentioned.
It's also possible that I'm misreading the CSSOM or Constructible Style Sheets specs. There's a remote chance that the authors of the spec did not realize that adding to "document or shadow root CSS style sheets" causes the sheets to eb exposed in the
styleSheets
property. Or it might be very intentional, but the Chrome implementors overlooked this subtlety. Would appreciate clarity from the spec authors. Inclusion instyleSheets
or not suggests different choices for naming.
Oops yeah I think we never intended the adopted stylesheets to be included in the styleSheets
list (hence why we named it moreStyleSheets
before we changed it). We don't want to reflect them twice (and only one of the list they appear in being mutable). I think names from category 1 or 2 from @othermaciej's post would work fine. https://github.com/WICG/construct-stylesheets/issues/97#issuecomment-581186920
Oops yeah I think we never intended the adopted stylesheets to be included in the styleSheets list
OK, filed https://github.com/WICG/construct-stylesheets/issues/118
While filing I also noticed a more serious problem with the spec, which is that the spec does not appear to require adopted stylesheets to be used for styling, since that is defined (I think) by CSS Cascading & Inheritence, not by CSSOM.
I like localStyleSheets
, but the contrast with global styleSheets
fails on document
. Also, each shadow root does have its own styleSheets
property. That might not be a big deal though.
local
doesn't really explain the difference with the styleSheets
property. Whether on document or shadow root, they are not more local than what is in styleSheets
.
re. dynamic
, specifically, isn't it misleading, given that they are less modifiable than the standard ones?
More generally, regarding the second category in Maciej list, <style>
and <link>
can also be added. The difference with that the "adopted" ones can't be statically defined. Not sure where it leads us, but it may be food for thought.
Regarding the priority options, the cascade is something that is often ignored by frontend devs that are primarily coders rather than designers, often to their detriment. Having a salient reminder of the existence cascade in the API name may be a good thing.
Edit: rootStyles
? They are directly tied to either the document root, or to the shadowRoot, unlike the others that belong to dedicated elements.
Good point about dynamic
, others can also be added, if a bit more indirectly. I don't see why they are less modifiable though? They are more conveniently modifiable.
The other kinds of styles also apply at the root, even if they originate from a more specific element, so I don't think rootStyles
is a clear distinction.
They are more conveniently modifiable.
Oh, indeed, not sure why I had erroneously inferred that the new methods were the only one that applied.
Naming is both a logical and a UX problem, which turns into bikeshedding contests because programmers are often not trained in the latter. There's a method to UX, and there are objective properties that make a good name beyond pure semantics.
Keep in mind that we're toolsmiths here, and that the names are the mental handles for those tools.
They should be:
They should also be descriptive, but I think that the description emphasis should be put on the properties that are important for everyday use, not for first time use.
That's why I don't like the adjectives. They are vague and ethereal, so they often don't stand on their own. You need to tack on "StyleSheet" for disambiguation. "Put the styles in the extraStyleSheets" vs "... in the epilogue".
Using a unique noun roots the the concept in the mental map without redundancy.
With all that said, stylesAddendum
has many good properties.
stylesForeword
that has (most of) the same good properties.stylesSecretStash
also comes to mind.
It is a bit less descriptive (emphasizing the fact that the are out of the DOM tree), but more playful (another important dimension as far as UX goes). This may not be the best name though... The accronym can be easily misused (trigger warning).
You could "put the CSS in the SSS", which is clearly better than the current acronym... It would only be one typo away given the QWERTY layout tough. Cue in harassment lawsuits for accidental typos (or actual harassment disguised as oversight). Edit: this took a dark turn, sorry...
Edit: That general direction may be worth exploring. stylesHideout
could work, for example.
The name
adoptedStyleSheets
is a bit awkward, for a few reasons:It's long
Unwieldy names aren't uncommon in the DOM, but it's particularly problematic when the most common example usage...
...involves repetition. (I'm hopeful that this pattern will be abandoned in favour of explicit methods, due to the fact that it will result in nasty race condition bugs, but it's still a lot to type.)
'Adopted' is confusing
I'm not aware of any other places in the DOM where this verb is used. The most commonly understood meaning of 'adopted' is in the family context, where there's a parent-child relationship. Multiple families cannot adopt the same child. Used here, it could easily be understood to mean that a stylesheet can belong to a single element.
The casing is hard to remember
Although CSS stands for Cascading Style Sheets, people informally talk about 'stylesheets' rather than 'style sheets' — one word. You only ever see
<link rel="stylesheet">
, never<link rel="styleSheet">
. This makes it harder to remember whether it'sadoptedStylesheets
oradoptedStyleSheets
, particularly if you're not writing it frequently.In fact, this is part of a spec called Constructable Stylesheets!
Of course, there is an easy way to remember it, but...
...The acronym is unfortunate
Not that I'm opposed to levity in web development, but I guarantee that this will be universally shortened to 'document dot aSS' or 'this dot aSS'. I'm not sure if that's what everyone had in mind.
Is there a reason this couldn't simply be
document.css
? An API like this would be a lot more palatable to most developers:(I realise there are concerns about being able to control the order of the collection, so
add
andremove
may be too simplistic an API, but I'd expect appending to account for 99% of cases. Regardless, that's a separate issue.)