There was a time when CSS preprocessors seemed like a magical elixir for any CSS problems. It was only necessary to learn a new syntax, set up the environment and add several dependencies to your project. But as time passed, web technologies developed, and preprocessors seemed to remain in their own isolated world. So right now I don't see any reason to use these tools in development.
Let's take a look at what preprocessors offer us, and how valuable their features are at the moment.
Variables, Nesting, Operations and Scope
Modern CSS has matured significantly compared to its original version. Now you can create variables using @property, limit the scope of selectors using @scope, describe complex operations with calc and use nested CSS rules. Therefore, such features are no longer advantages.
Mixins, Maps and Functions
Сomplex data structures such as Mixins, Maps and Functions seem to be a real advantage of preprocessors. But don't you think that there is already a programming language in web development that has been able to do all this for a long time?
The very concept of CSS-in-JS has an important message - not to invent a new programming language, but to use JavaScript. And browsers have supported this concept with a class of CSS constructed StyleSheets. Constructed stylesheet can be added to the HTML Document and to the HTML Element ShadowRoot. This makes it easier to reuse styles and dynamically change them. Besides this has radically changed the balance of power.
Take a look at the following mixin example from the Sass documentation:
@mixin theme($theme: DarkGray) {
background: $theme;
box-shadow: 0 0 1px rgba($theme, .25);
color: #fff;
}
.info {
@include theme;
}
.alert {
@include theme($theme: DarkRed);
}
.success {
@include theme($theme: DarkGreen);
}
You can replace it using JS:
const DarkGray = '169, 169, 169';
const DarkRed = '139, 0, 0';
const DarkGreen = '0, 100, 0';
function theme(value = DarkGray) {
return `background: ${value};` +
`box-shadow: 0 0 1px rgba(${value}, 0.25);` +
'color: #fff;';
}
const sheet = new CSSStyleSheet();
sheet.replaceSync(
`.info{${theme()}}` +
`.alert{${theme(DarkRed)}}` +
`.success{${theme(DarkGreen)}}`
);
Next, let's take a look at the example of maps usage from the Less documentation:
#colors() {
primary: blue;
secondary: green;
}
.button {
color: #colors[primary];
border: 1px solid #colors[secondary];
}
You can simplify it using JS:
const COLORS = {
primary: 'blue',
secondary: 'green'
};
const sheet = new CSSStyleSheet();
sheet.replaceSync(
`.button {` +
`color: ${COLORS.primary};` +
`border: 1px solid ${COLORS.secondary};` +
`}`
);
Finally, let's take a look at an example of functions from the Stylus documentation:
add(a, b)
a + b
sub(a, b)
a - b
invoke(a, b, fn)
fn(a, b)
body
padding invoke(5, 10, add)
padding invoke(5, 10, sub)
Well it's too simple for JS:
const add = (a, b) => a + b;
const sub = (a, b) => a - b;
const invoke = (a, b, fn) => fn(a, b);
const sheet = new CSSStyleSheet();
sheet.replaceSync(
`body {` +
`padding: ${invoke(5, 10, add)};` +
`padding: ${invoke(5, 10, sub)};` +
`}`
);
It looks like all the features of CSS preprocessors can be implemented using pure JS. Without dependencies. Without binding to the framework. So what price do you have to pay for using preprocessors?
At what cost?
Let's walk the path of working with a CSS preprocessor.
Our first step is to install a preprocessor, so I suggest taking a look at the Package Phobia report for Sass, Less, and Stylus:
Well, these are not particularly lightweight libraries. But what can you not do for the sake of new experiences.
Our second step is to master the syntax of the library. This definitely entails spending time and mental effort. Let's say we're smart enough to do it in less than a week.
Our third step is to set up the build tools. It is quite easy (Praise be to Vite!). But then there is an awareness of the problem.
We just moved away from CSS to come back. It was an exciting adventure but we got the usual static CSS at the output. Is the cost fair?
I'm sure someone will say, look, you've saved so much time than if you were writing in pure CSS. But I spent a lot more effort than I would have written in pure JS.
In addition, the new syntax always imposes its own limitations. And the most important limitation is the scope of application. CSS preprocessors solve only one problem, which is now easy to solve without them.
Final thoughts
In my opinion, using a CSS preprocessor is like flying in a hot air balloon. The destination will be reached, but with less comfort than by plane.
I think that the constructed stylesheets have completely changed the balance, now everything that is not implemented in CSS can be done directly using JS. And now it makes sense to create any CSS-in-JS solution only on top of constructed stylesheets. When I started using them, I lacked TypeScript support, server-side rendering, and selectors minification, which is why the idea of EffCSS was born.
It is useful to know about CSS preprocessors. It will be great to add them to your resume. But, it's hardly worth using them.
Enjoy your Frontend Development!



Top comments (6)
Solid points here. I dropped Sass from a project last year and honestly haven't missed it much. Native nesting + custom properties cover like 90% of what I was actually using it for.
The CSSStyleSheet approach is interesting though - I hadn't considered using it as a direct replacement for mixins. One thing I'd push back on slightly: the JS examples work fine for simple cases, but once you're dealing with media queries or pseudo-selectors inside those template literals, it gets messy fast. That's where I still reach for something like CSS Modules or even just well-organized vanilla CSS.
Curious if you've run into performance differences between constructed stylesheets vs regular style tags in larger apps?
Thanks for the comment! Yes, I agree with you that template literals are not the best way to describe styles, but probably the simplest. As for me, I prefer a more explicit functional approach, for example, where you get the
@propertyrule using theproperty()function.I can't say for sure about performance, I haven't made such measurements and usually use constructed stylesheets for dynamic styles, for example, to customize colors and sizes. Therefore, the total count does not exceed several dozen.
And I usually don't use style tags, only when using SSR to avoid unnecessary JS for the first rendering. Since both constructed stylesheets and style tags are tied to the browser API, different browsers can show their own measurement results.
I agree with most of this, especially the point that modern CSS has absorbed a lot of what made preprocessors attractive in the first place. Variables, nesting, calc(), and even things like @property mean we’re no longer stuck in 2012 pretending CSS can’t evolve.
That said, I don’t think the takeaway is “preprocessors are useless” so much as “they’re no longer the default solution.” Constructed stylesheets and CSS-in-JS shift logic into an actual programming language instead of inventing a new one, which is a big conceptual improvement. But there are still real tradeoffs: constructed stylesheets aren’t universally supported yet, runtime-generated CSS ties styling to JS availability, and preprocessors still make sense in static build pipelines or legacy projects.
What’s more interesting to me is the direction this points to. It feels less like CSS vs preprocessors and more like a transition toward host-language–driven styling. Imagine CSS as the declarative surface, while a typed language (Java, for example) defines structure, constraints, and theming logic that CSS simply renders. Instead of CSS trying to be a programming language and preprocessors trying to patch that, we let a real language handle computation and CSS handle presentation.
If that path continues, preprocessors don’t really “die” — they turn into compilers for higher-level style systems. The center of gravity just moves from macro syntax to structured, traceable style generation.
So yeah, preprocessors aren’t obsolete, but they’re no longer the center of the ecosystem. The real shift is CSS becoming better at what it does, and logic moving to places that were always better suited to express it.
Thanks for the comment! I like your way of thinking. And yes, the compilation path looks very promising. So we'll wait and see.
No. Just disable javascript. Your app should work fine. Use AI to correct your lack of css skills
You never did need preprocessors. You thought you did, but you didn't. And now vanilla CSS covers all those cases natively.