PicoCSS vs Bootstrap vs Tailwind: choosing your CSS framework

Table of contents (6 sections)

The project: TOUSPOURRIS.COM, a satirical site tracking French political corruption. The UI had to mimic the aesthetic of French Republic institutions (RF from here on), bleu france #000091, red #e1000f, Marianne typography. An immediately recognizable design, deliberately official for the ironic effect. This isn't a modern SaaS with rounded cards and gradients. It's an institutional pastiche.

And that aesthetic choice dictated the CSS framework choice. When the design is precise and identity-driven, the framework is no longer a neutral accelerator. It can become an obstacle. I evaluated the three usual suspects: Bootstrap, Tailwind, PicoCSS. Here's why two were ruled out and the third won.

The problem with Bootstrap

Bootstrap imposes its components. Buttons with border-radius: 0.375rem, colors in variables but an entire color system to override, navbar with preconfigured behaviors. For a generic design (admin dashboard, SaaS landing page), it's perfect: the defaults are the right ones.

For a French Republic institutional design, it's the opposite. You spend your time undoing what Bootstrap did. !important everywhere, CSS variables rewritten. You end up with Bootstrap-0: Bootstrap stripped of its defaults, shipping about 31 kB of CSS over the wire (232 kB uncompressed), most of it unused. Pico weighs about 12 kB over the wire. The cost/benefit ratio flips: Bootstrap becomes a liability, not an asset.

The problem with Tailwind

Tailwind fixes the imposed-components problem by shipping none. But it shifts the problem: for a consistent design, you need to declare the design system (RF colors, Marianne typography), then apply utility classes everywhere in the HTML. Since Tailwind 4 (January 2025), that declaration lives in your CSS, in an @theme block, not in tailwind.config.js any more. That's work.

And for this Symfony project with Twig templates, it meant learning an additional tool, a Node.js build step in a PHP stack, for a result that native CSS can deliver directly. The effort/benefit ratio didn't justify introducing Tailwind into a context where the design system was already defined and documented by the French government.

Why PicoCSS

PicoCSS starts from a different philosophy: clean styles on semantic HTML elements, without classes. A <button> is styled. An <input> is styled. A <nav> is styled. The base is usable immediately without writing a single line of CSS. And most importantly: the defaults are minimal and easy to override with CSS custom properties.

/* Override the PicoCSS design system with RF colors */
/* In the HTML: <html lang="en" data-theme="light"> */
:root {
    --pico-font-family: 'Marianne', system-ui, sans-serif;
    --pico-border-radius: 0;          /* Institutional = no rounding */
}

:root[data-theme="light"] {
    --pico-primary: #000091;          /* Bleu France */
    --pico-primary-background: #000091;
    --pico-primary-hover: #1212ff;
    --pico-primary-hover-background: #1212ff;
    --pico-del-color: #e1000f;        /* RF Red */
}

A handful of CSS variables and the site looks like a government portal. Two details matter: links read --pico-primary but buttons read --pico-primary-background, and Pico declares its colors with :root:not([data-theme=dark]), a stronger selector than a plain :root. Hence :root[data-theme="light"]. Still no !important. PicoCSS doesn't resist, it yields cleanly because it was designed to do exactly that.

The RF design system in practice

The code of the French government's design system, the DSFR, is public. Its use is not: the official repository says the DSFR must not be used by entities outside the public administration (it cannot be used outside a .gouv.fr domain), and that the Marianne fonts come with specific conditions. For a pastiche, read those terms before copying anything. Colors, typography, spacing, all defined and documented. With PicoCSS as the base:

  • Marianne font (provided by the DSFR, under usage conditions) loaded via @font-face
  • CSS variables for --bleu-france, --rouge-marianne, --gris-cool
  • Custom components ("corruption gauge" badge, politician cards) written in native CSS, no utility classes

The result: a site that deliberately looks like an official portal. The satirical effect relies entirely on the design. A visitor who arrives without context sees an institutional interface before realizing it's satire. That disconnect only works if the design is credible, and it wouldn't have been with off-the-shelf Bootstrap or hastily configured Tailwind.

When to choose what

There's no universal framework. Concrete criteria for deciding:

Situation Recommended framework
Admin dashboard, generic SaaS Bootstrap or shadcn/ui
Lots of utilities, custom design via config Tailwind
Precise design, semantic HTML, solid native CSS skills PicoCSS
Project < 10 pages, CSS < 500 lines No framework

The real question isn't "which framework is best" but "what am I going to fight against". Bootstrap imposes its components. Tailwind imposes its classes. PicoCSS imposes almost nothing, which can be an advantage or a disadvantage depending on whether you want to build or to override.

Key takeaway

PicoCSS isn't the universal answer. It's the answer when you have a precise design and you don't want to spend your time undoing a framework's decisions. For TOUSPOURRIS.COM, it was the right choice: a coherent institutional design in ~300 lines of custom CSS, without any specificity war.

The code is readable by any developer without knowing the conventions of a specific framework. In 2 years, if someone picks up the project, they read CSS, not Bootstrap or Tailwind. It's a form of technical restraint that has a short-term cost (no ready-made components) and a long-term benefit (a single CSS dependency, no build).

Comments (0)