Skip to content
HomePagesHomePages template kit

size-section-css

"A section's compiled CSS exceeds its byte budget."

Venue: check — A section’s compiled CSS exceeds its byte budget.

A section’s compiled cascade layer must gzip to 50 KB or less. What is measured is everything that lands in the layer:

  • the section’s hand-written CSS, and
  • every package stylesheet its module graph imports — the import "swiper/css" in a component or an island.

The budget is visible in template-kit check’s configuration and is not author-overridable. A workspace cannot raise it, and there is no per-section exemption.

The output is a real page for a real buyer, standing in a driveway on a phone — and a stylesheet is the worst thing to be heavy, because CSS blocks the first paint. Nothing can schedule it out of the way: the browser paints when the layer arrives and not before. That is why this budget is one hard number, where the renderer and island bundles get a guideline and a far higher ceiling.

“Including package CSS” is not a technicality; it is the failure this rule exists to catch. Your own stylesheet is almost never the problem — it is a few kilobytes of overrides. The package’s is. A one-line import "some-ui/dist.css" can drag in thousands of rules for components you never render — resets, theme variants, every widget’s styles — and they all land in your compiled layer. Nothing in your source looks large; the compiled layer is 400 KB.

So the number this check reports is frequently the first time anyone finds out what a one-line CSS import actually cost. (What this budget does not count is asset bytes: a url()-referenced webfont or icon file resolves to a cached URL and is weighed separately — see size-assets.)

Three moves, in order of how often they work:

  1. Import the slimmest entry the package offers. Most CSS-shipping packages have a core stylesheet plus opt-in modules, and a fat “everything” bundle that is the one you get from copying its starter snippet. Take the core, plus only the modules you use.
  2. Drop the icon font. If the package’s stylesheet declares an icon font and you use three of its glyphs, replace them with inline SVG — or with a family the template’s theme already declares in fonts (--tr-font-<name>), which costs nothing because it is already loaded. (The font file is weighed under size-assets, but its @font-face rules and every .icon-* class still land in this layer.)
  3. Drop the package and hand-write the residue. If you use one component from a large widget library, its stylesheet is paying for components you never render.
sections/gallery/Carousel.tsx
"use client";
import Swiper from "swiper";
import "swiper/swiper-bundle.css"; // ← every module Swiper ships, plus its icon font
export default function Carousel({ slides }: { slides: { id: string; url: string }[] }) {
// …uses navigation arrows and pagination dots, and nothing else
}
sections/gallery/Carousel.tsx
"use client";
import Swiper from "swiper";
import "swiper/css"; // ← the core layout only
import "swiper/css/navigation"; // ← the two modules this carousel actually uses
import "swiper/css/pagination";
export default function Carousel({ slides }: { slides: { id: string; url: string }[] }) {
// …
}

The arrows and dots that came from the bundle’s icon font are drawn as inline SVG in the component instead, so the layer no longer carries that font’s @font-face and icon-class rules (and the font file no longer shows up under size-assets either).

  • size-renderer-bundle — the section’s JavaScript, held to a guideline at this number and a ceiling well above it.
  • size-assets — the separate, warn-only report on the static asset files (fonts, images) a stylesheet or component references.
  • no-bare-css-import — why a package’s stylesheet is imported from code and never @imported from CSS.
  • TokenTheme — the fonts and tokens the page already loads, which cost you nothing to reuse.