🎨 CSS Hack: Role-Based App Themes

Here’s a simple dynamic CSS trick to make your Glide app’s theme automatically change based on user roles — like admin, member, vip or banned.
By declaring global CSS variables and using the :is() selector to shorten rules — together with :has() for data-driven conditions — you can keep your CSS clean, dynamic, and highly scalable.

ScreenRecording2025-11-01112758-ezgif.com-video-to-gif-converter

:globe_showing_americas: 1. Global Variable Declaration
Define role-based color variables that your app can reference dynamically.

/* Global variable declaration */
#root:has(.admin) {
  --theme-color: #2F6783;
  --theme-color-light: rgb(85, 137, 166);
}

#root:has(.member) {
  --theme-color: #8247A0;
  --theme-color-light: rgb(163, 115, 191);
}

#root:has(.vip) {
  --theme-color: #D9A441;
  --theme-color-light: rgb(237, 206, 129);
}

#root:has(.banned) {
  --theme-color: #555;
  --theme-color-light: #999;
}

:gear: 2. Data-Driven Theme Application
Apply the declared variables to UI elements based on detected user roles.

/* Data-driven theme application */
#page-root:has(:is(.admin, .member, .vip, .banned)) #nav-root > div {
  --container-bg-color: var(--theme-color);
}

#page-root:has(:is(.admin, .member, .vip, .banned)) .accent-bg,
#page-root:has(:is(.admin, .member, .vip, .banned)) .accent,
#page-root:has(:is(.admin, .member, .vip, .banned)) .user-controls-accent {
  background: var(--theme-color);
}

#screen:has(:is(.admin, .member, .vip, .banned)) {
  --app-color-accent: var(--theme-color);
}

#page-root:has(:is(.admin, .member, .vip, .banned)) .mapboxgl-marker path {
  fill: var(--theme-color);
}

#page-root:has(:is(.admin, .member, .vip, .banned)) {
  --gv-accent: var(--theme-color);
  --gv-text-accent: var(--theme-color);
  --gv-text-contextual-accent: var(--theme-color-light);
}

:puzzle_piece: 3. Example HTML element inside your Rich Text component
Dynamically apply one of the following elements in your Rich Text component according to the user profile data.

<div class="member"></div> or
<div class="vip"></div> or
<div class="admin"></div> or
<div class="banned"></div> or
<div class="admin banned"></div>

This will trigger the corresponding .member, .vip, .admin, or .banned logic above and switch your app’s theme color instantly.


:open_book: Read more:
Main method and concept explained in :brain: CSS Hack: Dynamic CSS in Glide

:sparkles: Inspired by @Robert_Petitto’s question about reducing repetitive CSS code.

9 Likes

Good work!

1 Like

:light_bulb: Update note:
Turns out you can actually skip :is():has() already supports multiple selectors separated by commas.
So this works perfectly fine too:

#page-root:has(.admin, .member, .vip, .banned) .target

:puzzle_piece: Revision

/* Data-driven theme application */
#page-root:has(.admin, .member, .vip, .banned) #nav-root > div {
  --container-bg-color: var(--theme-color);
}

#page-root:has(.admin, .member, .vip, .banned) :is(.accent-bg, .accent, .user-controls-accent) {
  background: var(--theme-color);
}

#screen:has(.admin, .member, .vip, .banned) {
  --app-color-accent: var(--theme-color);
}

#page-root:has(.admin, .member, .vip, .banned) .mapboxgl-marker path {
  fill: var(--theme-color);
}

#page-root:has(.admin, .member, .vip, .banned) {
  --gv-accent: var(--theme-color);
  --gv-text-accent: var(--theme-color);
  --gv-text-contextual-accent: var(--theme-color-light);
}

:is() is best used for multiple targets (elements you want to style the same way)

2 Likes