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 gzip — including 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.
Reason
Section titled “Reason”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:
- 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.
- 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 undersize-assets, but its@font-facerules and every.icon-*class still land in this layer.) - 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.
Before
Section titled “Before”"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}"use client";
import Swiper from "swiper";import "swiper/css"; // ← the core layout onlyimport "swiper/css/navigation"; // ← the two modules this carousel actually usesimport "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).
See also
Section titled “See also”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.