WPMake

← Back to BlogStyling a Plugin With CSS Custom Properties Instead of !importantTUTORIAL

Styling a Plugin With CSS Custom Properties Instead of !important

⏱ 3 min read  ·  👤 iamprazol  ·  Sep 3, 2026

Everybody who has styled a WordPress plugin knows the ritual. Open devtools, copy the selector the plugin used, paste it into Additional CSS, watch nothing happen, add a parent selector, watch nothing happen, add !important, move on with your life. Then the plugin updates, the markup changes, and your override styles an element that no longer exists.

The problem is not that plugin authors write bad CSS. It is that specificity is the only tool either side has, and it is a competition rather than an interface.

Custom properties change what you are overriding

When a plugin reads every size, colour and radius from a custom property, its own stylesheet stops being a wall and starts being a default:

.wpmake-advance-user-avatar-container .avatar-preview {
    width: var( --wpmake-aua-avatar-size, 96px );
    height: var( --wpmake-aua-avatar-size, 96px );
    border-radius: var( --wpmake-aua-avatar-radius, 0 );
}

You are no longer competing with that rule. You are supplying the value it reads. Custom properties inherit, so setting one on the container is enough — and because you are not fighting a selector, specificity never enters into it:

.wpmake-advance-user-avatar-container {
    --wpmake-aua-avatar-size: 150px;
    --wpmake-aua-avatar-radius: 50%;
}

Two lines in Appearance → Customize → Additional CSS, no !important, and it applies everywhere the widget appears on the site.

What that looks like in practice

Here is the Advanced User Avatar uploader as it ships — deliberately plain, so it inherits whatever your theme does with buttons:

The default avatar uploader on a front-end page
Out of the box. Square avatar, theme-default buttons.

And here it is after one rule:

.wpmake-advance-user-avatar-container {
    --wpmake-aua-avatar-size: 150px;
    --wpmake-aua-avatar-radius: 50%;
    --wpmake-aua-btn-primary-bg: #2f7d32;
    --wpmake-aua-btn-primary-bg-hover: #27682a;
    --wpmake-aua-btn-capture-color: #2f7d32;
    --wpmake-aua-btn-radius: 999px;
    --wpmake-aua-btn-padding: 10px 20px;
}
The same uploader with a round avatar and green pill buttons
Round avatar, pill buttons, brand colour. No template overrides, no !important, no selectors copied out of devtools.

Scoping it to one placement

Because custom properties inherit down the tree, a class on one instance is all you need to style that instance differently. The shortcodes accept a class attribute for exactly this:

[wpmake_advance_user_avatar_upload class="checkout-avatar"]
.checkout-avatar {
    --wpmake-aua-avatar-size: 64px;
    --wpmake-aua-btn-font-size: 12px;
}

Site-wide rule on the container, per-placement rule on your own class. Neither one needs to know anything about the plugin’s internal markup.

The full set

The naming is consistent, which is half the value — you can guess most of them:

--wpmake-aua-avatar-size          --wpmake-aua-btn-primary-bg
--wpmake-aua-avatar-radius        --wpmake-aua-btn-primary-bg-hover
--wpmake-aua-avatar-spacing       --wpmake-aua-btn-primary-color
--wpmake-aua-width                --wpmake-aua-btn-capture-color
--wpmake-aua-height               --wpmake-aua-btn-capture-color-hover
--wpmake-aua-padding              --wpmake-aua-btn-remove-color
--wpmake-aua-align                --wpmake-aua-btn-remove-border
--wpmake-aua-btn-padding          --wpmake-aua-btn-remove-border-hover
--wpmake-aua-btn-font-size        --wpmake-aua-btn-remove-bg-hover
--wpmake-aua-btn-radius           --wpmake-aua-btn-border-width

If you are building a plugin, do this

Three rules that cost almost nothing at authoring time and save your users hours:

  • Put the properties on a container the user can select, not on :root. A single stable class name is a better public interface than your entire markup tree, and it means two instances on one page can differ.
  • Give every property a fallback in the var() call. Then the widget still renders correctly if your stylesheet loads and the properties do not — and the fallback documents the default.
  • Name them predictably and never rename them. These are public API the moment you ship them. A renamed property silently breaks somebody’s site with no error anywhere.

The deeper point is about where the boundary sits. Markup and selectors are implementation, and a plugin should be free to change them in a minor release. A documented set of custom properties is a contract — one that survives refactors, needs no !important, and turns “how do I make this match my theme” from a devtools expedition into two lines of CSS.

Styling a Plugin With CSS Custom Properties Instead of !important