Bulma vs. Sass: Not a Choice, and the 40 KB Hiding in It
Bulma is written in Sass, so the real decision is precompiled or compiled. Measured: 65.2 KB down to 25.3 KB — with an 18.2 KB floor the theme layer makes mandatory.
Bulma and Sass are not alternatives. Bulma is a CSS framework written in Sass — 73 .scss files ship inside the package. So the real choice behind this comparison is not which to use, it is whether to link Bulma's precompiled CSS or compile it from its Sass source. Measured here, that decision is worth 40 KB gzipped.
The short answer
Sass is a preprocessor: variables, nesting, mixins, partials, compiled to CSS before a browser sees it. Bulma is a component library of ready-made classes — button, card, navbar — authored in Sass and distributed both ways. You do not pick one. You pick how you consume the other.
| Sass | Bulma | |
|---|---|---|
| What it is | A language that compiles to CSS | A CSS framework of component classes |
| Gives you | Authoring tools | Finished styles |
| Written in | — | Sass |
| Usable without the other | Yes, for any CSS | Yes, via precompiled bulma.min.css |
| Build step | Required | Optional |
| What it decides | How you write CSS | What your components look like |
The question worth asking: do I take the whole framework, or compile the parts I use?
| Consumption route | Raw | Gzipped |
|---|---|---|
bulma.min.css, precompiled | 677,931 | 65,219 |
| Full framework compiled from Sass | 690,613 | 65,479 |
| Sass subset — base + themes + button + form | 245,520 | 25,349 |
Same framework, same version, 61% less CSS. That is what Sass is actually for here.
The measurement, and the floor nobody mentions
Bulma 1.0.4, sass 1.105.1, compiled with --style=compressed. Each row adds one @use to the previous:
@use "bulma/sass/base";
@use "bulma/sass/themes";
@use "bulma/sass/elements/button";
$ npx sass --no-source-map --style=compressed --load-path=node_modules subset.scss subset.out.css
| Subset | Raw | Gzipped |
|---|---|---|
base only | 4,172 | 1,348 |
themes only | 184,961 | 16,803 |
base + themes | 189,132 | 18,201 |
base + themes + button | 212,203 | 21,337 |
base + themes + button + form | 245,520 | 25,349 |
Read the second row twice. The themes layer alone is 16.8 KB gzipped — 92% of the two-row floor, before a single component. Bulma's base reset is 1.3 KB; its first real component costs 3.1 KB. Everything else in a minimal Bulma build is the theme layer.
That layer is where Bulma 1.x declares the CSS custom properties its components resolve against, and it is not genuinely optional. Drop it and the compile still succeeds:
| Subset | Raw | Gzipped |
|---|---|---|
base + button, no themes | 27,243 | 4,224 |
4.2 KB is tempting and wrong. The geometry variables survive — --bulma-control-radius and --bulma-button-h are declared by base and the button file themselves — but every colour resolves through a chain that bottoms out here:
--bulma-button-disabled-background-color: var(--bulma-scheme-main);
--bulma-button-background-l: var(--bulma-scheme-main-l);
--bulma-scheme-main is referenced five times in that build and declared zero times. Only themes declares it:
--bulma-scheme-main: hsl(var(--bulma-scheme-h), var(--bulma-scheme-s), var(--bulma-scheme-main-l));
So the practical floor for a Sass-built Bulma is 18.2 KB gzipped, and a build that skips themes produces correctly sized, colourless components — a worse failure to debug than no styles at all, because the layout looks right.
Sass's own cost, measured in warnings
Bulma 1.0.4 against current Sass is noisy:
DEPRECATION WARNING [if-function]: The Sass if() syntax is deprecated in favor of the modern CSS syntax.
Repeated through every compile, with WARNING: 3 repetitive deprecation warnings omitted. closing the run. The deprecation is in Bulma's source, not in anything you wrote, so there is no fix available to you — only a choice between pinning Sass, filtering the output, or accepting it. This is the structural cost of the Sass route that the byte count hides: you have adopted the maintenance timeline of two projects instead of one, and Sass's deprecations land on Bulma's schedule for fixing them.
What the Sass route actually buys
Three things, in order of how much they matter:
Subsetting. The 40 KB above. The only way to get it.
Variable overrides before compile. Bulma's defaults are Sass variables, so a brand colour can be substituted at build time rather than overridden at runtime:
@use "bulma/sass" with ($primary: #465fff);
With the precompiled file you would redeclare the custom properties afterwards, which works in 1.x but means shipping both the default and your override.
One thing to expect from that override: the hex does not appear in the output. Bulma 1.x decomposes it into HSL components, so the compiled CSS carries --bulma-primary-h: 232deg and its saturation and lightness siblings rather than #465fff. Grepping the build for your brand hex finds nothing and proves nothing — check the hue instead.
One stylesheet. The Sass compiler concatenates; the precompiled route plus overrides means two files or a duplicated layer.
What it does not buy is anything about how your own CSS is written. That is the comparison Sass vs. Tailwind covers — and the reason this repository has none of it.
Why this codebase has zero .scss files
$ find src -name '*.scss' | wc -l
0
src/app/globals.css is 133 lines of plain CSS with a Tailwind v4 @theme block, and its 41 declarations are the entire design-token layer for 92 components:
/* src/app/globals.css */
@theme {
--color-primary: #465fff;
--color-primary-600: #3641f5;
--color-gray-900: #101828;
/* …41 declarations total */
}
Each of those emits a real CSS custom property and the utility that reads it. That is the overlap with Sass worth naming: @theme does the job $primary: #465fff does in a Bulma build, without a preprocessor, because Tailwind's PostCSS step was already in the pipeline. The file uses @apply exactly twice — both in the body rule — which is the whole of its mixin-shaped code.
The result, measured on the production build of this exact checkout today — Sass vs. Tailwind cites 13.3 KB from a September build of the same stylesheet, and the gap is posts and components added since, not a regression:
$ npm run build
✓ Generating static pages using 3 workers (762/762) in 10.7s
$ find .next/static -name '*.css' | xargs gzip -9c | wc -c
14803
14.5 KB gzipped for the entire storefront — home, pricing, docs, blog, 111 product pages, 762 prerendered routes. Bulma's floor with Sass is 18.2 KB before its first component, and its precompiled file is 65.2 KB. That is not a criticism of Bulma; it is what a framework of ready-made components costs versus a stylesheet generated from the classes 92 hand-written components actually reference. Bulma vs. daisyUI measures the same card three ways if you want the component-level version of this comparison.
Choosing between the two routes
| If | Use |
|---|---|
| No build step is available (CDN, CMS theme, plain HTML) | Precompiled bulma.min.css |
| You use more than roughly half the framework | Precompiled — subsetting saves little and costs a toolchain |
| You use a handful of components | Sass subset, and expect an 18.2 KB floor |
| Brand colours differ from Bulma's defaults | Sass, with @use ... with (...) |
| A bundler is already compiling your CSS | Sass — the marginal cost is one loader |
| You already run Tailwind | Neither; @theme tokens cover the variable layer |
Mistakes and troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| A Sass subset renders correctly sized but colourless components | bulma/sass/themes omitted, so --bulma-scheme-main is never declared | Keep themes — it is the floor, not an option |
| Sass subsetting saved almost nothing | The themes layer is 16.8 KB of any build; subsetting only trims components | Measure before committing to the toolchain |
Can't find stylesheet to import on @use "bulma/sass" | node_modules is not on the load path | Pass --load-path=node_modules, or use the bundler's Sass resolver |
DEPRECATION WARNING [if-function] on every build | Bulma 1.0.4's own source against sass 1.105.1 | Not fixable from your code; pin Sass or filter the output |
Overriding $primary has no effect | Variables must be passed at import time, not assigned after | @use "bulma/sass" with ($primary: …) — assignment after an import is too late |
| Both the precompiled file and your overrides are shipping | The precompiled route cannot be configured before compile | Pick one route; do not link bulma.min.css and then re-theme it |
Frequently asked questions
Is Bulma better than Sass? The question does not resolve — Bulma is written in Sass. A framework of finished component classes and a language for authoring CSS answer different questions, and using Bulma at all means Sass compiled it, whether on your machine or the maintainers'.
Can I use Bulma without Sass?
Yes. bulma.min.css is 65.2 KB gzipped and needs no build step at all — that is the main reason to choose it. You give up subsetting and compile-time variable overrides.
How much does the Sass route actually save? Measured on Bulma 1.0.4: 65.2 KB gzipped down to 25.3 KB for base, themes, button and form. A 61% cut, with a hard floor of 18.2 KB from the mandatory theme layer.
Do I need Sass if I use Tailwind?
No, and the two overlap enough that running both is usually a migration artefact. Tailwind v4's @theme block gives the variable layer, and its PostCSS step is already required — this repo has 41 @theme declarations and zero .scss files.
Why is the themes file so large? It declares the full custom-property set every component resolves colours against, for both light and dark schemes, rather than inlining literal colours per component. That is what makes Bulma 1.x re-themeable at runtime, and it is charged to every build regardless of how few components you import.
Templates in this post
ASoc Ignite is an AI-app marketing site with a capability showcase, a mobile-app section and a projects portfolio — the multi-section page where a framework's full component inventory is the tempting shortcut. ASoc Iris is a computer-vision studio site with vision capabilities, case studies and pricing, built from composed sections rather than framework classes. ASoc Keystone is a mortgage-lender site with loan products, an eligibility checker and a quote funnel, whose form-heavy pages are exactly where Bulma's form module would be imported first.
Browse the full sets: Next.js landing page templates, Tailwind landing page templates.
