Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scoped CSS #8

Closed
Rich-Harris opened this issue Nov 21, 2016 · 12 comments
Closed

Scoped CSS #8

Rich-Harris opened this issue Nov 21, 2016 · 12 comments

Comments

@Rich-Harris
Copy link
Member

Same as Ractive components. A few thoughts:

  • Svelte can probably be a bit smarter than Ractive about knowing whether it needs to 'double up' selectors (i.e. Ractive isn't sure whether a given scoped style applies to a top-level element or only to its children, so it expands .the-selector {...} to both [data-gubbins=xyz].the-selector {...} and [data-gubbins=xyz] .the-selector {...} (note the space in the second example)
  • Basing the unique ID (used for scoping) on a hash of the template might be a nice way to solve the problem of scoped CSS in server-rendered HTML matching what gets rendered to the DOM
  • The CSS parser/transformer doesn't need to be compact enough to run in the browser, so we can have fun with transformations and optimisations (e.g. minifying CSS)
  • We could warn about unused selectors etc
@Rich-Harris
Copy link
Member Author

This is implemented, in basic form, though it doesn't do any of the advanced stuff listed above (except for using a unique template-based hash).

Long-term it would probably make sense to use PostCSS and minify CSS by default, along with the other optimisations mentioned above. With Svelte it doesn't make sense to propagate the scoping attributes across component boundaries, so we should probably warn if any components exist outside top-level elements.

Since I'm not above stealing ideas, I had a look at https://vue-loader.vuejs.org/en/features/scoped-css.html. Turns out that scoping element selectors can entail a performance hit, for whatever reason. Should perhaps warn about that. Also, Vue has a nice mechanism for extracting CSS from a component graph and putting into a separate file for production, which is neat.

Will leave this open with an 'enhancement' label, since there's still stuff to do.

@evs-chris
Copy link
Contributor

I haven't really run across this particular method of styling before, but to me it makes a lot of sense for things like ractive and svelte: http://mxstbr.blog/2016/11/inline-styles-vs-css-in-js

It gets around scoping altogether by packaging styles up into generated class names (probably based on a hash of the content?) and then attaching those classes to the styled elements. It kinda kicks the whole cascading part of CSS, which felt wrong at first glance, but after a bit of fond reminiscing about debugging components that where broken by accidental cascades, well, you know...

That's probably not a universal fit, but it seemed like something worth mentioning here in case you haven't come across it before either.

@Rich-Harris
Copy link
Member Author

Thanks – I did wonder about an approach like that or CSS modules (which vue-loader supports).

Personally I think there's too much friction. You can't use element selectors and attribute selectors etc, which means that any element that needs a style has to have a class attribute, which can quickly turn your markup pretty gross. And while it can be useful to skip the cascading part (notwithstanding that it's already not that hard to do in CSS), a) sometimes you want cascading, and b) those approaches don't actually mean you no longer have to think about cascading (much less inheritance) because there's only one CSSOM and you don't know what else is on the page.

And it means you have to chuck out a lot of accumulated knowledge. A lot of developers I know would be unamused to learn they had to learn the quirks of a new leaky abstraction over something they're already reasonably productive with.

So for me, I view those sorts of approaches as a too-clever solution to an artificial problem ("our component templates are written in JavaScript now, therefore we need to put our CSS there too"). I think a lot of the biggest complaints about CSS (such as knowing which selectors you can delete, which is impossible unless you consider the CSS in the context of your markup) can be solved if you have a well-defined component structure and a dollop of static analysis.

@evs-chris
Copy link
Contributor

As usual, you're waaay ahead of me 😀

@mohsen1
Copy link

mohsen1 commented Nov 30, 2016

I thought about similar problem with CSS loader and came up with a proposal.

Basically I think it's optimal to let developers repeat themselves with CSS and compiler optimize resulted CSS. IMO Other than color variables there is no benefit of sharing CSS code.

@camwest
Copy link

camwest commented Dec 1, 2016

@mohsen1 I disagree. Most design systems share a lot of properties like spacing, widths, heights, grid systems etc. You definitely need to share a lot of CSS values between components in a large application.

Take a look at http://tachyons.io/docs/ for an example of other cross cutting concerns than just colors.

@paulocoghi
Copy link
Contributor

paulocoghi commented Dec 15, 2016

Maybe I'm being too simplistic, but in my projects:

  • shared CSS and "project-wide" values like spacing, widths, heights, grid systems etc are placed in a global CSS file
  • component specific values are placed inside the component

I don't understand why I would define a css class inside a component if this class will be shared with other components.

@plesiecki
Copy link

Imagine scoped styles together with styles encapsulation 🎉 💥 ✨ 😄

@DylanPiercey
Copy link

@Rich-Harris fwiw you can easily do attribute and element selectors with css modules two ways:

/** Global attr selector */
:global([my-attr="something"]) {...}

/** Scoped attr selector */
.my-class [my-attr="something"] {...}

I think it'd be awesome to support css modules :).

@Rich-Harris
Copy link
Member Author

This should probably be closed now, scoped CSS has been supported for ages

@morewry
Copy link

morewry commented Sep 1, 2017

Late input not so much about the feature in response to some related points raised.

I agree with @camwest, it's not just tokens like colors that are useful to share, though it's true components replace a lot of things previously shared through CSS frameworks.

Maybe I'm being too simplistic, but in my projects:

  • shared CSS and "project-wide" values like spacing, widths, heights, grid systems etc are placed in a global CSS file
  • component specific values are placed inside the component
    I don't understand why I would define a css class inside a component if this class will be shared with other components. - @paulocoghi

It's good enough for most use cases right now, for sure! But there are a few things worth considering.

If your component's rendering relies on something present in a global scope outside, rather than something explicitly passed in/imported, it's not just an academic problem. There are practical effects; for example, to test the component "in isolation" actually means including the global. Your test global and production global can drift and you have no way to lock down the version of the global class name "interface" used in your component. So your tests can pass, but the component renders broken in production.

Having a separate global stylesheet used by components works with anything that relies on JavaScript assistance with scoping so that interior component styles don't leak to the outside (inside-out). However, Shadow DOM will also provide outside-in style encapsulation, to fix that problem where code outside your component can break your component. This means with Shadow DOM those global class names will no longer work inside the component.

My view is that JS tools/UI frameworks doing CSS scoping is filling in for a missing feature in the web platform. AFAIK there's no reason to think that approach will remain useful enough to justify the maintenance cost once a "native" solution has sufficient support. While I doubt that's now or even next year, IMO it's not too early to begin thinking about approaches that will work now and also endure under Shadow DOM.

@paulocoghi
Copy link
Contributor

@morewry Wow! Thank you for the explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants