Modern CSS: No framework needed

October 07, 2025

For years, CSS frameworks like Bootstrap and preprocessors like SASS dominated web development. They solved real problems—CSS was missing essential features like variables, grid systems, and proper modularity. But CSS has evolved dramatically. Today’s native CSS is powerful enough that most projects don’t need these tools anymore. For this website, I decided to go without a framework or preprocessor and just write raw CSS from scratch. In this post, I reason why I chose so and how it worked out.

The role frameworks played

CSS frameworks provided crucial capabilities that CSS lacked back in the days:

These frameworks pushed CSS forward. Browser vendors took notice and added native features to address these needs. The frameworks succeeded—so much so that they made themselves less necessary.

What this site uses

For generating this website, I used zero CSS frameworks or preprocessors. Just plain CSS files that leverage modern, native features:

Let me show you some examples from the actual code.

Modern CSS features in action

CSS Grid replaces grid frameworks

Remember the 12-column grid systems? Here’s how this site lays out its structure:

body {
    display: grid;
    grid-template-columns: 1fr var(--gutter-width) var(--main-width) 1fr;
    grid-template-rows: auto 1fr auto;
}

Three lines. No framework classes like col-md-8 offset-md-2. The grid is explicit, readable, and flexible.

CSS Variables replace preprocessors

Before CSS variables, you needed SASS to define reusable values:

// SASS
$primary-color: #268bd2;
$spacing-md: 1rem;

Now CSS does this natively, with the added benefit that variables can be changed at runtime (for dark mode, user preferences, etc.):

:root {
    --sol-blue: #268bd2;
    --space-md: 1rem;
    --link-color: var(--sol-blue);
}

This site uses CSS variables for its entire Solarized color theme, allowing seamless light/dark mode switching without JavaScript manipulation of styles.

Modern layout tools

Remember fighting with floats and clearfixes? CSS Grid and Flexbox make complex layouts trivial:

.top-nav ul {
    display: flex;
    gap: var(--space-lg);
}

The gap property alone eliminates countless margin hacks. The shape-outside property lets text flow around rotated images naturally—something that previously required complex JavaScript calculations.

No build step required

One of the biggest advantages: no compilation. Edit a CSS file, refresh the browser, see the changes. No webpack configuration, no build errors, no waiting for SASS to compile. Development is instant. A workflow that I use now oftentimes, is editing the CSS in my browser’s development tools. This gives me immediate feedback and validation. When I’m satisfied with an edit, I just copy and paste the CSS from the browser development tools into my code repository.

YMMV

As always, “your mileage may vary.” For my modest personal website, using raw CSS has simplified my workflow, and I don’t perceive any downsides. I can imagine this is different when you’re building a huge corporate website, a web shop, or any web-based application.

The benefits of framework-free CSS

Downsides

No downsides, really? Well, as I said, I didn’t perceive any while working on this website so far. But if I’m really critical, there’s actually one example in this website’s CSS that I don’t like. For setting some colors differently in light and dark mode, there was no way I could prevent repeating the definition of color for the dark scheme:

/* Light mode - default and explicit override */
:root,
.light-mode {
    --bg-color: var(--sol-base3);
    --bg-color-alt: var(--sol-base2);
    --text-color: var(--sol-base00);
    /* left out the rest of the definitions for brevity. */
}

/* Dark mode - auto based on system preference */
@media (prefers-color-scheme: dark) {
    not(.light-mode) {
        --bg-color: var(--sol-base03);
        --bg-color-alt: var(--sol-base02);
        --text-color: var(--sol-base0);
    }
}

/* Manual dark mode - overrides auto mode and light mode.
 * We need to repeat the definitions here, CSS doesn't have a way to prevent this repetition. */
.dark-mode {
    --bg-color: var(--sol-base03);
    --bg-color-alt: var(--sol-base02);
    --text-color: var(--sol-base0);
}

A preprocessor-based solution might have been able to prevent this repetition. But to be honest, I’m willing to pay this price for the decreased complexity of the entire code base and build process.

Conclusion

CSS frameworks and preprocessors played a crucial role in web development history. They identified pain points and inspired native CSS features. But CSS has grown up. Modern CSS has native variables, grid, flexbox, nesting, and powerful selectors. For many projects, that’s all you need.

The best tool is the one that solves your problem without adding unnecessary complexity. For this website, that tool is plain CSS. And it’s been a joy to work with.

Try it on your next project. You might be surprised how little you miss the framework.