Coder Social home page Coder Social logo

construct-stylesheets's Introduction

RETIRED

The concepts defined in this specification were merged into the CSSOM spec.

construct-stylesheets's People

Contributors

autokagami avatar dbaron avatar domenic avatar dontcallmedom avatar ericwilligers avatar ewilligers avatar foolip avatar kevinv11n avatar marcoscaceres avatar nordzilla avatar rakina avatar saschanaz avatar tabatkins avatar takayoshikochi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

construct-stylesheets's Issues

Add a constructor that takes a Response

/cc @domenic @rniwa

Ryosuke suggested adding a constructor that just takes a URL, so you can construct a stylesheet as easily as adding a link, like document.loadCSSStyleSheet(...).

I thought that Fetch has a lot of options beyond just the URL, and I didn't want to duplicate those in the CSSStyleSheet() constructor (and keep it consistent as Fetch grows and changes). You can just do fetch(...).then(r=>document.CSSStyleSheet(r.text)) pretty easily.

Domenic pointed to WASM as an example where they have a constructor directly take a Response object, so you can build something from a fetch() response even more easily: document.CSSStyleSheet(fetch(...)).

This sounds good to me.

Need some wordsmithing on the "using constructed stylesheets" section

https://wicg.github.io/construct-stylesheets/index.html#using-constructed-stylesheets says:

A CSSStyleSheet can only be applied to the Document it is constructed on (e.g. the document on which the factory function is called on), and any ShadowRoot in the Document it is constructed on, by assigning an array containing the sheet to their adoptedStyleSheets. So, a stylesheet can be used in multiple DocumentOrShadowRoots within the document it is constructed on.

Non-explicitly constructed stylesheets cannot be added to adoptedStyleSheets.

There are a few problems here:

  1. The definition of which document a sheet is associated with is not clear. Is it the this object of the factory method, or a document derived from the factory method itself (from its Realm)? Those can be different if .call is used. Presumably it should just be the this object of the factory method. Ideally this would be clearly specified in the factory methods by storing a reference to the "context object" Document on the resulting sheet. This may require adding a state item ("pinned document", "unique document", "document", there are several options for naming and semantics here) to https://drafts.csswg.org/cssom/#css-style-sheets but that shouldn't be too bad, especially since CSSOM has a reasonably active editor now.

  2. There is currently no state associated with a stylesheet that indicates whether it's an "explicitly constructed stylesheet". Presumably @imports from constructed stylesheets are "non-explicitly constructed stylesheets", but right not that's not really defined. The Document state from item 1 might work to identify "constructed stylesheets", depending on how it's defined.

  3. The spec doesn't define what happens if you do try to assign a sheet in the wrong document. Presumably the adoptedStyleSheets setter should throw in this case. This might be best addressed by writing down actual steps for that setter. Those steps would also do the throwing for non-explicitly constructed stylesheets. You will need some handwaving in terms of how you're getting your hands on the actual stylesheets from the FrozenArray because that's slightly rocket-science at the moment; please talk to @domenic about that.

Switch back to Real Constructors™

We switched away from constructors to instead use factory functions for two reasons:

  1. Some of the loading details get easier if it's clear what document the stylesheet is associated with. While you can find an appropriate document to associate with a normal constructor (I forget what the right term is, but it's used elsewhere), it's a little weird. A factory function on document makes this obvious.

  2. We want at least some of the constructors to be async, and async constructors aren't going to be a thing.


@plinss suggested that we can get around both of those issues:

  1. If we really need to associate it with a document, we can just require passing that as an argument to the constructor. In new CSSStyleSheet(document) versus document.createCSSStyleSheet(), the former is even slightly shorter!

  2. The constructor can take some text (or whatever, there's a few forms), and create an inert stylesheet. You can then activate it with either .parse() (which is sync, and which throws if there's an @import) or .load() (which is async and allows @import). If we add a Response-taking constructor like in #49, that particular stylesheet can only be .load()ed; .parse() would throw.


Thoughts? @bzbarsky @annevk @dbaron @domenic TAG people?

DocumentOrShadowRoot.adoptedStyleSheets should clearly describe its getter and setter behavior

https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets defines an attribute that has a getter and a setter, but it seems pretty handwavy about (a) what the setter does and (b) what the getter does. Some of the relevant specification text seems to be above the description of the interface. But for things with a getter and a setter I think you'll often end up with a clearer spec if you explicitly describe the getter and setter behavior.

Instead of assignable FrozenArray, use add / remove

In cases where this API is used by custom elements, different subclasses may want to add a different stylesheet to adoptedStyleSheets. In that case, it's better to have explicit add and remove methods rather than to have author scripts manipulate FrozenArray.

