
Show HN: Styletron – Virtual CSS - rtsao
https://ryantsao.com/blog/virtual-css-with-styletron
======
wolfgang42
This isn't specifically to do with Styletron, but I'm wondering: what is the
use case for building arbitrary CSS from JavaScript? I've never written an app
where this seemed necessary; the most I've ever needed is some semantic
classes to apply, like this:

    
    
        .request-pending {background-color: $yellow;}
        .request-acknowledged {background-color: $green;}
    

It seems like mixing the actual styles in with the JS violates separation of
concerns and clutters up the actual logic.

~~~
kowdermeister
It makes no sense for 99.9% of the apps out there. If you are running at
Facebook or Google level, maaaybe. This whole madness started with a FB dev
presentation about running CSS "at scale". Then folks started to copy each
other and this is what we have now.

Just look at
[https://github.com/rtsao/styletron](https://github.com/rtsao/styletron)
there's a whole "how to use it" page, but zero info WHY to use it. Not even a
section about valid use cases.

IMHO SASS covers almost all cases of CSS "at scale".

> It seems like mixing the actual styles in with the JS violates separation of
> concerns and clutters up the actual logic.

It does not just seem like it... it does violate it for no good reason.

~~~
rtsao
I think the argument is that separation of UI components is a more true
"separation of concerns" than separating CSS, JS, and HTML.

The implementation of a UI widget is ultimately a combination of CSS, HTML,
and JS which are coupled to some degree, so by colocating them together, the
component is easier to manage. But to do this effectively, you need some way
to get around the global nature of CSS. CSS modules and CSS-in-JS are means of
achieving this.

A good blog post about this topic is: [https://medium.com/seek-developers/the-
end-of-global-css-90d...](https://medium.com/seek-developers/the-end-of-
global-css-90d2a4a06284#.kf4qq0njt)

~~~
kowdermeister
> the component is easier to manage

But you can still keep CSS in a CSS file inside a module folder. SASS or any
other CSS build took could grab it from there.

> get around the global nature of CSS

That can be done with proper scoping supported naturally by CSS.

Local CSS is still not as bad as moving CSS declarations to JavaScript.

~~~
scott113341
An additional problem is that even when CSS is properly scoped, you end up
with wasted bits over the wire by sending down duplicated declarations. I did
some cursory research using cssstats [1] because I was curious how many CSS
declarations are unique. Turns out it's about 20-25% for most "big tech"
websites.

Gzip helps reduce the impact of this, but Styletron's gzipped CSS is still
much (40% or so) smaller than the other CSS-in-JavaScript implementations [2].
In some cases, the cost of switching to using a tool like Styletron might be
justified by faster loading times in low-bandwidth markets.

[1] [http://cssstats.com](http://cssstats.com)

[2] [https://ryantsao.com/blog/virtual-css-with-
styletron](https://ryantsao.com/blog/virtual-css-with-styletron)

~~~
matchu
Bandwidth was the major motivation for building Aphrodite, too: Khan Academy
wanted to decrease the number of bytes required for the initial pageload.
[http://engineering.khanacademy.org/posts/aphrodite-inline-
cs...](http://engineering.khanacademy.org/posts/aphrodite-inline-css.htm)

> We must deliver the absolute minimum amount of CSS necessary by only sending
> down CSS in use by components in the server-side rendered body. This rules
> out extracting all the CSS used in all of our components at compilation
> time, as much of that CSS would not be needed for the initial page load.

Colocating styles with components _is_ a win, but, more importantly, styles-
as-JS-objects was the simplest way to get this perf feature out the door.

------
trueadm
Great work! Styletron looks awesome and the performance definitely fits well
with some of the apps I work with. I'll give it a try :)

------
matchu
I'm curious about this limitation:

> Descendant and child combinators are unsupported

Are conditional applications of rules also unsupported, like `:hover` and
media queries? That's a big deal in terms of runtime perf, too.

~~~
rtsao
Yeah, media queries and pseudo selectors (such as :hover) are supported. These
tend to be really important for critical CSS. Descendent combinators are
possible but to a greater degree involve tradeoffs. I posted my thoughts on
this on this issue:
[https://github.com/rtsao/styletron/issues/27#issuecomment-26...](https://github.com/rtsao/styletron/issues/27#issuecomment-265678839)

------
kevinyun
Am I having a hard time understanding this CSS in JS concept, and therefore
Styletron, if I've never worked with React before? Let's say at a basic level,
I have compiled stylesheets -- could you explain in simple web developer
layman's terms how this could be implemented, knowing the benefit of reduced
file size and increased performance is what were aiming for?

------
bostonvaulter2
Looks nice but I don't like the lack of pseudo selectors:

From the footnotes:

> The one area where this is useful is combining descendant combinators with
> pseudo classes, the most common use case being where hovering a parent
> triggers a style change in a descendant node. However, this behavior be
> implemented in JavaScript with event listeners and explicit state changes if
> needed.

~~~
fuzionmonkey
Plain pseudo classes are supported (e.g. :hover), but since descendant/child
combinators aren't supported, a parent :hover can't change a child style. But
any element can still have :hover styles.

~~~
err4nt
That seems like it would be a big roadblock to doing much useful with it. Is
it impossible, not yet supported, or supported but not easy to do?

~~~
rtsao
Someone submitted a proposal on how to support descendent/child combinators.
It's certainly possible, but I wrote a response on why it would would
potentially involve tradeoffs:
[https://github.com/rtsao/styletron/issues/27#issuecomment-26...](https://github.com/rtsao/styletron/issues/27#issuecomment-265678839)

------
doublerebel
tl;dr: deduplication processing for CSS speeds CSS compilation and produces
smaller file sizes. Cool!

The article only has compilation performance tests, and there's a small
mention in the docs: How does Styletron affect render speed in the browsers?

Also, what tool are you using to convert existing CSS to JS objects?

~~~
rtsao
I actually wrote a separate benchmark suite [1] that uses Paul Irish's
pwmetrics [2], so using real Chrome to check render performance. From those
numbers, Styletron performed really well in terms of time to first paint and
time to first meaningful paint. But I didn't include it in the blog post
because I wasn't sure how best to separate the transfer time factor (pwmetrics
is set up to throttle network speed) since Styletron critical CSS was so much
smaller.

[1]
[https://github.com/rtsao/styletron/tree/master/packages/benc...](https://github.com/rtsao/styletron/tree/master/packages/benchmarks)

[2]
[https://github.com/paulirish/pwmetrics](https://github.com/paulirish/pwmetrics)

------
k__
Sounds awesome.

I got the same idea, when I looked at javascript style sheets.

"We don't do inline styles, we generate classes!"

If they already generate, why not merge the whole stuff?

------
qz_
I love how your blog looks.

~~~
rtsao
Thank you! It was built with Styletron actually (you can inspect the source).

It was also built with the excellent Inferno.js [1] library to render static
pages while also having a super fast full client-side app, kinda like what
Gatsby.js [2] does with React.

[1] [https://github.com/trueadm/inferno](https://github.com/trueadm/inferno)

[2] [https://github.com/gatsbyjs/gatsby](https://github.com/gatsbyjs/gatsby)

~~~
goldenkek
Why overengineer something as simple as a blog?

~~~
rtsao
For fun mostly. It's a passion project I did in my free time. I wanted to
dogfood ideas, experiment, and learn.

