Inline CSS works better in a component world
davidnicholaswilliams.com
davidnicholaswilliams.com
You can do these things in JavaScript: match your media queries in JavaScript and change the inline styles, and reimplement :hover, :focus and the likes. But I expect (without supporting measurements) that doing this for everything will be fairly bad for performance, and it will generally be less responsive (in the performance sense of the word rather than the resolution-independence sense of the word), e.g. your state-dependent styles may apply a frame later than they should. And I don’t like to depend on JavaScript without good cause.
This is where utility CSS frameworks strike the balance: by using regular class names for the effects of inline CSS, they can apply media queries and psuedoclasses. It’s an interesting approach that I haven’t used yet but I’ve steadily been coming around to the notion of for some sorts of projects.
(There are also pseudoelements; those can’t be implemented with inline CSS at all.)
It's also fairly bad practice to put your CSS into JavaScript for a number of reasons (such as accessibility, disabled javascript etc.).
Could you explain why it would affect accessibility?
He says: " in modern web apps we don’t only render content in simple single-element containers like boxes and circles, but in drawers, modals, floating panels and other complex, multi-element components. [...] All web frameworks have a good abstraction for this, of course: components. [...]"
Now, I've always missed a way to apply style on top of complex components. You can still use CSS, but as he says there is a mismatch when you change the internal HTML structure. It would be great if you could use React components like
<Dialog>
<Button>
</Dialog>
and then specify separately in a theme component the styling - not just CSS, but also what elements to use to build it up. Of course, you can just use separate components for each theme - ModernButton, DarkButton, RetroButton. But there is a lot of room for errors and the interfaces can diverge. Better to have one opaque Button component that gets passed the Style from somewhere else.I actually started working on something like this - a Electron based Desktop Widgets tool, where you could write components in React and switch themes. But since I'm a React novice I could not find an architecture that I was happy with (and the idea of using an Electron instance to decorate my desktop to monitor performance seemed a bit crazy :-)).
Our solution for this was to have an internal Button in the library that defines the interface and handles the functionality, then ModernButton/DarkButton/etc simply use Button in particular ways, blindly passing along everything else they were given.
The "inline CSS" approach is an escape hatch to avoid cascading styles. I can see its advantages, to apply all (and only) the styles on the component level.
If you're using any component-based framework (I use Vue) it's an incredible experience. The stylesheet they provide helps you be consistent and inline styles help you move quickly. The natural ability of components to scope their markup and styles means that your code is actually DRY.
The barrier to make changes is so small. You don't have to refactor CSS classes as your HTML hierarchy changes, you just make the style changes in place.
It's such a powerful paradigm that it has made my designs much better. I get consistency for free and I can quickly translate from mental image to reality.
It may look ugly but don't knock it til you've tried it. It changes everything.
For components, you have no styles outside of your component partials, so nothing influences a component except what's targeting it. All targeting is via BEM naming, so no inheritance even for nested components.
So that's components, however sometimes things change depending on their context, which is really messy if you're using inline styles. You end up introducing logic, or you end up with different kinds of components for different contexts and having to maintain them all.
When using components/contexts, if for example a product-card on the checkout needs to look different in some small way. You just have a _checkout.scss file, and in it you target .checkout-page .product-card, and that's it. Simple, clean, no weird inheritance/overriding issues, just hygienic scoping of CSS and one level of inheritance available if needed.
The product-card never has to concern itself with checkouts, and the checkout knows it has a product card so it makes sense that it controls any changes it wants.
I've been using this method for a while now, the majority of the time you end up with ~10-20 small component files, and then 4 or 5 context files with maybe 20 lines in them. You know exactly where all styles affecting your component live, it ends up really clean and easy to maintain.
If you use (S)CSS modules, then you don't even need to worry about BEM.
Anecdotical, but the best improvement I've achieved doing this is shaving off ~30% of our final bundles, gzipped!)
How does your CSP stop a script from adding styles to DOM elements? <script> document.querySelector(‘body’) .setAttribute(‘style’, ‘my malicious css?’); </script>
Edit: As for scripts adding things, the CSP prevents the style attribute being applied iirc.
[1] https://developer.mozilla.org/en-US/docs/Web/Web_Components/...
In modern web applications, it's
pretty self evident that components
are the right solution
I often see this argument of "self evidence" made by developers who claim that some modern "best practice" approach is the right one.In my experience it is an indication that the proclaimed "better" approach is actually inferior. And the author had to resort to the argument of "obvious self evidence" because there are no better arguments around.
I think it is driven by what I call "tool religion". Developers who invested significant amount of time into learning a tool become religiously attached to it. Because they now want to be an "expert" of the "best way". Not just "Some guy with a preference".
"Component based" is basically just "functions composing other functions and calling each other in a top-down flow with bottom-up updates through framework state". It's "evident" that it's the correct abstraction because the alternatives (things like managing app state and UI interactions through MVC, MVVM and MVP) are mostly not needed or are not the right level of abstraction for composing large UIs in web apps (where components make it trivial and shift the complexity to stitching the state manangement <-> component interop when you need to break the abstraction).
Also - components are pretty uncontested these last few years.
If I can't see it given that I have actual experience with what you're talking about and can reasonably be expected to have the background to understand, how is someone from a different field supposed to understand what you wrote?
I don't think so. Many people still use traditional frontends, i.e. static or server-rendered HTML and CSS.
Components are newer and there is still more to talk about, so they naturally are more prominent on sites like hacker news. That doesn't mean they are uncontested in practice.
I think this is a reversal of the best practice of complex CSS class hierarchies. Having flatter and fewer CSS classes and more inline CSS will result in redundant style information, but having fewer CSS rules apply to nodes is a win overall.
Every CSS rule is effectively in global scope.
We had this problem in programming forever. These days, you can put your function in a class in a namespace ... still the namespace sits in global scope. But we never came to the conclusion that we should make all code inline to solve it. Fortunately.So if you make a CSS rule to make links in your userlist red:
.gizmosUserlist .name a { color: red }
Then yes, it will apply to other .gizmosUserlist instances.Shadow DOM is a way to prevent it if you want.
Personally, I think it is a good thing, that you can make all links in all gizmosUserlists red if you like and can target a specific one with a more specific selector if you like.
They are, and that's why sibling and child selectors exist. If you only ever define simple classes with no thought about how they'll work in the overall app then you're in for a bad experience with styles cascading to things they're not meant to affect. If you actually use CSS the way it was designed then you have complete control over exactly what styles are applied to which elements.
A good rule in component based development is to define a class name for the component and use ".unique-component-class-name > .class-for-things-in-this-component" to limit the application of styles to that component. This takes a bit of discipline but it's pretty obvious when you get it wrong.
I've seen that inline CSS seems to be the latest trend, but I haven't really read up on why myself. Is this post really the current thinking? I find it completely uncompelling.
See my other comment in this thread (https://news.ycombinator.com/item?id=24221241) for how I'm tackling that sort of problem at the moment. tl;dr Work out what the dev should be able to override in the style at runtime and make it a CSS var that's set inline in the component. As I said there, it might not be the best approach especially in very large apps, but it does seem to be working well for me.
Nobody bats an eye when a compiler unrolls a loop, and you get N copies of the same code in assembly. In the same sense, nobody should care how clean the "assembly" of the web is (CSS+HTML).
I think the author is justified in saying that designing with components in web development has become self-evidently better than not. All new web frameworks are component-based. Web Components were added to HTML. Pretty much all web developers agree on this.
Are you a web developer? Do you disagree that the benefits of components in web programming are self-evident? If so, that is definitely surprising to me, and probably to the author.
That's all, nobody else in this particular thread said anything about whether that means inline styles is the way to go.
You might want to post your question to the author of the blog post, or as a top-level question.
Would you say that this very site - Hacker News - is using this type of "components"?
Realistically, people were probably doing the same with perl scripts before that.
And any definition of component is going to find it hard to exclude standard html elements, other than by specifying that it's users being able to define new ones, and not just browser vendors.
Incidentally, CSS was the original implementations of user-defined components: it allows defining certain behaviours once, for a "class" or group of similar elements, then using it repeatedly.
I don't have the feeling that what he really means with "Inline CSS works better in a component world" is "Inline CSS is the better choice since the 90s".
Your question is slightly nonsensical, because components are not a design language, and it's not something you can see by looking at a rendered web page. To know whether Hacker News is using components, I would need to look at the source code, because components are a programming paradigm.
If you're asking me to comb through HN's JavaScript to see if they use that paradigm, well, no thank you.
This definitely leads me to believe that
you don't have much experience with modern
web frameworks
Here we go again. It would have suited the discussion even better if you said "it is definitely self evident".The rest though is not what I intended to get across. I've done it both ways, the inline way works better for the component model is what I'm saying. If a different model comes along in future, there may be a better approach and I may switch to that.
This isn't about there being one right way, just more appropriate ways for different paradigms.
I've been experimenting with a sort of hybrid model of dynamic CSS recently levaraging CSS variables. Most of the styling work is done in static CSS files for things that won't change (because caching is good), and those styles are applied to components with classes. The dynamic bits are also defined in CSS, but populated with CSS variables that have values set inline in the components. A trivial example would be;
.panel {
flex: 1;
background-color: var(--themeBackgroundColor);
}
<Panel className="panel" style={{'--themeBackgroundColor': `${userDefinedColor}`}} />
I don't really know if this approach is better than either plain CSS or styled components yet but it has solved some relatively complicated issues I was having with calculating positions of things and needing waaaaaay too many classes.One thing I'll go back and reword in the article is this notion that inline == style attribute. I can see how this comes across, but I'm really talking about 'inline' the pattern more than a specific implementation. Using CSS-in-JS to add styles to a style attribute is one implementation, with, as you point out, some downsides - there are others that provide more features while keeping the component-centric model.
- If you use something like React, Angular or Vue - use the CLI a loader with "hot reload" so changes in your files are instant and don't interrupt app state. That's the "best" option. - If you're stuck on an old build - set up storybook or just a separate endpoint where hot-reload works/is possible. - Otherwise use the Chrome DevTools "workspaces" feature that lets the Chrome devtools write automatically and update your files - that would save the "copying it over" part and also supports things you'd expect (like source maps).
As ever the answer is no one way is so superior in every circumstance that the other should be dismissed outright.
Defining your overall base and then only specifying the 'diff' between the base and the component is probably a reasonable goal.
Having said that, I don't like and don't do inline CSS.
Let's take some projects of various complexity - some personal webpage, online calendar, social app, etc.
And lets do these in Vanilla CSS - just some clean proper style.css in the <HEAD> and exactly the same project with all the inline styles with some JSS etc.
And let's discuss then. At what point in project's complexity what makes more sense. Which code is more readable/maintainable/etc. Performance gains and etc.
- Sharing styling libraries (currently done via css files) across multiple web development teams, giving the ability to a central team of designers/developers to modify the look and feel of dozens of websites of the company
- Media queries, sass mixins and functions
- Components can be used in different contexts. The styling can be dramatically different in these contexts. Overriding the "style" attribute is harder than overriding a css class definition.
- Worse developer experience while trying to reason about the styling of a particular page. Image you have a page composed of multiple components. I think (and thus argue) it is easier to glance at a css file (or multiple css files) to understand how the whole thing fits together, instead of looking at all the individual components files, mentaly filter out the markup to keep the css and try to compose a wholistic picture.
Repeating styles would be the least of the problem because of the gzip compression, no?
I like the "Controlling File Size" of the Tailwind CSS project: https://tailwindcss.com/docs/controlling-file-size
They DO tell developers to remove unused CSS when building for production of course, but in case you ship the whole (big) default file, it goes from 2309.7K to 180.6K (Gzip) or even 43.6K (Brotli)!
Exactly - perhaps 'colocated styles' might be a better term than 'inline styles'.
> Do web components use shadow-dom style scoping now
Not sure, I don't use or know much about Web Components (the technology) - by 'component' I just mean the web framework pattern of modularising a bunch of markup/behaviour (and styles if you agree with the arguments in the article!)
Also, how does it work for pseudo elements, state selectors etc. ? I can just see examples for media queries.
In my opinion it's also not really nice to read, just look at the example on his github page https://github.com/propjockey/css-media-vars.
Do you really think this is easier to read than normal media queries ?
I also agree that it’s not particularly easy to read, but since the whole premise is that you are writing components, you can simply abstract away this ugliness in whatever way makes sense to you.
The result is similar to various CSS-in-JS solutions, but conceptually simpler: instead of having a library that has to manage inserted stylesheets and generated class names, you just generate (uglier) inline CSS directly. It also makes static HTML output trivial, without any of the fragile build process used for CSS-in-JS - all you need is that one static CSS file and the generated inline style attributes.