replace and replaceSync should use USVString

At least, it seems to me that otherwise they end up being a little different from bytes coming in over the network in that they'd also support lone surrogates, which doesn't seem ideal.

Shall we include added stylesheets in `document.styleSheets`?

(instead of #3,)
Do we want to include manually-added sheets in document.styleSheets, similar to how document.fonts mixes OM-created and manually-created fonts?

Big difference is that ordering matters here, which makes dealing with the invariants much more annoying. (What happens if you manually add a sheet between two <link> sheets, then insert another <link> in the document between them? Does it go before or after your manually-added one? Or do we just make it illegal to manually add a sheet before an automatic sheet?)

Need to define what fetch groups various loads from the sheet go in

This applies to @import, backgrounds, fonts, etc.

This is a bit more complicated than the <link> case, because in that case there is only one plausible fetch group: the one for the document. With constructible sheets, there are at least two fetch groups involved: the one for the window the constructor came from (esp. for sheets not attached to anything) and the one for wherever the sheet is actually being used.

I guess a sheet can in fact be used in multiple places, so there could be any number of fetch groups involved....

As a concrete question, if I create a sheet from documen A's window, and am using it in documents B and C, and B matches a rule with one background image while C matches a rule with another, which load events, if any, are blocked by the resulting image loads.

How are non-text/css responses handled?

This applies at least to @import in sheets, and to the sheets themselves if loading from URL ever gets allowed. For <link> and @import from link loads, a non-text/css type for a same-origin load in quirks mode allows the sheet to be parsed. It seems to me that we may not want that quirk here.

first paragraph about adopting constructed stylesheets should be clearer

The section on Using Constructed Stylesheets currently begins with the paragraph:

A CSSStyleSheet can only be applied to the Document it is constructed on (e.g. the document on which the factory function is called on), and any ShadowRoot in the Document it is constructed on, by assigning an array containing the sheet to their adoptedStyleSheets. So, a stylesheet can be used in multiple DocumentOrShadowRoots within the document it is constructed on.

This paragraph appears to be a sequence of statements of facts (see Hixie's post). In other words, it doesn't have any normative requirements. But it also doesn't cite any references for those statements of facts, which makes me suspect that it might be intending to impose normative requirements.

I think this should be reworded to either (a) more clearly impose the normative requirements that it intends or (b) cite sources (i.e., other specifications) for its statements of facts.

Make processing model more precise for adoptedStylesheets getter/setter

The spec, even after #40, does not have a clear processing model for the getter/setter of adoptedStylesheets. It should define them. Roughly something like

Every DocumentOrShadowRoot has an adopted stylesheets FrozenArray<StyleSheet>

On getting, adoptedStylesheets returns this DocumentOrShadowRoot's adopted stylesheets.

On setting, adoptedStylesheets performs the following steps:

  1. Let adopted be the result of converting the given value to a FrozenArray<StyleSheet>
  2. Set this DocumentOrShadowRoot's adopted stylesheets to adopted.
  3. ... perform actual styling updates ... (unsure on right spec text for this)

Why have createEmptyCSSStyleSheet()?

Seems nicer to just have one sync constructor, createCSSStyleSheetSync(''). Maybe even make the string optional so you don't need to pass an empty string. (Although I guess passing nothing will be equivalent to passing 'undefined' which will be treated as a no-op ^_^.)

It's not clear to me that "Content-Type metadata" is a defined concept

The link goes to the HTML spec, which refers to mimesniff, which does not define the concept.

I've been trying to find where the behavior of normal @import and stylesheet loading is defined to reject cross-site non-text/css, but haven't found it yet. https://drafts.csswg.org/cssom/#fetch-a-css-style-sheet is a thing, but also uses "Content-Type metadata".

Most simply, what should happen for @import from a constructed stylesheet if the server does not send a Content-Type header?

This probably doesn't need to block this spec progressing, because of the mess the rest of stylesheet loading is, but it might be good to explicitly say the behavior needs to match https://drafts.csswg.org/cssom/#fetch-a-css-style-sheet and whatever HTML uses to load sheets, assuming this last is defined.

@domenic, @annevk

Define how origin is determined for a constructed stylesheet

Copied from inline ISSUE 5 in the section "Applying Styles In All Contexts".

One of the major "misuses" of the >>> combinator is to apply "default styles" to a component wherever it lives in the tree, no matter how deeply nested it is inside of components. The use-case for this is to provide the equivalent of the user-agent stylesheet, but for custom elements (thus, the styles by necessity must come from the author).
Unfortunately, this is extremely slow, and there’s not a whole lot that can be done about that—>>> combinators are slow by their nature. Note, though, that the UA and user stylesheets automatically apply in all shadows; it’s only the author stylesheet that is limited to the context it’s created in.

(At this point, one might point out that this is already handled by just setting up styles during element construction. This doesn’t help for cases where a component is purposely authored to be styled by the end-user; forcing users of components to go muck around in their components' source code is a non-starter.)

One possible solution here is to add another origin, the "author default" origin, which sits between "user" and "author", and applies in all shadow roots automatically. We can add a list for these stylesheets, akin to document.styleSheets, and allow you to insert constructed stylesheets into it. Or maybe add an .origin attribute to CSSStyleSheet, defaulting to "author"?

Maybe it only applies to the context you’re in and descendant contexts? Need to investigate; probably bad to let a component apply automatic styles to the outer page via this mechanism.

By default, the added stylesheet via .moreStyleSheets property would have "author" origin, but do we also need other ("user", or "author default") origins?

We may have other interfaces to add stylesheets to different origins, or have CSSStyleSheet have .origin property?

Maybe we don't need documents after all

Related to #57.

At TPAC we discussed what exactly ties stylesheets to documents, if anything. Our conclusion was that it's only the base URL, which is set at construction time. So in this sense document.createCSSStyleSheetSync() is equivalent to a hypothetical window.createCSSStyleSheetSync({ baseURL: document.baseURI }) or new CSSStyleSheet({ baseURL: document.baseURI }).

Given this, I suggest we just infer the base URL at construction time, in the same way many other web platform APIs do. Namely we can use the current settings object's API base URL.

Could we allow creating a no-imports stylesheet synchronously?

It makes sense that createCSSStyleSheet has to be async to wait for @import rules.

Would it be possible to allow the creation of a no-import stylesheet synchronously, with a new factory method?

Otherwise I fear we are going to quickly see developers writing code like this:

function createCSSStyleSheetSync(text, options) {
  const ss = document.createEmptyCSSStyleSheet(options);
  for (const rule of text.split("}")) {
    ss.insertRule(rule + "}");
  }
  return ss;
}

which I'm sure is very buggy, but will mostly work.

Cloning StyleSheets

Once it's easier to construct (or import, see WICG/webcomponents#759), they're more likely to be passed around to disparate parts of an application, which might try to independently mutate the stylesheet (say, to implement scoping via rewriting selectors).

Making it easy to clone a StyleSheet could help in code that wants to share/reuse StyleSheets safely. Clones could possibly be cheap if they allow for copy-on-write optimizations.

Allow for stylesheet composition using constructible stylesheets

We should add some way to compose stylesheets to support reuse over repetition. This is in relation to @annevk's comment on Web components issue 468. Consider adding an optional configuration argument to the CSSStyleSheet constructor that would essentially @import existing stylesheets into a the current object:

const sheet1 = new CSSStyleSheet(`
  :root {
    --primary: #004977;
    --secondary: #011728;
    --alert: #d03027;
  }`);

const sheet2 = new CSSStyleSheet(`
  h1 {
    background: var(--secondary);
    color: var(--primary);
  }`, { import: [sheet1] });

const sheet3 = new CSSStylesheet(`
  .error {
    color: var(--alert);
  }`, { import: [sheet1] });

This would solve for my concern in the aforementioned issue about only allowing one stylesheet to be attached to a single custom element in the registry, would not interfere with current CSS behavior and would require only minimal modifications to the current proposal.

I think the only question I would have is how does the config import play with any @import in the sheet body (I would assume it is inserted before). Even if this syntax doesn't work, there needs to have a way to custom import constructed stylesheets into other constructed stylesheets to make the solution for 468 viable.

Define behavior when `@import` fails

From @calebdwilliams #25 (comment)

A follow up question is what happens when an @import fails? Does the rest of the stylesheet still parse? Say, your imported sheet is for CSS custom properties as I've outlined in #24 and the importer has fallbacks set up? For the record, this is my primary interest in @import for constructible stylesheets (composing constructed stylesheets).

Why methods on document instead of static factories

This is mostly a bikeshedding issue and I don't feel strongly. But IMO the following seems nicer:

const ss = await CSSStyleSheet.create(text, options);
const ss2 = CSSStyleSheet.createEmpty(options);

than the current spec's

const ss = await document.createCSSStyleSheet(text, options);
const ss2 = await document.createEmptyCSSStyleSheet(options);

replace() should return a rejected promise, not throw

If sheet contains one or more @import rules and sheet’s list of adopter documents contains any other Document than sheet’s constructor document, throw a "NotAllowedError" DOMException.

this should be "return a promise rejected with a "NotAllowedError" DOMException.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.