Skip to content
HomePagesHomePages template kit
Menu

template-kit/size-section-css

The template-kit/size-section-css authoring rule — what it enforces, why, and how to fix it.

A section’s compiled CSS must be ≤ 50 KB gzipincluding the package CSS its module graph imports. That inclusion is the whole point of the rule.

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.

Same page, same phone, same buyer as size-renderer-bundle — and here the bytes are worse, because CSS blocks the first paint.

“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 the quickstart. 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 counts against size-assets either).

  • size-renderer-bundle — the same budget on the section’s JavaScript.
  • size-assets — the separate budget 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.
  • Theme and CSS — the fonts and tokens the page already loads, which cost you nothing to reuse.