Have you ever wanted to give content editors more freedom in the design of the pages they're building without needing to create multiple custom themes? Enter CSS variables!
Step 1: Define and Create Your Fields in the Drupal UI
Whether you add these fields directly to a particular content type, or you create a Brand/Theme taxonomy and add the fields there is up to you. For this example, I'll keep things simple by creating a background color field and a border radius field directly on a node. You can create as many fields as necessary to achieve your desired end result! The more fields you create, the more flexibility you'll give your content editors.
Step 2: Create Variables from Field Values
Once we have our fields defined, we need to access the user-entered field values so we can do something with them. In this example, I've created an Extra Field that gets the values of my background color and border radius fields and stores them in an array.
$background_color = $entity->field_background_color->color ?? '#FAFAFA';
$border_radius = $entity->field_border_radius->value . 'px' ?? '3px';
Step 3: Output CSS Variables
Now that we have our field values stored, it's time to output them so we can use those values in our custom theme. In the output of the extra field I've created, I'm looping over each item in the styles array and assigning it a CSS variable name. Then, I'll output those CSS variables in a style tag, which allows me to access them in my custom theme!
Here's the full Extra Field snippet:
class BrandStyles extends ExtraFieldDisplayBase {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function view(ContentEntityInterface $entity): array {
$output = [];
$styles = [];
$inline_css = '';
$background_color = $entity->field_background_color->color ?? '#FAFAFA';
$border_radius = $entity->field_border_radius->value . 'px' ?? '3px';
$styles['background_color'] = $background_color;
$styles['border_radius'] = $border_radius;
foreach ($styles as $key => $value) {
$inline_css .= '--brand-' . str_replace('_', '-', $key) . ':' . $value . ';';
}
$output['styles'] = [
'#type' => 'html_tag',
'#tag' => 'style',
'#value' => ':root { ' . $inline_css . ' }',
];
return $output;
}
}
Step 4: Use the CSS Variables in Your Custom Theme
Now that we have a style tag with our CSS variables rendering on the page, we can access these variables in our custom theme. For example, I can use the border-radius variable to apply the user-defined value to buttons, cards, inputs, etc. (I always make sure to add a default value, just in case!)
// Background color
body {
background-color: var(--brand-background-color);
}
// Border radius
button, input, .card {
border-radius: var(--brand-border-radius);
}
A Word About Accessibility
It's worth noting that when allowing content editors to select custom background colors, you must ensure that any text placed on top of that background color is accessible. WCAG 2.0 level AA requires a contrast ratio of at least 4.5:1 for normal text. Read Ashley's article on Using Functions to Leverage Accessible Color Contrast with User-Entered Values for more information on this topic.
And there you have it! Now your content editors can easily customize the theme of individual pages without needing to develop multiple custom themes.