Closed lukeed closed 4 years ago
if this is the wrong place for this -- sorry!
nope, right place!
I definitely hear you, though it feels like disabling scoping by default is the wrong solution. Or rather, disabling scoping would be the right solution if we wanted to be able to disable scoping, but not for the sake of a side-effect of doing so β because we don't want to! (At least, I don't think we do?)
If <style scoped>
was something people opted in to, a lot of people wouldn't use it, and as a consequence they'd end up reverting to over-engineered namespacing conventions (which defeats the object) or they'd experience annoying-to-debug conflicts. Or perhaps they would read about what scoped
entails, and opt in reluctantly because they believe it would have deleterious performance impacts. Eliminating that kind of 'configuration anxiety' from web development (and the associated learning overhead) is one of Svelte's goals.
Which prompts two further questions:
scoped
optional?I believe the answer to 1 is 'not very'. Bytes-wise, although the selectors themselves don't compress well, you only have one unique selector per component so I'd expect the post-gzip impact to be acceptable. Perf-wise, there's definitely a theoretical hit, but what kind of numbers are we talking about? (Genuine question!)
As for 2, the answer is, well... maybe? For example if we analysed your entire component tree, we could generate efficient Styletron-style selectors and replace classes accordingly (gets slightly tricky with dynamic classes, but still possible). That has one major downside which is that your original classes would vanish (follow me on Twitter for occasional rants about why that's bad...), but if it's an opt-in for perf-heads like you then I'd be okay with it π
These are just my thoughts though, I would be interested to know what others think.
just an idea...
how about going the opposite way, i.e:
<style unscoped>
so we keep current behaviour and add unscoped styles if needed, by declaring them explicitly?
Cool, thanks!
If
<style scoped>
was something people opted in to, a lot of people wouldn't use it, and as a consequence they'd end up reverting to over-engineered namespacing conventions
I tend to disagree. I think it's a matter of documentation. The ability to scoped
was one of the first things I learned about Vue, actually.
1) I can do some work on comparing rendering impacts, though I strongly suspect it's mostly theoretical, as you say. I think there's more loss in older browsers' ability to match CSS with an attribute inclusion. (I mean, like, IE8/9 old.)
The bytes _do_ come to be a bit of an issue, imo. I have a a [demo app](https://menu-demos-mncdqitsvb.now.sh/#), which is a single component with `cascade:false`, and the scoped namespace is added to the stylesheet 18 times. That's an extra 306 bytes of CSS! _(plus an extra 17 for holding the JS value)_
Now, 306 isn't that much, initially --- although I do have libraries that are smaller than that.
It's more of a problem with _actual_ applications with, say, 10-20 unique components. I have one of these, but unfortunately cannot link to it. Although, I will say that the byte-increase definitely scales up predictably.
So I end up having to _(over?)engineer_ solutions to avoid the scope/namespace altogether.
My inclination is to still go with the scoped
attribute, especially since it's declarative. And it can be "on by default" by just including it by default on all examples & CLI templates.
I also like @ekhaled's idea, but would like noscope
instead as a homage to CS days π... but seriously.
The important part, to me, is just having a simple, straightforward way to turning it off, aside from just avoiding style
tags altogether.
Another option is to just call the attribute global
so that it aligns with current naming. Behind the scenes, it could just wrap each selector with the :global
modifier.
This seems to be the same issue as #1080 (which I closed, since this conversation was already in progress).
I totally agree with @lukeed
The global style could also be used to allow @media, @page or @font-face in css. So instead of just a component with some visual attributes components could also be used to add style to a page.
is there currently a way keep scoped styles for a css classname that is dynamic and is on the same element? So I was expecting to be able to do this:
img:global(.dummy){
width: 100%;
height: 100%;
opacity: 0;
}
resulting in
img.svelte-pz57d7.dummy{width:100%;height:100%;opacity:0}
at the moment you can only do it without the space
img :global(.dummy){
width: 100%;
height: 100%;
opacity: 0;
}
resulting in
img.svelte-pz57d7 .dummy{width:100%;height:100%;opacity:0}
syntax like this might also be handy.
img &.dummy{
/* styles here*/
}
@cssandstuff This might be edging on "offtopic" territory, not sure π. But, I think you may be after :global(img.dummy)
@cssandstuff not sure I understand what result you're looking for (i.e. what CSS should be generated)?
Some compound selectors will look wacky inside :global(...)
, depending on your syntax highlighter, so I generally recommend :global(img).dummy
rather than :global(img.dummy)
. They both mean the same thing though so either will do
Grouping leaky styles together would make things cleaner.
<style>
@document { /* No highlighting support for @global */
.btn>.icon {}
.btn>.icon:hover {}
}
</style>
For anyone following along at home, thereβs this RFC which is just in the beginning stages and has not PR yet: https://github.com/arxpoetica/rfcs/blob/css-in-html/text/0000-css-in-html.md
Perf-wise, there's definitely a theoretical hit, but what kind of numbers are we talking about? (Genuine question!)
I'm curious about this myself. In Pinafore, I wrote a script to make all CSS global because I wanted to get rid of the extra attribute selectors, but now that attribute selectors are gone (#1118) it's worth revisiting.
I built Pinafore with and without the globalizing, and the total size of all CSS (35 files) increased from 41372 bytes to 48672 bytes (41.3kb -> 48.6kb, +17.6%). So not an enormous increase.
Probably more interesting would be to measure the impact on style calculation costs, but this is going to vary heavily from app to app (e.g. how much layout thrashing you may be doing, how complex your DOM is) and from browser to browser.
I used @MaxMilton 's code and created this preprocessor which will make any css code global including support for external files and postcss plugins: https://www.npmjs.com/package/svelte-preprocess-css-global
I have a solution for sass/scss with the style[global]
attribute in the @ctx-core/sass package.
https://github.com/ctx-core/ctx-core/blob/master/packages/sass/svelte.js#L34
If this is the wrong place for this -- sorry! StackOverflow didn't seem like the right place to me.
Currently, the inclusion of any CSS within a
style
tag is considered scoped. The only way out of this is to wrap your selector(s) in:global()
. This, however, gets to be fairly verbose when you want to wrap all selectors on the page.Arguably, the appeal of SFCs is encapsulating all component-relatives into the single file. Additionally, a core motivation of Svelte (imo) is to assist in the creation of vanilla apps (including HTML, CSS, JS) in a nicer, faster way. (We all know this, duh!)
I bring this up because, right now, devs are essentially penalized for using the SFC format --- the obvious format for Svelte --- with an additional 17 bytes of CSS per selector, and the only ways to avoid the penalty are cumbersome: keep all CSS in a
styles/
dir or:global
all the things.Proposition
I'd like to use Vue as inspiration & move the current behaviors under the
scoped
attribute for thestyle
tag. Nothing would change, including the ability to "exit" the scope with the help of:global
.Then, without
scoped
, Svelte would treat normalstyle
contents as partial CSS files. By default, no "penalties" via bytes (& render time, lol) are suffered. Instead, Svelte concatenates the stylesheet, as is, via component assembly.This also opens the door for CSS preprocessors down the road via the
lang
attribute... another hat tip to Vue.