Skip to main content

Fix WordPress FSE Theme Footer Text Visibility - WCAG Contrast Issue

Β· 3 min read

While developing a WordPress FSE enterprise theme for a client, I discovered the Footer block text was nearly invisible across multiple Style Variations. This post documents the complete fix process - from WCAG contrast diagnosis to introducing semantic colors and handling global styles override.

TL;DR​

Problem: FSE theme's contrast color token has conflicting semantics. In light themes, contrast β‰ˆ light gray β‰ˆ base (white), resulting in Footer contrast ratio of only 1.05:1.

Solution:

  1. Introduce surface semantic color for dark block backgrounds
  2. Delete override styles in wp_global_styles
  3. Add surface definition to all Style Variations

Result: Contrast ratio improved from 1.05:1 to 15.8:1 (WCAG AAA grade).

Problem​

Footer block uses backgroundColor="contrast" + textColor="base":

<!-- wp:group {"backgroundColor":"contrast","textColor":"base"} -->
<div class="has-base-color has-contrast-background-color">
Footer content
</div>

Under default theme, Footer text is nearly invisible:

CombinationForegroundBackgroundContrastWCAG
Footer text#ffffff (base)#f8fafc (contrast)1.05:1❌ Fail
Footer link#f59e0b (accent)#f8fafc (contrast)1.78:1❌ Fail

WCAG AA standard requires β‰₯ 4.5:1 for normal text. Current state is far below standard.

Root Cause Analysis​

1. Conflicting contrast Semantics​

contrast was designed as "background color that contrasts with base", but semantics conflict across themes:

VariationbasecontrastExpected vs Actual
Default (light)#ffffff white#f8fafc light grayExpected dark, actual light
Tech (dark)#0f0f1a deep black#1e1e2e deep purpleExpected light, actual dark

Footer Pattern assumes contrast is a dark background, but in 5/6 Style Variations it's light.

2. Missing Semantic Color for Dark Blocks​

Original design system only had one "contrast" color, without distinguishing:

  • Light contrast blocks (CTA Banner, etc.)
  • Dark contrast blocks (Footer, dark Hero, etc.)

Solution​

Step 1: Introduce surface Semantic Color​

Add surface token in theme.json for dark block backgrounds:

{
"slug": "surface",
"color": "#0f172a",
"name": "Surface"
}

Step 2: Update All Style Variations​

Each variation defines its own surface color (usually equals primary):

// styles/commerce.json
{ "slug": "surface", "color": "#1f2937", "name": "Surface" }

// styles/nature.json
{ "slug": "surface", "color": "#14532d", "name": "Surface" }

// styles/tech.json (dark theme)
{ "slug": "surface", "color": "#1e1e2e", "name": "Surface" }
<!-- wp:group {"backgroundColor":"surface","textColor":"base"} -->
<div class="has-base-color has-surface-background-color">
Footer content
</div>

Step 4: Delete Global Styles Override​

Colors still not working after modifying theme.json? Check global styles:

# Check if global styles exist
docker exec wp_cli wp post list --post_type=wp_global_styles --fields=ID,post_title --allow-root

# Delete global styles
docker exec wp_cli wp post delete <ID> --force --allow-root
docker exec wp_cli wp cache flush --allow-root

Reason: color.palette in wp_global_styles completely overrides (not merges) theme.json's palette.

Results​

Variationsurface + base ContrastWCAG Grade
Default15.8:1βœ… AAA
Commerce13.1:1βœ… AAA
Industrial12.6:1βœ… AAA
Professional9.9:1βœ… AAA
Nature10.8:1βœ… AAA
Tech11.5:1βœ… AAA

Color Semantics Summary​

TokenPurpose
primaryBrand color (Logo, primary button)
secondarySecondary elements
accentCall to action (CTA, links)
basePage main background
contrastLight contrast block background
surfaceDark block background (Footer, dark CTA) ← New

Interested in similar solutions? Get in touch