Skip to content

WWW CSS Performance Plan (Top 25 Pages)

Created: March 2026 Scope: WWW bundles only (not CRM) Related docs: Performance CSS Bundles | Dead CSS Removal Workflow | FA7 Optimization Report | Asset Build Workflow


Reduce CSS weight and improve load performance on the pages that matter most: the top 25 most-visited WWW pages. Success is measured by gains on representative URLs from that list, not sitewide averages.

All WWW pages share a single global pipeline:

www.bundler.js
└─ www.index.scss
├─ bs.scss → full Bootstrap 5.3 (customised variables)
├─ FA Pro CSS → 5 font families (solid, regular, sharp-solid, sharp-regular, brands)
├─ 00-variables/ → project tokens
├─ 01-base/ → resets + typography
├─ 02-objects/ → layout objects (navbar, footer, etc.)
├─ 03-components/ → large barrel (_components.scss — ~40 partials)
├─ 04-utilities/ → custom utility extensions
├─ Uppy CSS → file upload styles
└─ Fancyapps CSS → carousel + lightbox styles

The global www CSS bundle is approximately 628 KB (production, parsed). Every page on the site pays for the full weight whether it uses the imported modules or not.


Use one of these sources (GA4 recommended for broadest traffic view) and refresh quarterly.

SourceAPI / queryBest for
GA4Seo::Ga4ApiClient#top_pages (ordered by screenPageViews)All traffic including paid, direct, email
First-party visitsSiteMap ordered by visit_count_30d (fed by Seo::VisitsSyncService)Server-verified visits aligned to internal paths
Organic onlyAhrefs top pages (Seo::AhrefsApiClient#top_pages)SEO-focused prioritization

Export exact paths (including locale prefix like /en-US/... if treating locales separately). Deduplicate paths that resolve to the same controller/template.


flowchart LR
exportList["Export top 25 paths"]
groupTemplates["Group by template"]
pickReps["Pick representative URLs"]
baseline["PSI + Coverage baseline"]
globalTier["Optimize shared WWW CSS"]
splitTier["Optional: split barrels"]
exportList --> groupTemplates --> pickReps --> baseline --> globalTier --> splitTier
  1. Export the top 25 page paths from GA4 (last 28-90 days).
  2. Group by controller/template — many paths share the same layout (e.g. all blog posts use one template).
  3. Pick representatives — one URL per template group to keep the test matrix small (aim for 10-15).
  4. Baseline — run PSI and Chrome Coverage on each representative (see Measurement below).
  5. Optimize — work through the tiers below, re-measuring after each meaningful change.

Run all measurements against the same representative URLs with a consistent device profile.

ToolWhat it tells youHow to run
Webpack treemapModule-level breakdown of JS and CSS bundlesmise exec -- yarn analyze:webpack then open tmp/webpack-bundle-report.html
PSI / LighthouseLCP, CLS, unused-CSS opportunityPageSpeed Insights (mobile, same throttling each time)
Chrome CoverageSession-level used vs unused bytes per stylesheetDevTools → Coverage panel; include user interactions on tool pages

Record each baseline in the table below (or a linked spreadsheet). Re-run after meaningful CSS changes and compare same URL, same profile.

Interpreting “unused CSS”: Lighthouse will flag Bootstrap utilities and global component styles that are used on other routes. Treat the number as a trend indicator, not a delete list. See Dead CSS Removal Workflow for safe procedures.


Every top-25 page pays for these. Reducing them yields the broadest impact.

AreaCurrent stateAction
BootstrapFull @forward "bootstrap/scss/bootstrap" via bs.scssAudit which Bootstrap modules are actually used across templates. Moving to a curated partial import is a large change — requires class-level grep of app/views/, components, and Stimulus DOM. Defer until Coverage data identifies the heaviest unused modules.
_components.scss barrel~40 partials imported globallyIdentify partials that only serve one or two templates (e.g. page-checkout, page-smartplan). Candidates for extraction into route-scoped CSS entries or lazy-loaded chunks.
Font Awesome5 CSS families imported in www.index.scssInventory which FA families appear in ERB/components across the top-25 templates. Drop any family with zero references. See FA7 Optimization Report for prior work.
Fancyapps CSSLazy-loadedfancy_carousel_controller.js already imports @fancyapps/ui/dist/carousel/*.css on demand alongside each plugin’s JS, so only carousel-bearing pages pay for it. Keep this pattern when adding new plugins (Lazyload, Toolbar, etc.).
Uppy CSSGlobal importOnly a handful of routes use file uploads — candidate for lazy-loading alongside the Uppy JS in the same way Fancyapps now does.
Orphan SCSSOngoingContinue removing unreferenced partials (rg for basename + @use/@import paths; delete only when confirmed unused).

Tier B — Template-driven (after bucketing the top 25)

Section titled “Tier B — Template-driven (after bucketing the top 25)”

Once the 25 pages are grouped by template, optimizations can target the heaviest template buckets:

  • Blog / content — Usually typography + cards + nav. Coverage may show that many _components.scss partials are cold on these routes.
  • Homepage — Already has a separate wwwHomeStyles entry; check for overlap with the global bundle.
  • Quote builder / tools — Heavier on JS; CSS weight is secondary to interaction performance (INP). Ensure lazy-loaded chunks cover tool-specific styles.

Tier C — Strategic (separate initiative)

Section titled “Tier C — Strategic (separate initiative)”
  • PurgeCSS — Only with comprehensive safelists (Bootstrap utilities, dynamic classes, CMS content, Stimulus-added classes). Treat as its own project with full QA and rollback. See Dead CSS Removal Workflow.
  • Critical CSS — Only if LCP on key pages is dominated by render-blocking CSS after Tier A/B work. Measure first.

Source: GA4 property 252042830 (screenPageViews, 90-day window ending March 23 2026). Locale duplicates (en-CA) excluded; paths stripped to route-level for controller mapping. Refresh quarterly.

RankPage pathViews (90d)ControllerBucketRep
1/16,877pages#show (home)global-heavyY
2/floor-heating15,611pages#showglobal-heavyY
3/quote-builder9,843www/quote_builder#showtoolY
4/snow-melting/heated-driveway9,306pages#showglobal-heavy
5/towel-warmer8,526www/towel_warmers#indexglobal-heavyY
6/floor-plans/bathroom8,181www/floor_plan_displays#by_room_typetoolY
7/snow-melting7,822pages#showglobal-heavy
8/snow-melting/quote-builder7,060www/quote_builder#showtool
9/posts/How-to-Calculate-the-Cost-of-a-Heated-Driveway-11816,951posts#showcontentY
10/products/code/WHMA-120-03056,000www/products#codeglobal-heavyY
11/posts/9-pros-and-cons-of-heated-floors5,714posts#showcontent
12/floor-heating/quote-builder5,429www/quote_builder#showtool
13/my_cart4,297my_carts#showtoolY
14/products/code/WHCA-120-00434,171www/products#codeglobal-heavy
15/products/code/WHMA-120-02053,205www/products#codeglobal-heavy
16/posts/How-Much-Does-Floor-Heating-Cost-25743,107posts#showcontent
17/radiant-heat-panels2,979www/radiant_panels#indexglobal-heavyY
18/quote2,871www/leads#quoteglobal-heavyY
19/posts/remove-driveway-ice-without-salt2,816posts#showcontent
20/tools/online-design-tool2,643pages#showglobal-heavyY
21/posts2,633posts#indexcontentY
22/posts/bathroom-floor-heating-...2,633posts#showcontent
23/floor-heating/thermostats2,551pages#showglobal-heavy
24/floor-heating/heated-floor-mat2,511pages#showglobal-heavy
25/product-reviews2,481www/reviews#index (redirect)global-heavyY
TemplateControllerCountCombined viewsRep URL for testing
CMS static pagepages#show967,189/floor-heating
Blog postposts#show621,221/posts/How-to-Calculate-the-Cost-of-a-Heated-Driveway-1181
Quote builderwww/quote_builder#show322,332/quote-builder
Product pagewww/products#code313,376/products/code/WHMA-120-0305
Towel warmer PLPwww/towel_warmers#index18,526/towel-warmer
Floor planswww/floor_plan_displays#by_room_type18,181/floor-plans/bathroom
Cartmy_carts#show14,297/my_cart
Blog indexposts#index12,633/posts

13 representative URLs cover all template groups for PSI/Coverage testing.

Bucket values: global-heavy (layout + nav + footer dominant), content (blog, CMS), tool (quote builder, calculators, room planner).

Rep: Y marks the URL that represents its template group in PSI/Coverage testing.


  • CRM bundles — Separate entry point, separate audience. Duplicate Bootstrap across WWW and CRM is expected and intentional.
  • Third-party script weight (GTM, analytics pixels) — Not controlled by CSS pipeline.
  • Server-side rendering or caching — Orthogonal to stylesheet optimization.