0
0
Fork 0
mirror of https://github.com/discourse/discourse.git synced 2026-08-06 13:08:40 +08:00
discourse/.skills/discourse-writing-html-css/references/color-and-theming.md
Kris 7f1cff822f
FEATURE: LLM skills for writing HTML and CSS (#40410)
This attempts to define some useful rules for LLMs to write better HTML
and CSS for Discourse... the basics covered include:

**Naming (BEM)**
- `block__element` + standalone `.--modifier` (two-dash); `is-`/`has-`
state classes
  - Name by meaning, not appearance (no position/color/size in names)
  - Don't interpolate user input into class names — use data attributes
  - Prefer a state class over `:has()`

  **Color & theming**
- Never hardcode color; use the custom-property palette; no separate
dark-mode block
- `--token-color-*` for standard UI, palette for bespoke; `--d-*` design
vars
  - Don't rely on color alone; WCAG AA contrast; forced-colors awareness

  **CSS authoring**
- Native CSS over compile-time SASS; keep `z()`, `lib/viewport`, `&`
nesting
  - Low specificity; avoid `!important` (comment when unavoidable)
  - `em`/`rem` + flexible sizing + `overflow-wrap`; `gap` over margins
- Local custom properties for reuse/`calc()`; mobile-first, intrinsic
layout
  - RTL via logical properties
  - Shared mixins (`ellipsis`, `line-clamp`, `d-animation`)
  - Style with restraint — minimal styling, leave aesthetics to themes

  **Accessibility**
  - Semantic/landmark markup; heading levels by outline
- Icon-only labels; `.sr-only` (not `display:none`); live regions via
the `a11y` service
- `:focus-visible`; `prefers-reduced-motion`; animate
`transform`/`opacity`
  - Design to work without hover

  **Templates**
- Escape by default (XSS); `dIcon` with valid sprite icons; translatable
strings
- `<DButton>` variants; FormKit for forms; `...attributes` on root;
`dConcatClass`
- `<PluginOutlet>` (don't add speculatively); avoid div-itis & empty
containers

  **Stylesheet placement**
- `common/` responsive stylesheets (`desktop/`/`mobile/` deprecated);
plugin/theme registration
  - Lint with `bin/lint --fix`
  
Also fixed an issue with two docs having the same index and cleaned up
some references to align better.
2026-06-01 11:08:46 -04:00

5.1 KiB
Vendored

Color & theming reference

Companion to the Color & theming section of SKILL.md. The cardinal rule lives there: never hardcode color, and never write a separate dark-mode block — the palette inverts. This file is the variable inventory.

All variables are defined in app/assets/stylesheets/color_definitions.scss and remapped per color scheme, so the same variable is dark in dark mode and matches any theme's palette.

The core palette

Each base color has a graduated scale blending it toward its opposite (-low is closest to the background, -high closest to the foreground), plus numeric steps -50-900.

Variable family Use for
--primary / --primary-low--primary-high, --primary-100--primary-900 Main text and foreground; low steps for subtle borders/backgrounds
--secondary Main background / surface
--tertiary (+ scale) Accent, links, primary actions
--quaternary Secondary accent for themes
--danger, --success, --love, --highlight (each + -low/-medium/-hover) Semantic states
--header_background, --header_primary Header surface and its text
--d-hover, --d-selected Hover / selected affordances

Need a translucent color? Use the -rgb triplet variants inside rgba():

background: rgba(var(--tertiary-rgb), 0.1);

Semantic design tokens (preferred for new UI)

app/assets/stylesheets/common/tokens.scss layers semantic tokens on top of the palette. Prefer these when one fits — they encode intent and already handle light/dark via light-dark():

  • Text: --token-color-text-default, --token-color-text-subtle, --token-color-text-accent, --token-color-text-inverse
  • Icons: --token-color-icon-default, --token-color-icon-subtle, --token-color-icon-danger
  • Borders: --token-color-border-default, --token-color-border-focused, --token-color-border-input
  • Surfaces: --token-color-surface, --token-color-surface-hovered, --token-color-surface-selected
  • Sizing: --token-radius-small|normal|large|full, --token-border-width
  • Weight: --token-font-weight-regular|medium|semibold|bold

General-purpose --d-* design vars

A family of app-wide design constants — --d-border-radius (and --d-border-radius-large, --d-input-border-radius), --d-content-background, --d-link-color, --d-hover, --d-selected — for conventions like the standard corner radius and link color. Prefer these over inventing your own constant so a component matches the rest of the UI (and a theme can retune them globally).

Which to reach for: a raw palette var when no token fits; a token or --d-* var when one does.

Theming components via their design vars

Many components expose --d-* custom properties as theming hooks: override the variable (globally in :root, or scoped to a wrapper) to retheme the component without rewriting its selectors or fighting specificity. Coverage varies by component and is still expanding, so treat the listed source file as the authoritative, current set — these are entry points, not exhaustive lists.

Rounded corners

--d-border-radius is the standard corner radius used across the UI; --d-border-radius-large is the larger step. Component radii derive from it — --d-button-border-radius, --d-input-border-radius, --d-nav-pill-border-radius, --d-tag-border-radius. Override --d-border-radius to round everything consistently; override a component's own var to change just that component. (Semantic-token equivalents: --token-radius-small|normal|large|full.)

Buttons

common/components/buttons.scss defines the button hooks in :root, by variant:

// pattern: --d-button-{variant}-{text-color|bg-color|icon-color|border}[--hover]
// variants: default, primary, danger, success, flat
:root {
  --d-button-primary-bg-color: var(--tertiary);
  --d-button-primary-bg-color--hover: var(--tertiary-hover);
}

Plus globals --d-button-border-radius, --d-button-border, --d-button-transition. Override these to restyle every button of a variant without touching .btn selectors.

Inputs & form elements

common/base/discourse.scss defines input hooks: --d-input-bg-color, --d-input-border, --d-input-text-color, --d-input-focused-color, --d-input-border-radius (each with a --disabled variant where relevant). For FormKit layout (gutters, input widths), see the --form-kit-* vars in common/form-kit/_variables.scss (--form-kit-gutter-x/y, --form-kit-max-input, --form-kit-{small,medium,large}-input).

Sidebar (and admin sidebar)

common/base/sidebar.scss defines the sidebar hooks: --d-sidebar-background, --d-sidebar-active-background, --d-sidebar-active-color, --d-sidebar-active-icon-color, --d-sidebar-animation-time/-ease, etc. The admin layout's sidebar adds --d-sidebar-admin-* (e.g. --d-sidebar-admin-background) in admin/sidebar.scss. Override these to retheme the sidebar in either context without overriding its internal selectors.