Custom properties in wp-admin part 2: abstractions

Following on from part 1, this explores some more technical ideas for using custom properties in the WordPress admin.

This is a longer one, so here’s a quick table of contents:

  1. Two sets of variables
  2. Naming the variables
  3. Automating accessible contrast

1. Two sets of variables

This is the idea that there is a base color palette and a set of function-based variables. The function-based variables are the ones which are actually used in the CSS, the base color palette should not be used in CSS.

Using this approach means that we can have color schemes with consistency – a light and dark scheme could use the same color palette, applied differently. Changes would be easier, too – if, say, the button color needs to change, it can be changed in one place, rather than searching all the files where the color is used.

One early idea was that the base colors would be defined in Sass, and built into the different custom properties. This would prevent a plugin from totally overriding “blue” for the whole of wp-admin, and gives a more understandable “API” for styles. A plugin could use --wp-admin--page--background, and know it will always match the page background.

The function-based properties would be editable, but the base WordPress color palette would stay the same. In this case, I think the color names make more sense than primary, etc.

In practice, this could look like:

$white: #fff;
$black: #000;
$blue-10: #9ec2e6;
$blue-50: #2271b1;

body {
    --wp-admin--button-primary--foreground: $white;
    --wp-admin--button-primary--background: $blue-50;
}

// This class is based on current color scheme functionality.
body.admin-color-dark-mode {
    --wp-admin--button-primary--foreground: $black;
    --wp-admin--button-primary--background: $blue-10;
}

// A scheme would not be required to use the default palette (maybe?)
body.admin-color-party {
    --wp-admin--button-primary--foreground: pink;
    --wp-admin--button-primary--background: red;
}

// Then in the individual CSS files, use the custom property.
.button-primary {
    color: var(--wp-admin--button-primary--foreground);
    background: var(--wp-admin--button-primary--background);
}

By using this kind of abstraction, we can also pare down the palette as needed. Right now we’re using all 13 greys, but we could converge onto 7, and since we know where the Sass variables are used, we know we can remove the other 6.

This also opens the door for plugins to customize these colors on their pages. For example, WooCommerce could change its buttons to purple by changing the custom properties:

body.woocommerce {
    --wp-admin--button-primary--foreground: white;
    --wp-admin--button-primary--background: $woo-purple;
}

2. Naming the variables

In the above example, I also snuck in a naming convention. It’s somewhat inspired by the Gutenberg conventions, specifically the idea of -- as a separator, for “readability, for human understanding. It can be thought as similar to the BEM naming schema, it separates “categories”.”

My concept is this format: [prefix]--[location]--[property]--[state], with state optional.

In the example of --wp-admin--button-primary--background, we have:

  • Prefix: --wp-admin, which will be a universal namespace for all admin colors
  • Location: button-primary, all primary button related styles will use this
  • Property: background, the thing actually being controlled by this variable (roughly corresponds to a css property, but not necessarily)
  • State: none, so we know this color applies to the default background

State could be hover, focus, disabled, maybe something that means both hover and focus, if those don’t need to be different. Using the list from my last post, I could see custom properties like this:

--wp-admin--page--background
--wp-admin--surface--background
--wp-admin--surface--border
--wp-admin--text--color
--wp-admin--text-secondary--color
--wp-admin--link--color
--wp-admin--link--color--focus
--wp-admin--link--color--hover
--wp-admin--link--color--destructive
--wp-admin--link--color--warning
--wp-admin--link--color--confirmation 
--wp-admin--notification--border--info
--wp-admin--notification--border--success
--wp-admin--notification--border--warning
--wp-admin--notification--border--error
--wp-admin--row--background
--wp-admin--row--background--alternate
--wp-admin--row--background--info
--wp-admin--row--background--error

These names are specific and understandable, and map to stable UI components in wp-admin (we’re not getting rid of list tables any time soon). The exact terminology used can be debated, but I think this is a good framework.

3. Automating accessible contrast

If we name these variables in a consistent way, would it be possible to ensure that all text and background colors have a 4.5+ contrast ratio? I like this idea, but I don’t think we should make this a goal. For one thing, different schemes will need different contrast minimums. We want to create high contrast schemes, so those would need to pass 7+, and low contrast schemes, which don’t have criteria but maybe shouldn’t exceed some value.

There’s also a technical issue – most of the variables I’ve suggested don’t map to text and background pairs. The main and secondary text colors could be used on any background. It’ll be important to pay attention to the contrast in each scheme, but I don’t think this is something to automate initially.

%d bloggers like this: