Continuing the discussion from Styling Discourse with variables: Show & Tell:
I totally appreciate the effort to improve Discourse’s theming experience! However, I’m not entirely convinced that the approach of adding a lot of css variables as shared in the above topic is the optimal solution. I wanted to share a few thoughts on why.
I’ve been experimenting with this approach myself through the Canvas Theme Template, which essentially provides a collection of adjustable variables for building base themes:
:root {
/* Layout */
--d-max-width: 1110px;
--canvas-nav-space: 0.75rem;
--canvas-content-padding: 1.5rem;
--canvas-topic-list-padding: 0.8em;
/* Base Styles */
--canvas-background: var(--secondary);
--canvas-surface: var(--secondary);
--canvas-border: 1px solid var(--primary-500);
--canvas-border-light: 1px solid var(--primary-200);
/* Border Radius */
--d-border-radius: 2px;
--d-border-radius-large: 2px;
--d-button-border-radius: 2px;
--d-input-border-radius: var(--d-button-border-radius);
--d-nav-pill-border-radius: var(--d-button-border-radius);
/* Button Styles */
--canvas-button-padding: 0.5em 0.65em;
--canvas-button-primary-padding: 0.5em 0.65em;
/* Header */
--canvas-header-height: 4rem;
--canvas-header-background: var(--header_background);
--canvas-header-border: none;
--canvas-header-shadow: var(--shadow-header);
/* Sidebar */
--d-sidebar-width: 17em;
--d-sidebar-background: var(--secondary);
--canvas-sidebar-border: 1px solid var(--primary-low);
--canvas-sidebar-scrollbar: var(--scrollbarWidth);
--d-sidebar-row-height: 2.2em;
--d-sidebar-highlight-background: var(--primary-low);
/* And several more... */
}
While this works reasonably well for simple adjustments, I’ve run into several limitations when trying to scale this approach:
Cognitive Overhead and Discoverability
An extensive list of variables essentially requires a lookup table. This feels disconnected from how you’d typically work in a component-based framework, where I’d actually expect to style components. And maybe that’s just me, but I feel it shifts the mental model from “I want to style this component” to “I need to find the right variable name.”
Lack of Cascading Logic
The current implementation assigns hard-coded values directly to variables without establishing a proper cascade hierarchy:
--d-sidebar-link-color: var(--primary-high);
--d-nav-background-color--active: transparent;
--table-border-width: 1px;
This means there’s no inheritance from more general variables like --link-color
or --border-width
. If I want to make systematic changes, I need to update multiple specific variables instead of changing one foundational value.
Design-to-Development Gap
I think the approach creates friction when working between design tools (like Figma) and implementation. Design systems typically use semantic variables that don’t map one-to-one with these very implementation-specific variables.
An alternative approach that embraces the component architecture
I think we could achieve the same goal more naturally by combining basic semantic variables with reliable component targeting. Instead of having a long list of specific variables, what if we could just count on unique and consitstently named component classes throughout Discourse? Things like .d-sidebar
, .d-topic-list
, .d-header
.
Then pair that with a smaller set of foundational variables that actually cascade the way CSS is meant to work:
/* Set the design foundation */
:root {
--d-border-width: 2px;
--d-surface-color: #3498db;
--d-space-1: 1rem;
}
/* Override at the component level when you need to */
.d-topic-list,
.d-sidebar {
--d-border-width: 1px;
}
To me this feels more like how CSS naturally works. I set my global styles, then refine them where needed. When I want to change how borders look across the app, I change one variable. When I want the sidebar to be different, I target the sidebar specifically.