FlexPlat logoFlx Modernize

Step 9: Restyle in Tailwind

Steps 3–6 made the pages look native by reusing WordPress's own stylesheet: about 175 KB of CSS inlined in every page. Once the markup matches, you can replace that stylesheet with the renderer's own Tailwind CSS, keeping the score. On Twenty Twenty-Five this took five small tasks and two days, and the score went up to 94.2% / 90.9%.

Keep a switch, and measure both sides

Add a style mode before changing any styles (src/lib/styleMode.ts, FLX_RENDER_STYLE_MODE):

  • wp: today's output, WordPress's full global styles inlined. This becomes the rollback.
  • the new mode: only the theme's preset variables (--wp--preset--*, about 4 KB of the 175 KB) are inlined; everything else comes from the renderer's stylesheet.

In CI, capture the same pages in both modes, on the same content (run the second capture before any check that adds posts), and report both tables. Switch the default only when the new mode passes the same gate.

Order of work

  1. Tokens (src/styles/tailwind.css, @theme inline): map each preset to a Tailwind token that reads the WordPress variable: bg-wp-base, text-wp-contrast, font-wp-manrope, text-wp-large, p-wp-50, max-w-wp-content. A site's palette, font and size choices then still apply.
  2. Chrome in utilities (header, menu, footer, post lists, pagination, search form, 404): put the theme's layout rules in one place as class strings (src/platforms/wp/twentytwentyfive/tw.ts: global padding, alignfull and alignwide, constrained children, block gap) and use them in the templates. Keep the wp-block-* class names as hooks for the menu script and plugins. The copied per-page wp-container-* rules from steps 4 and 6 go away.
  3. Templates and text blocks: rebuild the page and post templates from the theme's templates/page.html and single.html. Port WordPress's block-library CSS for layout and text blocks into a cascade layer (src/styles/content.css), reading the same presets. Inside post content, restore browser defaults (margins, list bullets) with revert: native content relies on them, and Tailwind's preflight removes them.
  4. Media and site blocks (media.css, site-blocks.css): images, galleries, covers, embeds, search, latest posts, social icons. Two values WordPress prints per block (the gallery gap) or on <body> (wp-embed-responsive, which embed aspect ratios depend on) must be supplied by the renderer.
  5. Switch the default when both modes score the same. Keep FLX_RENDER_STYLE_MODE=wp as a one-variable rollback.

A local loop before each CI run

A CI run takes about ten minutes. To iterate faster, save the payloads the CI run sent (they are in its artifacts), render them locally with the current build in both modes, and compare each page against a frozen copy of the production render and against the native HTML: a pixel match at 1280 and 390 px, plus an element-by-element diff of boxes and key computed styles (font, size, colour, spacing). Then use the CI run to confirm. The script used for Twenty Twenty-Five is compare.mjs in the project's ops folder (Playwright and pixelmatch); any similar script works.

Results on Twenty Twenty-Five

Task wp mode (live) new mode
tokens and switch 80.9 / 77.4 51.7 / 56.4 (baseline)
chrome in utilities 80.9 / 77.3 63.1 / 69.4
templates, layout and text blocks 91.2 / 86.4 86.6 / 86.3
media and site blocks 94.2 / 90.9 94.2 / 90.9

The template work raised both modes, because it fixed markup, not only styles. Page HTML went from about 187 KB to 17 KB (26 KB to 4 KB compressed). The stylesheet (52 KB, 10 KB compressed) is cached by the browser across pages under a versioned URL (Flx Render).

Known gap of the new mode: a site's Additional CSS and Global Styles edits other than preset values are not applied.

Check: the CI gate passes in the default mode, and the rollback mode's report matches it.

Published from rickey29/twenty-twenty-five at commit 837705d · Flx Modernize 1.11.0 · Flx Render 1.11.0