At some point, we stopped writing CSS… and started outsourcing it.
There was a time when installing an NPM package felt like progress. Need a grid? Package. Need spacing? Package. Need a button? Somehow… also a package.
Fast forward to 2026, and I’ve started doing something that feels almost rebellious:
I’m removing dependencies. On purpose
The Old Me
A year ago, my workflow looked like this:
- Spin up a React app
- Install a UI library
- Add a utility framework (yes, even with the UI library)
- Pull in helpers for layout, animation, theming, responsiveness
- Spend half a day figuring out how to override styles
I wasn’t writing CSS anymore. I was orchestrating abstractions.
I convinced myself it was efficient. After all, everyone was doing it. The ecosystem normalized it
“Don’t reinvent the wheel.”
But here’s the uncomfortable truth:
We weren’t avoiding reinventing the wheel
we were shipping entire factories
Between tailwind css react native discussions, design systems, and endless plugin chains, my apps became dependency-heavy beasts. Every feature came with a cost I didn’t fully understand.
The Breaking Point
It wasn’t ideology that changed me it was pain.
1. Bundle Size Got Out of Hand
I started paying attention to javascript bundle size optimization. What I found was… embarrassing.
- UI libraries pulling in unnecessary styles
- Utility frameworks generating massive CSS outputs
- Helper packages doing trivial things
All this just to render a few divs and buttons.
I wasn’t building a high performance web server, but my frontend sure felt like it needed one to keep up.
2. Updating Became a Ritual
Every few weeks:
- update package with npm
- Google “how to update npm package”
- Check changelogs
- Fix breaking changes
- Run npm get version of package to debug inconsistencies
It wasn’t development anymore. It was maintenance.
3. Overengineering Became Default
We normalized complexity.
Need responsive design? Use a framework.
Need state-based styling? Use JS.
Need conditional layouts? Write logic.
At some point, we started trying to replace CSS with JavaScript and calling it progress.
The Shift
The turning point came when I revisited CSS… out of frustration, not curiosity.
I had a simple requirement. Normally, I’d reach for a package. This time, I paused.
“What if CSS can already do this?”
Spoiler: it could.
That’s when I started exploring modern css features not as a fallback, but as a first choice.
And suddenly, the question changed from:
“Which package should I install?”
to:
“Do I even need one?”
Native CSS Superpowers in 2026
Let’s be clear this isn’t nostalgia. This is about native CSS 2026 being legitimately powerful.
Container Queries (Finally Real Responsive Design)
.card {
container-type: inline-size;
}
.card-content {
font-size: 1rem;
}
@container (min-width: 400px) {
.card-content {
font-size: 1.25rem;
}
}No JS. No hacks. Just container queries css doing exactly what we wanted for years.
Native Nesting (Yes, Really)
.card {
padding: 1rem;
& .title {
font-weight: bold;
}
&:hover {
background: #f5f5f5;}
}
}With native css nesting support, the argument for preprocessors weakens significantly.
The :has() Selector (Game Changer)
.form:has(input:invalid) {
border: 1px solid red;
}We used to write JavaScript for this. Now? Pure CSS.
This is where CSS vs JavaScript 2026 gets interesting CSS is reclaiming territory we gave away too easily.
Cascade Layers (Control Without Chaos)
@layer base, components, utilities;
@layer components {
.btn {
padding: 0.5rem 1rem;
}
}Finally, a structured way to manage specificity without fighting it.
Trade-offs (Let’s Not Pretend It’s Perfect)
This isn’t a fairy tale.
- Browser support can still lag in edge cases
- Debugging complex CSS can be… character-building
- Team familiarity matters not everyone is ready to drop frameworks
- Some patterns are still easier with abstractions
And yes, sometimes you will miss the convenience of prebuilt systems.
But the trade-off is clarity.
You write less. You understand more.
When NPM Still Makes Sense
Let’s not swing to the other extreme.
There are still valid NPM package alternatives scenarios:
- Complex component libraries (e.g., accessibility-heavy UI)
- Data visualization
- State management
- Truly reusable, domain-specific logic
But styling?
That’s increasingly becoming a native concern again.
Not every problem needs a dependency. Some just need better CSS.
The Bigger Picture
This shift isn’t just about styling. It’s about mindset.
- npm reduce dependencies → fewer moving parts
- remove npm package → less maintenance overhead
- reduce bundle size → faster apps
- Better alignment with web performance optimization principles
And in a world where web performance news constantly reminds us that users bounce in milliseconds, this matters more than ever.
Conclusion: Unlearning as a Skill
The hardest part wasn’t learning modern CSS.
It was unlearning the instinct to reach for a package.
We built habits around convenience, but ignored long-term cost. Now, the platform has caught up and in many ways, surpassed our abstractions.
The best optimization I made this year wasn’t adding a tool it was removing one.
Native CSS isn’t just viable in 2026.
It’s powerful, expressive, and finally enough.
And maybe the real growth as a developer isn’t in how much you can add…
…but in how much you’re willing to take away.