WICG / construct-stylesheets

API for constructing CSS stylesheet objects
Other
138 stars 25 forks source link

Allow for stylesheet composition using constructible stylesheets #24

Open calebdwilliams opened 6 years ago

calebdwilliams commented 6 years ago

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.

TakayoshiKochi commented 6 years ago

Sounds like an interesting use case, but could it be solved in CSSOM?

calebdwilliams commented 6 years ago

Potentially, but there's not really solid documentation on CSSImportRule that I could find. But given that this is still a relatively young proposal, I doubt that CSSImportRule is capable of taking a constructed stylesheet (although if this proposal really gets off the ground, that should certainly be amended).

Regardless, I think the usability and functionality afforded to developers using the CSSStyleSheet constructor would be worth the effort. Assume, for a minute, that CSSImportRule is capable of taking a constructed stylesheet as an argument, I would assume the equivalent of the above code would be:

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

const sheet2 = new CSSStyleSheet(`
  h1 {
    background: var(--secondary);
    color: var(--primary);
  }`);

const sheet3 = new CSSStylesheet(`
  .error {
    color: var(--alert);
  }`);

const importSheet1 = new CSSImportRule(sheet1);

sheet2.insertRule(importSheet1);
sheet3.insertRule(importSheet1);

or something similar which is far less developer friendly, especially for library authors who are using this feature in conjunction with the web components feature I listed above. Adding a composition syntax of some sort to the CSSStyleSheet constructor would make the tool much more friendly.

Also, any given constructed stylesheet might have multiple imports (say variables like sheet1 above, typography, common classes, etc.) as they would be either attached to a shadow DOM and/or treated as a user-agent sheet (depending on where the discussions in webcomponents issue 468 end up).

Adding this feature would be a concise way for library authors to create short, succinct CSS partials that have one specific job and import them where they are needed without a lot of overhead and allow browser vendors to optimize applying those stylesheets well (because sheet1 might be added to n different stylesheets).

TakayoshiKochi commented 6 years ago

I'm not sure referring a JS object from CSS stylesheet ever worked like the OP (import: [sheet1]). Also I would like to hear feedback from style engine implementors whether such smaller chunk of stylesheets are well optimizable.

Anyway this is an addition on top of constructed stylesheets, so this is not blocking the stylesheet constructor itself.

calebdwilliams commented 6 years ago

@TakayoshiKochi I suppose that makes sense, but we are proposing new interfaces and features to the CSSOM with this proposal, so I don't necessarily think it's a non-starter. What I do know is that this feature (along with web components issue 468) would go a long way in solving a lot of the long-term strategy my organization has with web components.

calebdwilliams commented 6 years ago

Another option, depending on how #10 and #25 pan out is to have the toString method of a style sheet object return the URL for @import purposes.

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

const sheet = new CSSStyleSheet(`
  @import ${customProps};

  h1 {
    background: var(--secondary);
    color: var(--primary);
  }`);