
Inline CSS works better in a component world - davnicwil
https://davnicwil.com/inline-css-works-better-in-a-component-world/
======
chrismorgan
This article seems to completely ignore the biggest area where inline CSS is
problematic: dynamic, state-dependent styles. That is, things like
pseudoclasses (hover states and the likes) and media queries.

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.)

~~~
diob
I went from styled, to just using style as much as possible, to finally using
tailwind. It's a wonderful development experience, and I hardly ever need to
go beyond it. Can't recommend it enough, it makes developing quicker and
simpler. And in the end, the product ends up looking way more consistent than
anything else I've tried.

~~~
j-krieger
I wish there was a mode to tree shake tailwind in production. Automatically
extract all the class arguments into css classes for a cleaner markup

~~~
akoutmos
While there is no automatic way of doing it (as far as I know), I have been
using Tailwind's @apply directive for things that are used site wide and that
has worked out well. Really excited to use the latest 1.7 version that makes
this process even easier given you don't need to split up pseudo classes
[https://github.com/tailwindlabs/tailwindcss/pull/2159](https://github.com/tailwindlabs/tailwindcss/pull/2159).

------
captainmuon
In the old model, you had semantic markup (ideally) and css on top, that you
could swap.

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 :-)).

~~~
Izkata
> ModernButton, DarkButton, RetroButton. But there is a lot of room for errors
> and the interfaces can diverge.

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.

------
floppiplopp
And so, the modern web becomes an unmaintainable, monolithic clusterfuck with
the illusion of modularity. It's the idea of the 90s with the complexity of
2020 - just because people cannot handle the simple core concepts of CSS.

~~~
marijn
I'm not going to defend the article, but I really bristle at this idea that if
you just _get_ CSS it isn't problematic anymore. CSS tries to solve a hard
problem and it's certainly preferably to inline-everything, but its design
(global, cascading, with many types of behavior—positioning, z-stacking,
etc—depending on the styling of parent elements in interesting ways) is
actively hostile to many kinds of modularity, and that's a real issue even for
people who "get" CSS.

~~~
IfOnlyYouKnew
Cascading / depending on the parent's style are features specifically intended
to _enable_ a component-based approach. It allows, for example, to use h1's in
your component, but have them render at appropriate sizes depending on their
level in the overall hierarchy.

~~~
lioeters
Cascading is, to me, like class inheritance in object-oriented style of
programming. Useful in some cases, but can become unmanageable with more than
a few layers.

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.

~~~
lioeters
Apparently someone didn't appreciate the jab at OOP. Well, I call it like I
see it - seen more messes made by class inheritance and cascading, than
without.

------
habosa
Yes! This is dead on. I can't stop evangelizing Tailwind lately:
[https://tailwindcss.com/](https://tailwindcss.com/)

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.

------
ehnto
I'm still against inline CSS and what are essentially inline css helper
libraries (tailwind etc), but a big part of maintainability is co-location of
related code, which inline CSS provides at the cost of readability and
control. I feel you can get most of that benefit with well organised SCSS,
specifically something similar to the components/contexts model.

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.

~~~
nicoburns
> All targeting is via BEM, so no inheritance even for nested components.

If you use (S)CSS modules, then you don't even need to worry about BEM.

~~~
j-krieger
If you use CSS Modules, you can not target an elements children with another
css module class name. You can‘t know the hash beforehand

~~~
nicoburns
You could import the parent CSS module in the child. It might not be a bad
idea to make the dependency explicit like that if the components are so
tightly coupled.

------
qubyte
I'm mostly a server dev, and I'm keen on a nice strict Content-Security-Policy
(CSP) header which rules out inline CSS. The benefits (preventing extensions
etc. from injecting style in a way which may constitute an attack) outweigh
the convenience of inlined CSS for components in my opinion.

[https://developer.mozilla.org/en-
US/docs/Web/HTTP/CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP)

~~~
RyanGoosling
I’m curious. Can you provide an example where CSS can constitute an attack?

How does your CSP stop a script from adding styles to DOM elements? <script>
document.querySelector(‘body’) .setAttribute(‘style’, ‘my malicious css?’);
</script>

~~~
qubyte
Attack is stretching the term sightly, I admit. It’s possible for a malicious
style to reorganise things on a page in a misleading way, or place a lewd
image in a background for example.

Edit: As for scripts adding things, the CSP prevents the style attribute being
applied iirc.

------
Ahch1eep
I've been rewriting my personal/private tools from React to standard
webcomponents, lately, and one of the things I love the most is the shadow dom
[1], which allows to sandbox styles within a component. It's best of both
world, basically.

[1] [https://developer.mozilla.org/en-
US/docs/Web/Web_Components/...](https://developer.mozilla.org/en-
US/docs/Web/Web_Components/Using_shadow_DOM)

------
FreeHugs

        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".

~~~
gizmo
Every CSS rule is effectively in global scope. And as the complexity of web
apps increases regression testing becomes a bigger and bigger challenge. Being
able to insert components multiple times and not having to worry whether an
innocuous CSS change can result in "spooky action at a distance" really helps.

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.

~~~
chii
the inline CSS is not redundant, because redundancy only applies to the
source, not the output. And in a component world, the source is the
js/compiler/component source code, and the output is what's on the page. I
wouldn't care if the css is repeated for every component that's rendered, as
long as it's clear from the source code of the component (or js source).

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).

