Imagine a programming language that only had global variables.
You have to carefully name your variables using complicated conventions in order to avoid any conflicts or unexpected behavior.
Even your functions don't have local variables; there is no lexical scoping. Any function can overwrite or mutate what any other function is doing inside. There is no real encapsulation.
After you've done this perfectly, your application gets bigger and you start wanting to reuse third-party modules made by other developers, because they've already solved some of your problems.
Uh-oh: they didn't follow exactly the same conventions, and now things conflict. Or their variable names were perfectly unique in their own code base but not when combined with yours (or when combined with several other third-party modules).
This language is CSS and is why people are so fed up with selectors. Even "scoped" selectors really aren't lexically scoped in the sense that other languages handle scoping... it's still just another naming convention hack.
I use CSS-in-JS because CSS wasn't designed to be a language that survives attempts at modularization, third-party code sharing, etc. No sane programming language attempting this would only have global variables. So, we throw out the selectors part of CSS and keep the rest, at least for now.
Nobody using CSS-in-JS thinks this is an ideal situation. Nobody wakes up thinking, "oh my god, I need to put my CSS in my JS, it would be perfect." We're just trying to deal with the hand that's been dealt.
This is sad. All because people are not able to think of one simple prefix and stick with it when naming CSS classes. How hard can it be? Just use some part or abbreviation of the company name and be done with it. Or better yet: Let third party do that. I always hated that, when someone used Bootstrap on a website and Bootstrap f'ed up all future styling, by assuming it was the only one player in the game. So stupid.
I personally never ever ran into any problem, when I myself named CSS classes and that is because I automatically think about the future and whether a name could conflict with something else, instead of being lazy and typing 3 characters and thinking I did my job. I am simply careful and use prefixes and give unique names, so that it has such a low chance of someone else using that CSS class name, that it simply never happened in practice. So from my personal experience all that mumbo-jumbo about CSS name collisions comes from people not being careful and is a "house made" problem, not a problem of CSS. I never had any need to use JS to do what is CSS's job.
Using JS for doing something CSS should do is furthermore dangerous, since clever people deactivate their JS or block it partially. For me personally, your (not you personally, but you in general, anyone who reads this) JS better comes from your own domain, or it will be blocked by default. If you can live with people seeing your website utterly destroyed by its inability to apply style, then OK, do the styling in JS.
I'm happy that just prefixing things is working for you. I don't typically have problems on smaller projects.
But I've also been writing CSS since 1997. I've deployed CSS to sites like walmart.com, nfl.com, mlb.com, starbucks.com, twitch.tv, etc. Some of these sites have a lot of third-party widgets on them. I can confidently say that the (multiple) issues with CSS are not a "just do <simple thing X>" type of problem.
People want an interface such that a folder represents all they want to know at that moment about a component. But then someone else may want an interface such that a folder can represent all the styles across the app.
Otherwise I do think that the naming collision problem is really easily fixed.
Angular implements a polyfill for this. Every angular component has 3 files html, ts, (s)css, and the styles in the components css file are automatically scoped to just the component they apply to. It takes away all the stress of global css selectors, and if you want to share styles you can just have a library of shared styles and import them via scss. It's honestly heavenly and I haven't thought about conflicting selectors in years.
I'm aware and agree, and it also – even if less so than other solutions like Styled Components – counts as CSS-in-JS. So welcome to enjoying CSS-in-JS :)
Or use Polymer/LitElement, where it's just all in one file... I swear people are just reinventing react methods to eventually get to where Web Components have been for the past 4 years.
I agree CSS has problems. What I don't see is how styles-in-JS addresses them.
Very typically, for a given app and page the styles of individual elements and components are not independent. They also depend the app theme, app section, layout area, component group, etc. The element fits the component. The component fits into the section, the section fits into the page. The specific relationships in a particular case are different of course. Styles are visual and the idea that a component on a page has nothing visually to do with the rest of the page is wrong.
The typical scoping rules of programming languages doesn't fit that well here.
To the extent some styling solution encourages you to treat styles that are dependent as independent, that's not a good or useful thing.
I don't entirely understand why some people find CSS so difficult to work with. I agree that it has its own challenges, but solutions generally aren't very complex. Global selectors ("variables") collisions? Use namespacing. Specificity is convoluted? Simplify by using only non-nested classes.
Does the annoyance primarily center around the fact that styles cascade to child elements? Hard to tell from the article.
Good software is reusable. I can import functions from 1,000,000 different npm modules all into my project and they don't fuck with each other, right?
Let's say you wanted to pull in a button from Bootstrap for one part of your page, a button from Material UI elsewhere, a button from Semantic UI elsewhere, etc.
These things are made to be reusable right?
What are the chances you can do that without issues? Do you think any of their style rules/selectors would clobber each other? What about the base/assumed CSS that they all most likely require? What about components more complicated than a button? Without actually trying it, how much confidence do you have in your guess, vs. your assumptions about importing other things (like functions from npm modules)?
On the flip side, after using CSS in large projects for years with many, many third party libraries, I've never once felt this urge... Rarely had any problems. At least none that the effort of styling everything in JS would merit!
Not a solution for CSS I guess but if I was using a programming language that had only global variables I'd write a compiler to generate variable names.
I don’t really understand this comment. Emacs lisp always had dynamic scoping, which is a bit more than just global scope because you aren’t quite stomping on top of other variable bindings. You get resetting your bindings to what they were before you started for free and you don’t need to worry about nonlocal exits. Emacs lisp also has macros and gensym to avoid some of the pain of name clashes.
Emacs lisp also has lexical scoping. It optionally had it for a long time using cl.el with lexical-let and friends. It now has it as a file-local variable read by the compiler/interpreter.
I also don’t understand what you’ve written at all. You say “Nowadays it does support semantic scoping” but semantic scoping isn’t really a thing (as you next write lexical scoping, I assume you mean dynamic scoping), but the words “nowadays,” “but,” and “still” imply that you are talking about the new kind of scoping (ie lexical) and comparing with the old (dynamic, which you cal lexical???).
And HTML is a markup language for hypertext, a document rather than an application.
But it turns out that we're using it and CSS and JavaScript to build full blown applications. So, because we're trying to solve problems with applications rather than documents, we have to map the problems of application programming onto it.
So, to build an application, we run into problems CSS wasn't designed to solve (being a not-programming language.) Whether it is or isn't a programming language is irrelevant - to solve our problems (writing applications), we have to treat it as if it is.
I understand the "pit of success" idea, particularly when it comes to more junior devs. But I don't necessarily agree that you need stringent processes to get most of the gains you cite from using something like SCSS or even regular CSS these days. It's really easier than ever.
1- append only? No, each module/feature/widget gets its own CSS file, imported to the main app CSS file. Delete the widget? Delete the file.
2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure (doesn't have to be BEM, it could literally be ".widgetName-header")
Since I adopted those 2, I've almost never had dead CSS from deleting features or collisions in my CSS. I do still have a small base set of styles that are shared but it's small enough to be easily manageable.
3- dynamic properties? CSS variables. Not an option? Child classes that apply the dynamic styles serve most use cases. Truly dynamic styles are rare, in my experience.
I'm still keeping an open mind about the possibilities, but my strong opinion (weakly held) is that I still don't see CSS-in-JS as more of a bandaid for people that like CSS and (for many, not all) those that don't have an in-depth understanding of it.
All three of the points raised are just dismissing the root of the problem and offering a "solution" using plain CSS classes that relies on everybody following some bespoke convention to work around the problem rather than addressing it head-on like CSS-in-JS solutions do.
1. and 2. attempt to address the lack of modularity in CSS through convention when you can have guaranteed modularity through auto-generated CSS classes that are content-addressed and thereby globally unique by definition with CSS-in-JS. Not to mention you can use a real module system for sharing styles instead of being limited to sharing variables through some global context, which again opens up the possibility of name clashes.
3. recommends a solution for dynamic styles based on yet another CSS feature that relies on global namespacing, and then a fallback based on string concatenation that can't actually address all dynamic use cases. Then it goes on to dismiss the use case entirely, when in a single page application, all styles are inherently dynamic based on the state of the components that are currently being rendered, which is why there's such a painfully obvious impedance mismatch when implementing anything that's truly dynamic using CSS classes, when you have to resort again to concatenating lists of static classes together rather than mapping state to styles directly like you could with CSS-in-JS.
Of course, I'm not saying those approaches can't work at all, nobody is saying that. You can obviously make them work, and people have used those approaches for ages before CSS-in-JS came along. But using the existence of those approaches to dismiss a different approach that tangibly addresses the inherent flaws of those approaches doesn't feel like a particularly compelling argument.
Yes, it's dismissing the root of the problem because I am not convinced the "cost of doing CSS" is enough to justify moving to something like CSS-in-JS. Again, as I said above - it's a strong opinion, but weakly held - given enough evidence, I'd reconsider my position.
My point with the examples I gave was just to show that it's possible to handle the issues the author wrote about. I'd prefer to see efforts to fix the issues in CSS instead of discarding it completely in favor of a JS solution.
I'm not saying I can specify how to "solve" CSS issue in a couple paragraphs. As regards #3, that's specific to the kinds of dynamic styles I find most often in web apps. Very rarely do I see styles generated dynamically where it isn't effectively a choice between a couple of options (in my experience, of course). And when you do, you can just write out styles from the JS into the template (and I've definitely done fully dynamic styles in that way when it is necessary). Dynamic styles would be a place where I could see a fit for CSS-in-JS, btw.
The global namespacing this is something I believe is being worked on in the CSS Modules specification, but again, that is really easily solved. I can say loading external libraries can mess that up (i.e. Bootstrap and the ilk).
I don't care what people use, I'm glad the argument is what the author (who co-wrote the styled components lib) was what he liked. But I am really concerned that some proponents promote their way as the only way forward. Personally, I haven't found a situation yet where CSS-in-JS would materially benefit the application over a careful, convention-based approach. And I want to make sure people know there are other options that work.
I agree with you. I've done both approaches at scaled, and I'm still not really sold on CSS-IN-JS. Of course, I think it's a matter a taste (and maybe experience?) so to each its own.
Personally I much prefer using separate css (or sass) file, one for each component (assuming you also have a "layout" component for shared styles) and import each relevant css file as a module.
This way you keep writing our CSS out of your JS, but still can keep it scoped to your component. It's also obvious what css a component uses, and each to grep for when you want to delete some css.
It addresses some of these points at 35:23 - that you can kind of make CSS work if you always do everything right, but it's not as easy in practice (most of the experience stuff is at the beginning - which shows that they did kinda do everything "right").
This rarely happens. I would argue that creating an automated system to enforce "rules" should be favored over forcing every developer to know the rules and abides by them.
It is much easier to understand the relationship between css and js when the css is just a js variable.
Having built many large applications using the CSS file method, css modules, each widget gets its own file, co-locating css files with the js, I much prefer using `styled-components`. It provides a ton of flexibility, it opens doors for dynamic css by leveraging js (the hacks I've seen, had to write to get css dynamic is astounding), and I don't have to look very far to see how it's being used because the CSS is literally attached to the component I'm using. All I do in VSCode is cmd+click and bam, I can see the CSS for this component. There's no need for naming convention, there's no worry about global css variables getting into your styles, and there's no digging around looking for css that might be influencing your component. The best part for me is: when I delete the component, the CSS is gone as well. There's no thought put into scouring the FS to find lingering CSS that used to be used.
I love `styled-components` and most of the designers I work with also enjoy it.
I take issue with your assertion about how IDs "are intended". I think that idea (and CSS being taught that way) is one of the reasons people have trouble with CSS.
There are quite a few reasons for preferring to not use IDs, here's two:
1- specificity of IDs always trumping things
2- having to change it from an ID to a class later on if it becomes a reusable item (which in a widget, is almost always the case). There is no reason a class cannot apply to just a single item, where an ID is by its nature limited.
Because one is an extension of the underlying technology, and the other one changes the technology out altogether. I still believe CSS is a vital part of the web ecosystem, and we should work to fix the underlying issues rather than just try to work around it via JS.
> 2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure
I have one exception to that in my own work, which is to only ever use IDs for styles that affect the layout of a block/component on a specific page. This makes sense since parts of a page layout are usually very specific and not that dynamic(in which case class names might be more appropriate). At the same time, component-level styles should never make assumptions about how they are positioned on a given page.
Let's say that we have a page `/blog/:entry_id`, and this page has a right-hand column to list related blog entries. This component would have an id `#blog-entry__entries-list`, which would control how the related-entries list appears on the blog-entry page(in this case, putting it in a column on the right), and a `.entries-list` class that controls the global appearance of the component.
This way, the entries-list can be used in different contexts without having weirdness caused by a margin working fine on one page but having to be negated on another page where the margin doesn't work. Try to add styles, but do as minimal overriding as possible.
In combination with BEM, primarily for the benefit of all selectors having the same specificity, I've found this separation of concerns between IDs and class names to be very powerful and simple to understand, especially since it doesn't require more verbosity.
Another part of my styling workflow is Sass mixins.
Let's say that we want the entries-list component to appear more compact on another page. Perhaps it appears somewhere on the site index, and takes up a little more room than we'd like.
Since component styles can't assume anything about their environment, and since layout styles(i.e. our ID selectors) can't know about the inner workings of their components, there needs to be a way for layouts to have a choice of component variations.
In this case, I would create a mixin `entries-list--compact` inside the entries-list Sass file, which would contain CSS properties that would make the entries-list smaller.
Back on in the index Sass file, I would include that mixin:
I've found this pattern of mixins to be very powerful. Any page can decide whether to use any mixin at any page-width. CSS for layout stays very lean, as the only properties it's concerned with 99% of the time is width, height, margin, and padding. A component can be completely replaced with new styles and behave properly on existing pages so long as it conforms to its existing "API" of mixins.
We built a relatively large social media management platform, and for one of our major features (a streams page that shows social media activities from different sources), we put a lot of our css in JS including all the logic for stream sizing/resizing and page responsiveness. I can honestly say that this approach is terrible. It is a maintenance nightmare. Even the smallest changes require a ton of time. We're now rebuilding the page from the ground up because it has gotten so messy, no one on the team is interested in touching it.
> Why don't we have more : "We tried it, it is the worst, especially for products which lifespan is more than two months"
Because that last sentence is just rubbish, CSS in JS is great. I'm using it for large projects already 4 years. If your experience is bad you must be doing something wrong. CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.
At my company, I made the executive decision to drop CSS-in-JS because none of those libraries support PostCSS, and most have their own from-stratch, half-baked CSS transformation pipeline, not 10% as powerful as the PostCSS ecosystem.
I love PostCSS, and I'll happily consider CSS-in-JS again when somebody writes a library that doesn't try to reinvent the wheel.
For one thing, it's not CSS in Javascript... there's no cascade and no sheet, so it's just "styles in Javascript". (And, actually, this article is only about a specific implementation.)
The benefits listed are:
- "confidence" - but I think that's a matter of understanding and mastering the tool, whether it's CSS or this library. As the co-creator of "styled-components" the author is no doubt a master of it. For for the general developer, perhaps a roughly equal effort would provide a similar level of mastery in each. So why not invest in the standard?
"Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.
"Enhanced Teamwork" - I don't see the connection here. The discussion in this section seems to be about mastery of the tools again. The team can learn how to manage styles though CSS-based techniques or they can learn through techniques based on coding Javascript and the capabilities of this library.
Not that CSS doesn't have its issues. IMO, it's too low-level to use directly for many cases. There are two main problems:
(1) missing the tools to manage complexity, like scoping, variables, and modules. (2) allows you a lot of freedom to do bad things. But there are libraries that address these that don't throw out the fundamental design of CSS, as styles-in-code does.
To me it seems like a better approach to build on CSS to address its weaknesses rather than throw it out.
The design of CSS itself came out the recognition that the tight coupling of style and content has drawbacks, and this is signing back up for those drawbacks. And you better neatly divide your presentation code from your business logic code and data access code or you'll get all that coupled tightly as well.
I'm not dismissing this out-of-hand -- I haven't dug into styles-in-code approach so I don't have a deep understanding of it.
But I'm not convinced it's worth the time to look more closely at it. Really, not even close.
> "Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.
But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.
The potential problem I could see is that changes which would have been easy with a cascade would require lots of changes to copypasta in this approach. Like, "take the spinach out of this ravioli and replace it with mushrooms." Everything is scoped properly and the task is obvious at a glance-- it's just annoying.
> But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.
Ah, well, things are not that simple.
In a project of any complexity at all, the style of any individual element is typically dependent on a number of things which collectively make up the context of its presentation. E.g, the site theme, the component, and the individual element (at least -- usually there's an app-subsection and components are usually grouped into modules, etc.).
Note that this is inherent to the problem space and is true whether you're specifying styles in code or styles in cascading style sheets or any other way.
CSS provides a basic mechanism for dealing with this -- the cascade (though as I mentioned, IMO it is lacking some necessary features). Styles in code needs an answer as well.
If you were to simply hard-code styles at the element-level (which you can do using either mechanism BTW though its probably easier with style-in-code), you'll have a hard time finding all the places in the code you need to update if you want to make a change. You'll be doing a lot of full code searches, reading code, and trying to put yourself into the mind of the person who wrote the code in the first place.
The "spaghetti" in the metaphor are the lines of dependencies. We have spaghetti code when those lines are disorganized, entangled with irrelevancies, obscured, and otherwise unnecessarily difficult to deal with.
In fact, if you hard-code a style on an element that is dependent on the site theme, app section, component module, and component, you'd be hiding those dependencies, which creates spaghetti code rather than avoids it.
Now, I expect most developers would naturally try to avoid doing something like that. I'm just trying to point out why style-in-code doesn't really help you avoid spaghetti code.
Hm, I don't share your opinion on this matter, to be honest. You can easily avoid this in both Angular (which does it out of the box) and React by including CSS Modules (https://github.com/css-modules/css-modules) which, if you use create-react-app to build your projects, is a 5 minute change to your architecture. So there really is no reason to write that down as a con for React.
I have so many small components that I would loathe to have a separate stylesheet. Yes, it's a small thing to just switch tabs, but this is a small problem. And these small problems add up and can be a huge pain. I really really like the SFCs in vue and compare it to a bit of butter on toast. It might be a small thing, but it seems like it makes a big difference.
You can avoid many things by forcing yourself to use this and this practice. In my experience not all developers out there know what is "good" and what is "bad" practice and there are certainly many React developers out there who never heard about CSS modules. Let's say better it's not a flaw in React but a trap which can cause huge maintenance headache in my opinion.
You're right, but community support around a certain pattern often makes it the de-facto practice, so defaults matter even for a non-opinionated library (where "defaults" are essentially what tutorials and thought leaders point to)
What you linked is "CSS-in-JS" (in the sense that the library/framework you use transforms the output for you, for convenience, i.e., you're not writing BEM or whatever - same as in the original article). Vue scopes the styles by adding a data attribute.
To me this seems really implicit and magical and strange.
Where is template getting assigned to the code inside the script tag?
Does OtherComponent somehow mysteriously map to other-component? How does one pass arguments to it? Is a .vue file actually HTML or is it parsed somehow to be HTML?
The thing I like about React is the explicitness of it. This is a source code file that exports component X. Component X uses style Y as defined above because it's explicitly passed in as a prop, etc etc.
> and has a very wierd concept of how objects work in JS.
What is so weird about it? I personally find Vue vastly more approachable than React is, especially once you have to start writing all the plumbing to get all the libraries you need to go along with it to write a real world app.
> ] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.
Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)
CSS is just another add-on through Webpack when using Single File Components. Nothing really ground breaking here except for the fact that it creates a nice separation of concerns. This is especially true on teams with junior devs or designers. Or with a team that works on a site with mixed MPA and SPA features.
Yup, that's what you can have with precompiled templates. Riot.js introduced the same concept of scoped css years ago, I wish it was more popular. On the other hand it goes against the "it's just javascript" concept of React.
Be very aware that most popular CSS-in-JS libraries (such as JSS) will completely break CSP (Content Security Policy). The default reaction is usually "Just allow unsafe-inline in your CSP header", but this is dangerous advise as it will disable CSP! I've even seen 'experts' advising to use webpack to set a static value as a CSP nonce during build-time...
If you want to use CSS-in-JS, you'll either have to use server-side rendering to inject CSP nonces in your index.htm [0], or set up a complex build system to extract the CSS from your JS so you can serve them as .css files.
Using server-side rendering to inject nonces into your single-page client side rendered webpage is such an ugly hack. I'd prefer the second solution but I have not been able to find a solution like that, nor do I have the time to dive into the webpack rabbit-hole to do so.
The down-side with this is very high coupling between UI logic and style.
If style becomes out of fashion, you have to modify files that contain logic. If framework (react/vue) becomes out of fashion, keeping styles will be difficult.
The other down-side is thousands of web developers having to re-learn CSS and the tooling behind your app instead of just changing CSS files.
Your styles are coupled to your UI logic anyway, even if you go out of your way to make them implicit by separating the CSS and JS into their own files. It's better to have the relationship explicitly defined in code instead of hiding it. That's the whole reason why CSS sometimes breaks in unexpected ways: you fail to realize the implicit coupling of the styles and the UI logic, so you fail to reason what changes need to be made both to styles and the UI logic to make your change.
In practice, I think a lot of people have found that you can rarely do a complete overhaul of a website’s design using only CSS. Even if you could, it would be impossible to feel confident that your changes look reasonable across all uses of said CSS. So if you’re doing a big redesign you will usually have to work with logic anyway.
I think there’s truth to your second point though - reusing styles in parts of a project that does not use the same framework. Something like Tailwind CSS can be a good option then.
> you can rarely do a complete overhaul of a website’s design using only CSS
Full design yes, but branding/theming is much easier if you use an external styling framework like Bootstrap 4 or Foundation and use their component and utility classnames.
We have a 300+ page app and tried the one stylesheet per component thing with theme and layout all combined in the past, and was a huge mistake.
Banning most custom CSS in place of using the Bootstrap component and util classes has been so much easier.
Ok, but, the average startup web dev stays at a company for like two years? And then the thing eventually gets rewritten anyway in the latest flavor of the week, because nobody is using the same tools as two years ago.
I guess the concern for longevity most devs have is amusing when most software, if its not like systems level stuff, or problems most devs dont want to solve, tends to get disposed pretty frequently.
By the way, most of the software that actually sticks around was written in C and generally solves a problem most people wont tackle. Like zlib or sqlite or nginx or the linux kernel. You can almost pretty much judge the longevity of a piece of software based on how hard the problem it tackles is. Like encryption or compression? Those libraries are going to be around forever, because how many coders do you know that can write a semi compitent encryption library? And how manu coders can write a templating engine?
Like most of web dev is throwaway code. It just is. Arguments based on like "will they be able to restyle it in 10 years?" Well are they even going to be around?
If you're building a complex UI that uses components as a cohesive library, there will always be some coupling. Even with the classic bootstrap example, once you've built an application and introduced any number of third party components, it gets messy to change things.
Better to have a cohesive set of theme/rules and get them to work together as best possible. I've been a big fan of material-ui and react-jss and is imho about the best option I've used in over two decades of working on web based applications.
You don't need to use different languages to decouple things. A common pattern in React is to decouple logic and style using presentational components and container components (there are lots of articles on it if you Google those two terms), and I find that split to be much more natural than trying to split up HTML, JS, and CSS (which often need to cooperate with each other). One good practice with CSS-in-JS is to only use CSS in presentational components.
CSS... sweet memories. For some reason I never was able to learn how the damn thing works. I worked for Google Analitics in 2011 and we rebuilt it using new in house built framework which championed an idea of a separate styles for an on screen component. Every dev was starting a new component with: clean_styles directive as nobody was brave enough to deal with what comes from the top. Even though it was possible to use cascading part, nobody was brave enough to own styles for the whole product. So, We ended up with so many styles we had to split them in couple files as we reached a limit in IE on number of styles in one file. Last time I checked GA is loading 3 of them...
Is it a time for some other way of doing it?
I didn’t say I did not spend time, I said - could not. Same applies for most people in the team. I think we had coupe folks who were spending a lot of their time explaining CSS.
My theory is that CSS was something that was treated as a task. Make a lot of client/server side development and then make these freaking lines align perfectly. So, most of time engineers were avoiding styles, applying them was the most tedious and hated part of the job.
You have to carefully name your variables using complicated conventions in order to avoid any conflicts or unexpected behavior.
Even your functions don't have local variables; there is no lexical scoping. Any function can overwrite or mutate what any other function is doing inside. There is no real encapsulation.
After you've done this perfectly, your application gets bigger and you start wanting to reuse third-party modules made by other developers, because they've already solved some of your problems.
Uh-oh: they didn't follow exactly the same conventions, and now things conflict. Or their variable names were perfectly unique in their own code base but not when combined with yours (or when combined with several other third-party modules).
This language is CSS and is why people are so fed up with selectors. Even "scoped" selectors really aren't lexically scoped in the sense that other languages handle scoping... it's still just another naming convention hack.
I use CSS-in-JS because CSS wasn't designed to be a language that survives attempts at modularization, third-party code sharing, etc. No sane programming language attempting this would only have global variables. So, we throw out the selectors part of CSS and keep the rest, at least for now.
Nobody using CSS-in-JS thinks this is an ideal situation. Nobody wakes up thinking, "oh my god, I need to put my CSS in my JS, it would be perfect." We're just trying to deal with the hand that's been dealt.
I personally never ever ran into any problem, when I myself named CSS classes and that is because I automatically think about the future and whether a name could conflict with something else, instead of being lazy and typing 3 characters and thinking I did my job. I am simply careful and use prefixes and give unique names, so that it has such a low chance of someone else using that CSS class name, that it simply never happened in practice. So from my personal experience all that mumbo-jumbo about CSS name collisions comes from people not being careful and is a "house made" problem, not a problem of CSS. I never had any need to use JS to do what is CSS's job.
Using JS for doing something CSS should do is furthermore dangerous, since clever people deactivate their JS or block it partially. For me personally, your (not you personally, but you in general, anyone who reads this) JS better comes from your own domain, or it will be blocked by default. If you can live with people seeing your website utterly destroyed by its inability to apply style, then OK, do the styling in JS.
But I've also been writing CSS since 1997. I've deployed CSS to sites like walmart.com, nfl.com, mlb.com, starbucks.com, twitch.tv, etc. Some of these sites have a lot of third-party widgets on them. I can confidently say that the (multiple) issues with CSS are not a "just do <simple thing X>" type of problem.
Otherwise I do think that the naming collision problem is really easily fixed.
Angular implements a polyfill for this. Every angular component has 3 files html, ts, (s)css, and the styles in the components css file are automatically scoped to just the component they apply to. It takes away all the stress of global css selectors, and if you want to share styles you can just have a library of shared styles and import them via scss. It's honestly heavenly and I haven't thought about conflicting selectors in years.
Very typically, for a given app and page the styles of individual elements and components are not independent. They also depend the app theme, app section, layout area, component group, etc. The element fits the component. The component fits into the section, the section fits into the page. The specific relationships in a particular case are different of course. Styles are visual and the idea that a component on a page has nothing visually to do with the rest of the page is wrong.
The typical scoping rules of programming languages doesn't fit that well here.
To the extent some styling solution encourages you to treat styles that are dependent as independent, that's not a good or useful thing.
(You can also relatively easily implement your own, because JS :))
[1] https://www.styled-components.com/docs/advanced#theming
Does the annoyance primarily center around the fact that styles cascade to child elements? Hard to tell from the article.
Let's say you wanted to pull in a button from Bootstrap for one part of your page, a button from Material UI elsewhere, a button from Semantic UI elsewhere, etc.
These things are made to be reusable right?
What are the chances you can do that without issues? Do you think any of their style rules/selectors would clobber each other? What about the base/assumed CSS that they all most likely require? What about components more complicated than a button? Without actually trying it, how much confidence do you have in your guess, vs. your assumptions about importing other things (like functions from npm modules)?
Good software is reusable without worry.
It has different functionalities.
I live in the real world where it's used almost exclusively by programmers.
Whether technically it's a programming language or not is tangential.
Deleted Comment
Emacs lisp also has lexical scoping. It optionally had it for a long time using cl.el with lexical-let and friends. It now has it as a file-local variable read by the compiler/interpreter.
I also don’t understand what you’ve written at all. You say “Nowadays it does support semantic scoping” but semantic scoping isn’t really a thing (as you next write lexical scoping, I assume you mean dynamic scoping), but the words “nowadays,” “but,” and “still” imply that you are talking about the new kind of scoping (ie lexical) and comparing with the old (dynamic, which you cal lexical???).
But it turns out that we're using it and CSS and JavaScript to build full blown applications. So, because we're trying to solve problems with applications rather than documents, we have to map the problems of application programming onto it.
So, to build an application, we run into problems CSS wasn't designed to solve (being a not-programming language.) Whether it is or isn't a programming language is irrelevant - to solve our problems (writing applications), we have to treat it as if it is.
1- append only? No, each module/feature/widget gets its own CSS file, imported to the main app CSS file. Delete the widget? Delete the file.
2- Specificity issues? Never use IDs, stop using tag names and simple classes and adopt a simple naming structure (doesn't have to be BEM, it could literally be ".widgetName-header")
Since I adopted those 2, I've almost never had dead CSS from deleting features or collisions in my CSS. I do still have a small base set of styles that are shared but it's small enough to be easily manageable.
3- dynamic properties? CSS variables. Not an option? Child classes that apply the dynamic styles serve most use cases. Truly dynamic styles are rare, in my experience.
I'm still keeping an open mind about the possibilities, but my strong opinion (weakly held) is that I still don't see CSS-in-JS as more of a bandaid for people that like CSS and (for many, not all) those that don't have an in-depth understanding of it.
Each component has its own folder with its own css file and each rule starts with .name-of-the-component.
For dynamic properties, we either create conditional classes (e.g. 'success', 'error') or pass the rules through 'style' (e.g. dynamic height).
For dynamic themes, we create an object at the root of the app
Then pass it down to the related components That being said, I tried styled-components once and don't really have negatives about it. It's a viable option.1. and 2. attempt to address the lack of modularity in CSS through convention when you can have guaranteed modularity through auto-generated CSS classes that are content-addressed and thereby globally unique by definition with CSS-in-JS. Not to mention you can use a real module system for sharing styles instead of being limited to sharing variables through some global context, which again opens up the possibility of name clashes.
3. recommends a solution for dynamic styles based on yet another CSS feature that relies on global namespacing, and then a fallback based on string concatenation that can't actually address all dynamic use cases. Then it goes on to dismiss the use case entirely, when in a single page application, all styles are inherently dynamic based on the state of the components that are currently being rendered, which is why there's such a painfully obvious impedance mismatch when implementing anything that's truly dynamic using CSS classes, when you have to resort again to concatenating lists of static classes together rather than mapping state to styles directly like you could with CSS-in-JS.
Of course, I'm not saying those approaches can't work at all, nobody is saying that. You can obviously make them work, and people have used those approaches for ages before CSS-in-JS came along. But using the existence of those approaches to dismiss a different approach that tangibly addresses the inherent flaws of those approaches doesn't feel like a particularly compelling argument.
My point with the examples I gave was just to show that it's possible to handle the issues the author wrote about. I'd prefer to see efforts to fix the issues in CSS instead of discarding it completely in favor of a JS solution.
I'm not saying I can specify how to "solve" CSS issue in a couple paragraphs. As regards #3, that's specific to the kinds of dynamic styles I find most often in web apps. Very rarely do I see styles generated dynamically where it isn't effectively a choice between a couple of options (in my experience, of course). And when you do, you can just write out styles from the JS into the template (and I've definitely done fully dynamic styles in that way when it is necessary). Dynamic styles would be a place where I could see a fit for CSS-in-JS, btw.
The global namespacing this is something I believe is being worked on in the CSS Modules specification, but again, that is really easily solved. I can say loading external libraries can mess that up (i.e. Bootstrap and the ilk).
I don't care what people use, I'm glad the argument is what the author (who co-wrote the styled components lib) was what he liked. But I am really concerned that some proponents promote their way as the only way forward. Personally, I haven't found a situation yet where CSS-in-JS would materially benefit the application over a careful, convention-based approach. And I want to make sure people know there are other options that work.
Personally I much prefer using separate css (or sass) file, one for each component (assuming you also have a "layout" component for shared styles) and import each relevant css file as a module.
This way you keep writing our CSS out of your JS, but still can keep it scoped to your component. It's also obvious what css a component uses, and each to grep for when you want to delete some css.
It addresses some of these points at 35:23 - that you can kind of make CSS work if you always do everything right, but it's not as easy in practice (most of the experience stuff is at the beginning - which shows that they did kinda do everything "right").
This rarely happens. I would argue that creating an automated system to enforce "rules" should be favored over forcing every developer to know the rules and abides by them.
It is much easier to understand the relationship between css and js when the css is just a js variable.
Having built many large applications using the CSS file method, css modules, each widget gets its own file, co-locating css files with the js, I much prefer using `styled-components`. It provides a ton of flexibility, it opens doors for dynamic css by leveraging js (the hacks I've seen, had to write to get css dynamic is astounding), and I don't have to look very far to see how it's being used because the CSS is literally attached to the component I'm using. All I do in VSCode is cmd+click and bam, I can see the CSS for this component. There's no need for naming convention, there's no worry about global css variables getting into your styles, and there's no digging around looking for css that might be influencing your component. The best part for me is: when I delete the component, the CSS is gone as well. There's no thought put into scouring the FS to find lingering CSS that used to be used.
I love `styled-components` and most of the designers I work with also enjoy it.
http://getbem.com/
There are quite a few reasons for preferring to not use IDs, here's two:
1- specificity of IDs always trumping things
2- having to change it from an ID to a class later on if it becomes a reusable item (which in a widget, is almost always the case). There is no reason a class cannot apply to just a single item, where an ID is by its nature limited.
and suddenly
> I still don't see CSS-in-JS as more of a bandaid for people that like CSS
Why are SCSS or poor-man's-substitute-for-modularity in the form of naming conventions fine, and why JS-in-CSS is bad?
Deleted Comment
I have one exception to that in my own work, which is to only ever use IDs for styles that affect the layout of a block/component on a specific page. This makes sense since parts of a page layout are usually very specific and not that dynamic(in which case class names might be more appropriate). At the same time, component-level styles should never make assumptions about how they are positioned on a given page.
Let's say that we have a page `/blog/:entry_id`, and this page has a right-hand column to list related blog entries. This component would have an id `#blog-entry__entries-list`, which would control how the related-entries list appears on the blog-entry page(in this case, putting it in a column on the right), and a `.entries-list` class that controls the global appearance of the component.
This way, the entries-list can be used in different contexts without having weirdness caused by a margin working fine on one page but having to be negated on another page where the margin doesn't work. Try to add styles, but do as minimal overriding as possible.
In combination with BEM, primarily for the benefit of all selectors having the same specificity, I've found this separation of concerns between IDs and class names to be very powerful and simple to understand, especially since it doesn't require more verbosity.
Another part of my styling workflow is Sass mixins.
Let's say that we want the entries-list component to appear more compact on another page. Perhaps it appears somewhere on the site index, and takes up a little more room than we'd like.
Since component styles can't assume anything about their environment, and since layout styles(i.e. our ID selectors) can't know about the inner workings of their components, there needs to be a way for layouts to have a choice of component variations.
In this case, I would create a mixin `entries-list--compact` inside the entries-list Sass file, which would contain CSS properties that would make the entries-list smaller.
Back on in the index Sass file, I would include that mixin:
```
```But what if we only need the list to be compact at a specific page width?
```
```I've found this pattern of mixins to be very powerful. Any page can decide whether to use any mixin at any page-width. CSS for layout stays very lean, as the only properties it's concerned with 99% of the time is width, height, margin, and padding. A component can be completely replaced with new styles and behave properly on existing pages so long as it conforms to its existing "API" of mixins.
Why don't we have more : "We tried it, it is the worst, especially for products which lifespan is more than two months"
Because that last sentence is just rubbish, CSS in JS is great. I'm using it for large projects already 4 years. If your experience is bad you must be doing something wrong. CSS in JS is almost the same as working with (S)CSS, except for extra power to control dynamic elements without having to juggle with classnames.
I love PostCSS, and I'll happily consider CSS-in-JS again when somebody writes a library that doesn't try to reinvent the wheel.
For one thing, it's not CSS in Javascript... there's no cascade and no sheet, so it's just "styles in Javascript". (And, actually, this article is only about a specific implementation.)
The benefits listed are:
- "confidence" - but I think that's a matter of understanding and mastering the tool, whether it's CSS or this library. As the co-creator of "styled-components" the author is no doubt a master of it. For for the general developer, perhaps a roughly equal effort would provide a similar level of mastery in each. So why not invest in the standard?
"Painless Maintenance" - I would have to use it deeply before I could say too much about this. But I would guess that the danger of creating spaghetti code and a spaghetti of .css are pretty much the same and have the same root causes.
"Enhanced Teamwork" - I don't see the connection here. The discussion in this section seems to be about mastery of the tools again. The team can learn how to manage styles though CSS-based techniques or they can learn through techniques based on coding Javascript and the capabilities of this library.
Not that CSS doesn't have its issues. IMO, it's too low-level to use directly for many cases. There are two main problems: (1) missing the tools to manage complexity, like scoping, variables, and modules. (2) allows you a lot of freedom to do bad things. But there are libraries that address these that don't throw out the fundamental design of CSS, as styles-in-code does.
To me it seems like a better approach to build on CSS to address its weaknesses rather than throw it out.
The design of CSS itself came out the recognition that the tight coupling of style and content has drawbacks, and this is signing back up for those drawbacks. And you better neatly divide your presentation code from your business logic code and data access code or you'll get all that coupled tightly as well.
I'm not dismissing this out-of-hand -- I haven't dug into styles-in-code approach so I don't have a deep understanding of it.
But I'm not convinced it's worth the time to look more closely at it. Really, not even close.
But as you pointed out, there is no cascade and no sheet. The styles apparently just apply to the stuff they are near in the code. No twisted logic to unwind, hence no spaghetti.
The potential problem I could see is that changes which would have been easy with a cascade would require lots of changes to copypasta in this approach. Like, "take the spinach out of this ravioli and replace it with mushrooms." Everything is scoped properly and the task is obvious at a glance-- it's just annoying.
Ah, well, things are not that simple.
In a project of any complexity at all, the style of any individual element is typically dependent on a number of things which collectively make up the context of its presentation. E.g, the site theme, the component, and the individual element (at least -- usually there's an app-subsection and components are usually grouped into modules, etc.).
Note that this is inherent to the problem space and is true whether you're specifying styles in code or styles in cascading style sheets or any other way.
CSS provides a basic mechanism for dealing with this -- the cascade (though as I mentioned, IMO it is lacking some necessary features). Styles in code needs an answer as well.
If you were to simply hard-code styles at the element-level (which you can do using either mechanism BTW though its probably easier with style-in-code), you'll have a hard time finding all the places in the code you need to update if you want to make a change. You'll be doing a lot of full code searches, reading code, and trying to put yourself into the mind of the person who wrote the code in the first place.
The "spaghetti" in the metaphor are the lines of dependencies. We have spaghetti code when those lines are disorganized, entangled with irrelevancies, obscured, and otherwise unnecessarily difficult to deal with.
In fact, if you hard-code a style on an element that is dependent on the site theme, app section, component module, and component, you'd be hiding those dependencies, which creates spaghetti code rather than avoids it.
Now, I expect most developers would naturally try to avoid doing something like that. I'm just trying to point out why style-in-code doesn't really help you avoid spaghetti code.
Why does copying CSS multiple times (once for each component) not also create spaghetti code?
Many elements share style in a normal webpage. Font, for example. Having to specify the font in every file seems crazily redundant.
And if you separate that out into a separate file that gets included in many places, you lose all the other benefits like "painless maintenance".
Look at this beauty for comparison: https://vuejs.org/v2/guide/single-file-components.html
https://vue-loader.vuejs.org/guide/scoped-css.html#scoped-cs...
Inspect the result here: https://codesandbox.io/s/3v0pjzoy7q
Where is template getting assigned to the code inside the script tag?
Does OtherComponent somehow mysteriously map to other-component? How does one pass arguments to it? Is a .vue file actually HTML or is it parsed somehow to be HTML?
The thing I like about React is the explicitness of it. This is a source code file that exports component X. Component X uses style Y as defined above because it's explicitly passed in as a prop, etc etc.
What language are you talking about? React is Javascript
> Look at this beauty for comparison
Meanwhile Vue is neither HTML [1], nor strictly speaking CSS [1], and has a very wierd concept of how objects work in JS.
[1] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.
Vue Templates are a very thin DSL on top of HTML. It's just markup.
Once you understand that, everything falls into place.
What is so weird about it? I personally find Vue vastly more approachable than React is, especially once you have to start writing all the plumbing to get all the libraries you need to go along with it to write a real world app.
> ] It's a templating system with its own rules and mini-DSLs that ends up being compiled into JS.
Vue has the option to use Webpack to compile html compliant templates to JS functions just like JSX (which BTW is not JavaScript and not HTML compliant and is also a separate concept that needs to be learned as well.)
CSS is just another add-on through Webpack when using Single File Components. Nothing really ground breaking here except for the fact that it creates a nice separation of concerns. This is especially true on teams with junior devs or designers. Or with a team that works on a site with mixed MPA and SPA features.
Add in Tailwind utility classes and you've got a great design system that can be built on the fly with consistent standards.
If you want to use CSS-in-JS, you'll either have to use server-side rendering to inject CSP nonces in your index.htm [0], or set up a complex build system to extract the CSS from your JS so you can serve them as .css files.
Using server-side rendering to inject nonces into your single-page client side rendered webpage is such an ugly hack. I'd prefer the second solution but I have not been able to find a solution like that, nor do I have the time to dive into the webpack rabbit-hole to do so.
[0] https://github.com/cssinjs/jss/blob/master/docs/csp.md
If style becomes out of fashion, you have to modify files that contain logic. If framework (react/vue) becomes out of fashion, keeping styles will be difficult.
The other down-side is thousands of web developers having to re-learn CSS and the tooling behind your app instead of just changing CSS files.
I think there’s truth to your second point though - reusing styles in parts of a project that does not use the same framework. Something like Tailwind CSS can be a good option then.
Full design yes, but branding/theming is much easier if you use an external styling framework like Bootstrap 4 or Foundation and use their component and utility classnames.
We have a 300+ page app and tried the one stylesheet per component thing with theme and layout all combined in the past, and was a huge mistake.
Banning most custom CSS in place of using the Bootstrap component and util classes has been so much easier.
I guess the concern for longevity most devs have is amusing when most software, if its not like systems level stuff, or problems most devs dont want to solve, tends to get disposed pretty frequently.
By the way, most of the software that actually sticks around was written in C and generally solves a problem most people wont tackle. Like zlib or sqlite or nginx or the linux kernel. You can almost pretty much judge the longevity of a piece of software based on how hard the problem it tackles is. Like encryption or compression? Those libraries are going to be around forever, because how many coders do you know that can write a semi compitent encryption library? And how manu coders can write a templating engine?
Like most of web dev is throwaway code. It just is. Arguments based on like "will they be able to restyle it in 10 years?" Well are they even going to be around?
both of these are pretty bad examples, as several modern developments have surfaced in both cases - here are 2 examples
- https://wikipedia.org/wiki/Curve25519 - https://github.com/google/brotli
Better to have a cohesive set of theme/rules and get them to work together as best possible. I've been a big fan of material-ui and react-jss and is imho about the best option I've used in over two decades of working on web based applications.
So just put the styles in separate .js files and import them.
People not taking the time to learn is not a reason to throw an entire building block of the web out.
(Yes, I realize there are a lot of people who know CSS and still choose CSS-in-JS, but I'm specifically referencing the point re: not learning CSS.)
My theory is that CSS was something that was treated as a task. Make a lot of client/server side development and then make these freaking lines align perfectly. So, most of time engineers were avoiding styles, applying them was the most tedious and hated part of the job.
And it is hard to be good at something you hate.