Make WordPress Core

Opened 3 months ago

Closed 3 months ago

#65443 closed enhancement (duplicate)

Replace hardcoded admin CSS colors with centralized CSS custom properties

Reported by: dervishov Owned by:
Priority: normal Milestone:
Component: Administration Version:
Severity: normal Keywords: has-patch
Cc: Focuses:

Description (last modified by sabernhardt)

I've been digging into how WordPress admin handles colors and noticed something that's been bugging me for a while — there are over 740 hardcoded hex values scattered across 14 CSS files (common.css, forms.css, dashboard.css, list-tables.css, etc.), and the color scheme system can only touch the sidebar and admin bar. The actual content area — page backgrounds, card surfaces, text, borders, form inputs, table rows, notices — is completely locked to static hex values.

This means if you want to build a dark mode, a high-contrast mode, or even just let an agency brand the admin panel beyond the sidebar, you're stuck writing hundreds of selector-level overrides. I tried building a dark scheme and ended up with 390 lines of CSS just to flip the content area colors. That's not sustainable.

So I went ahead and built what I think is a cleaner foundation: a set of 32 semantic CSS custom properties defined in a single :root{} block at the top of common.css. Then I went through all 14 admin CSS files and replaced the hardcoded hex values with var() references.

The property set breaks down like this:

  • Backgrounds--wp-admin-bg-page (#f0f0f1), --wp-admin-bg-card (#fff), --wp-admin-bg-alt (#f6f7f7), --wp-admin-bg-hover, --wp-admin-bg-disabled
  • Text--wp-admin-text-primary (#1d2327), --wp-admin-text-body (#3c434a), --wp-admin-text-secondary (#646970), --wp-admin-text-tertiary (#50575e), --wp-admin-text-placeholder (#a7aaad), --wp-admin-text-inverse (#fff)
  • Borders--wp-admin-border-default (#c3c4c7), --wp-admin-border-light (#dcdcde), --wp-admin-border-emphasis (#2c3338), --wp-admin-border-subtle (#8c8f94)
  • Status — error, warning, success, info — each with a foreground color, background tint, and border accent (10 properties total)
  • Shadows--wp-admin-shadow-color, --wp-admin-overlay-dark


Every default value matches the existing hardcoded hex exactly, so there's zero visual change for any current color scheme. Modern, Midnight, Coffee — they all render identically. The only difference is that now, overriding 32 variables in a color scheme stylesheet is enough to re-skin the entire admin.

To give a concrete example: a dark mode that previously required 390 lines of .admin-color-dark .postbox, .admin-color-dark input[type="text"], .admin-color-dark .widefat td... can now be done in about 35 lines of variable reassignment. Same story for high contrast, reduced motion themes, or agency whitelabel setups.

I intentionally kept this to 32 properties because I wanted to hit the sweet spot — enough to cover 86% of all color instances without creating a maintenance burden. The remaining 14% are mostly theme-color-dependent values already handled by --wp-admin-theme-color, or one-off colors in niche contexts.

A few things I'd love feedback on:

  1. Are the property names clear enough? I went with semantic names like --wp-admin-text-secondary instead of palette-based names like --wp-admin-gray-646970, but I know there are different schools of thought here.
  2. Should the :root{} block live in common.css (as I've done), or would a dedicated file be better?
  3. Is 32 the right number? I could expand to ~40 to capture more edge cases, or trim to ~25 by merging some status variants.

GitHub PR with the full implementation: https://github.com/WordPress/wordpress-develop/pull/12133

Happy to iterate based on feedback from the CSS and design folks.

Change History (3)

This ticket was mentioned in Slack in #core by dervishov. View the logs.


3 months ago

This ticket was mentioned in PR #12133 on WordPress/wordpress-develop by @dervishov.


3 months ago
#2

## Summary

Replace 740+ hardcoded hex color values across 14 admin CSS files with references to 32 semantic CSS custom properties defined in a single :root{} block in common.css.

## Problem

WordPress admin uses hardcoded hex colors scattered across common.css, forms.css, dashboard.css, list-tables.css, edit.css, themes.css, media.css, widgets.css, nav-menus.css, admin-menu.css, customize-controls.css, revisions.css, about.css, and site-health.css. Color schemes can only change the admin menu/bar/buttons — the content area is locked to static values.

## Solution

Define 32 semantic CSS custom properties in common.css :root{}, then replace hardcoded values with var() references.

Backgrounds (5): --wp-admin-bg-page, --wp-admin-bg-card, --wp-admin-bg-alt, --wp-admin-bg-hover, --wp-admin-bg-disabled

Text (6): --wp-admin-text-primary, --wp-admin-text-body, --wp-admin-text-secondary, --wp-admin-text-tertiary, --wp-admin-text-placeholder, --wp-admin-text-inverse

Borders (4): --wp-admin-border-default, --wp-admin-border-light, --wp-admin-border-emphasis, --wp-admin-border-subtle

Status (10): error, warning, success — each with color + background + border variants

Info/Links (2), Shadows (2), Extremes (1)

## Key design decisions

  • Light defaults match existing hardcoded values exactly — zero visual change
  • Semantic naming (--wp-admin-text-secondary not --wp-admin-gray-646970)
  • 32 properties cover 86% of all admin color instances
  • Existing color schemes (Modern, Midnight, etc.) work identically

## What this unlocks

  • Dark mode: Override 32 variables instead of 200+ selector overrides
  • High contrast mode: Adjust text/border contrast from one place
  • Custom branding: Theme the full admin via wp_add_inline_style
  • Plugin compatibility: var(--wp-admin-bg-card) works in any admin context

## Files changed

  • src/wp-admin/css/common.css:root{} block + var() replacements
  • src/wp-admin/css/forms.css — var() replacements
  • src/wp-admin/css/dashboard.css — var() replacements
  • src/wp-admin/css/list-tables.css — var() replacements
  • src/wp-admin/css/edit.css — var() replacements
  • src/wp-admin/css/themes.css — var() replacements
  • src/wp-admin/css/media.css — var() replacements
  • src/wp-admin/css/widgets.css — var() replacements
  • src/wp-admin/css/nav-menus.css — var() replacements
  • src/wp-admin/css/admin-menu.css — var() replacements
  • src/wp-admin/css/customize-controls.css — var() replacements
  • src/wp-admin/css/revisions.css — var() replacements
  • src/wp-admin/css/about.css — var() replacements
  • src/wp-admin/css/site-health.css — var() replacements

## Test plan

  • [ ] npm run build:dev builds successfully
  • [ ] Every admin page looks identical to trunk (zero visual regression)
  • [ ] Browser devtools shows CSS custom properties applied on :root
  • [ ] Existing color schemes (Modern, Midnight, Coffee, etc.) render identically
  • [ ] RTL layout renders correctly
  • [ ] Override test: adding body { --wp-admin-bg-card: red; } turns all card backgrounds red

#3 @sabernhardt
3 months ago

  • Description modified (diff)
  • Keywords needs-design-feedback css removed
  • Milestone Awaiting Review
  • Resolutionduplicate
  • Status newclosed
  • Version trunk

Already tracking this on #49930

Note: See TracTickets for help on using tickets.