~~~
amoe_
I'll believe that CSS+HTML is the "assembly of the web" once I have to touch
them as little as I have to touch the output of my C++ compiler or Java
bytecode. Right now, any web developer has to be very comfortable with
debugging HTML and CSS issues, whereas it's entirely possible for a competent
Java developer to know literally zero about bytecode.

~~~
type0
That argument falls because it was never designed that way. If you want broad
browser support and careful testing of edge cases you can't threat it that
way, even with WASM you likely won't escape it.

------
onion2k
Because why would you care about caching static assets like CSS files in the
browser, right? Loading all that data every time the page loads makes a
developer's life easier and we don't care about users and their bandwidth
obviously. Hmm. Perhaps if you're David Nicholas Williams, but not if you're
me. I only want users to have to download things they need once.

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.

~~~
mattacular
You can use tools such as webpack to write css scoped to component-level so
that it extracts and bundles all that css into files so the user can still
benefit from browser cache between deployments. This is of course a great deal
of tool/config complexity but it may be worth it depending on your app.

~~~
j-krieger
Yes. This has been a default since Webpack 3. The fact that most people on
this site don‘t know that all modern bundlers extract css shows they have no
clue what they are talking about.

------
pvsukale3
TailwindCSS recommends a similar approach to avoid repetition of common css
code. Abstract CSS components at framework partial/components level.

------
zuhayeer
I've been on the inline CSS hype, it makes rapid prototyping so much faster.
Also if you use Dev Tools / Inspect Element to dynamically edit your web
frontend its so much easier to test things and then just copy it over.

~~~
inglor
You don't need to copy it over - that's an incredibly frustrating flow
compared to what you can get where you have to copy the correct thing or a
refresh overrides your work.

\- 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).

------
weego
'probably better compression' is an understatement.

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.

------
dsego
Reusable components != reusable styles. Many functionally or semantically
different components can resemble and share the same styles. One solution I
guess with inline is to have a few levels of nested containers and params?
Like <RoomyBox withShadow roundedBorder><LayoutBox><>etc
etc</><LayoutBox></RoomyBox> vs <div class="layout roomy-box">. Not sure if
this is much better way of reusing common styles than using css classes.

------
AndrewThrowaway
It would be interesting to see some data, some A/B test of these ideas.

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.

------
gtsop
I feel like this is yet another© solution to an arrificial problem caused by
inability to understand the web platform and existing tooling options. I can't
even list the multiple levels of wrong with this approach.

~~~
davnicwil
Could you list a couple of the most important ones? If aspects of my approach
are wrong or could be improved, I'd be really interested in learning why :-)

~~~
gtsop
Yes of course:

\- 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.

------
njsubedi
> Probably better compression by not repeating styles everywhere

Repeating styles would be the least of the problem because of the gzip
compression, no?

~~~
onion2k
I suspect that if you're using React's 'style' expansion using an object, the
order of styles that are written inline is going to be non-deterministic which
means your compression won't be optimal. It'll still work, obviously, but not
as well as the compression you'd get if you used a class name.

------
somishere
Inline means no logic /state / pseudo.

~~~
tobr
That used to be the case, but it’s not true any more. You can use custom
properties to react to media queries and pseudo selectors. See
[https://propjockey.github.io/css-media-
vars/](https://propjockey.github.io/css-media-vars/)

~~~
wtf_srsly
That's just a hack using css custom properties that still requires a global
css file to define all breakpoints on the html element.

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](https://github.com/propjockey/css-media-vars).

Do you really think this is easier to read than normal media queries ?

~~~
tobr
Yes, you still need a CSS file or <style> tag to set up the breakpoints, but
it’s going to be tiny and not something you actively work in unless you want
to add a whole new breakpoint.

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.

------
romanovcode
Yes, this is why you use tailwind.

