Skip to content

Design-Tokens

Das Frontend-Design steuert ein LESS-Token-System mit zentralen Variablen in custom.less. Tokens werden sowohl als LESS-Variablen (@colorPrimary) als auch als CSS-Custom-Properties (--color-primary) bereitgestellt — Admin-UI unter /admin/design erlaubt Live-Editing ohne Rebuild. Diese Seite zeigt alle Tokens, das Mapping zu CSS-Variablen und die Cache-Integration.

Token-Quelle

Die zentrale Datei liegt nicht im Theme, sondern global im CMS:

_public/src/css/frontend/custom.less

Sie wird beim Frontend-CSS-Build von allen Themes gelesen und als Bestandteil des Bundles kompiliert. Redakteure koennen den Inhalt ohne Deploy direkt im Admin unter /admin/design editieren — die Aenderungen landen dann in der DB (website.custom_less) und werden beim naechsten Cache-Rebuild aus der DB gelesen.

Farben (17 Tokens)

LESS-VariableCSS-VariableDefaultZweck
@colorPrimary--color-primary#0368DBButtons, Links, Akzente
@colorPrimaryHover--color-primary-hoverdarken(#0368DB, 8%)Button-Hover
@colorDanger--color-danger#D40D12Fehler, Loeschen
@colorSuccess--color-success#45BF55Erfolg
@colorWarning--color-warning#FFC144Warnung
@colorText--color-text#333333Haupt-Textfarbe
@colorTextLight--color-text-light#8A92A6Helle Textfarbe, Borders, Inputs
@colorWhite--color-white#ffffffHintergruende
@colorBackground--color-background#ffffffSeiten-Hintergrund
@colorBorder--color-border#8A92A6Input-Borders, Trennlinien
@colorScrollbar--color-scrollbar#A3A3A5Scrollbar
@colorOverlay--color-overlayrgba(0, 0, 0, 0.8)Loader/Modal-Overlay
@colorMobileMenu--color-mobile-menu#014034Mobile-Menu-Hintergrund
@colorCookieAccent--color-cookie-accent#11327aCookie-Consent-Akzent
@colorCookieText--color-cookie-text#58585aCookie-Consent-Text
@colorLink--color-link#337ab7Alternative Link-Farbe
@colorError--color-error#ff0000Error-Border (Inputs)

Typografie (8 Tokens)

LESS-VariableCSS-VariableDefaultZweck
@fontBody--font-body'Inter', sans-serifHaupt-Schrift
@fontIcon--font-icon'Font Awesome 6 Pro'Icon-Font
@fontSizeBase--font-size-base14pxStandard-Schriftgroesse
@fontSizeSmall--font-size-small12pxKleine Schrift
@fontWeightLight--font-weight-light300Duenne Schrift
@fontWeightRegular--font-weight-regular400Normal
@fontWeightMedium--font-weight-medium500Mittel/Strong
@lineHeightBase--line-height-base1.429emZeilenabstand

Spacing (7 Tokens)

LESS-VariableCSS-VariableDefaultZweck
@spacingBase--spacing-base8pxBasis-Einheit
@spacingSmall--spacing-small10pxKlein
@spacingMedium--spacing-medium20pxMittel
@spacingLarge--spacing-large30pxGross
@spacingXLarge--spacing-xlarge40pxExtra-gross
@spacingSection--spacing-section40px.ns-row margin-bottom
@spacingForm--spacing-form30px.form-group margin-bottom

Layout (5 Tokens)

LESS-VariableCSS-VariableDefaultZweck
@radiusBase--radius-base4pxStandard-Border-Radius
@radiusRound--radius-round25pxPill-Shape (runde Buttons)
@inputHeight--input-height44pxHoehe von <input>/<select>
@buttonLineHeight--button-line-height44pxLine-Height fuer .btn
@scrollbarWidth--scrollbar-width6pxScrollbar-Breite

Breakpoints (2 Tokens)

LESS-VariableDefaultVerwendung
@breakpointDesktop991pxTablet-zu-Mobile-Breakpoint fuer Navigation, Layout
@breakpointMobile768pxKlassischer Mobile-Cut

Beide Breakpoints sind nur als LESS-Variablen verfuegbar — CSS-Variables werden nicht generiert (Media-Queries akzeptieren keine CSS-Variables im Selektor).

Pagebuilder nutzt eigene Breakpoints

Die hier gelisteten Tokens (991px/768px) gelten fuer das Frontend-Theme-Layout (Navigation, Mobile-Menu). Das Pagebuilder-Responsive-System (Column-Widths, Spacing, Flex) nutzt einen eigenen festen Satz: 1200px / 992px / 768px fuer Desktop/Laptop/Tablet/Mobile. Diese Pagebuilder-Breakpoints werden von cache_compress_css.php fuer Media-Queries generiert und sind nicht aus custom.less-Tokens editierbar — sie sind Teil der Pagebuilder-Architektur.

Shadow (1 Token)

LESS-VariableCSS-VariableDefault
@shadowCard--shadow-card0px 4px 20px rgba(0, 0, 0, 0.08)

:root — CSS-Custom-Properties-Block

Am Ende der Token-Definition generiert custom.less einen :root {}-Block, der alle Tokens ausser Breakpoints als CSS-Custom-Property verfuegbar macht (Breakpoints gehen nicht, siehe Abschnitt weiter unten):

less
:root {
    --color-primary:       @colorPrimary;
    --color-primary-hover: @colorPrimaryHover;
    --color-text:          @colorText;
    --font-body:           @fontBody;
    --font-size-base:      @fontSizeBase;
    --spacing-base:        @spacingBase;
    --spacing-section:     @spacingSection;
    --radius-base:         @radiusBase;
    --shadow-card:         @shadowCard;
    /* ... alle weiteren */
}

Warum beides?

  • LESS-Variablen (@colorPrimary): Compile-Zeit, koennen in Mixins und Berechnungen (darken(), fade()) verwendet werden.
  • CSS-Custom-Properties (var(--color-primary)): Runtime, koennen dynamisch via JavaScript geaendert werden (z. B. Theme-Switch), vererben durch DOM-Tree.

Komponenten, die nur Werte referenzieren, koennen beides nutzen. Dynamische Theme-Overrides laufen ueber CSS-Variables:

css
/* Dark-Theme-Override auf Body */
body.dark-theme {
    --color-text: #f0f0f0;
    --color-background: #0b0f1a;
}

Das menueditor-Plugin nutzt ein zweites Set von CSS-Variablen mit --me-*-Prefix, die aus den Design-Tokens abgeleitet werden:

less
.me-wrapper {
    --me-bg:              @colorBackground;
    --me-primary:         @colorPrimary;
    --me-primary-fade:    fade(@colorPrimary, 5%);
    --me-text:            @colorText;
    --me-text-light:      @colorTextLight;
    --me-border:          fade(@colorBorder, 25%);
    --me-dropdown-bg:     @colorBackground;
    --me-dropdown-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
    --me-spacing:         @spacingBase;
    --me-radius:          @radiusBase;
    --me-nav-height:      56px;
    /* ... */
}

Das erlaubt dem Menu-Editor eigene Abweichungen (z. B. me-dropdown-shadow ist spezifischer als shadow-card), ohne die globalen Tokens zu aendern. Das Menu-LESS lebt unter _public/src/css/frontend/menu.less und nutzt var(--me-*).

Details zum Menu-Editor-System liegen im php-backend-check-Skill im Abschnitt "Menu Editor".

Live-Editing via /admin/design

Der Design-Token-Editor unter /admin/design zeigt den kompletten Inhalt von custom.less in einem CodeMirror-Editor mit LESS-Syntax-Highlighting und Syntax-Validierung:

1. /admin/design oeffnen
2. Token-Werte anpassen (z. B. @colorPrimary: #E11D48;)
3. "Speichern" klicken
4. Core validiert LESS via Less_Parser
5. Neuer Wert landet in website.custom_less (DB-Spalte)
6. Core triggert Cache-Rebuild via rebuildCssCache()
7. Neue Tokens sind nach dem Rebuild wirksam — ohne Deploy

Der Rebuild in Schritt 6 laeuft im Normalfall automatisch direkt nach dem Save. Wenn er fehlschlaegt (z. B. APCu-Permission, DB-Verbindungsproblem), zeigt das Frontend weiter den alten Wert — in dem Fall manuell /admin/cache → "Cache leeren" triggern. Siehe Haeufige Fehler unten.

API-Actions (/api/backend/design)

ActionMethodeZweck
load_lessGETCustom LESS aus DB laden (Fallback: Datei)
save_lessPOSTLESS validieren, in DB speichern, Cache-Rebuild
reset_lessPOSTDefault aus Datei laden, in DB schreiben

Nach jedem Save wird der CSS-Cache via rebuildCssCache() neu generiert, damit die neuen Token-Werte ins Production-Bundle fliessen.

Cache-Integration

Der CSS-Build-Prozess (ueber das cache_settings-Plugin) laedt Custom-LESS aus der DB, falls vorhanden:

php
// cache_compress_css.php (Auszug)
function loadCustomLessFromDatabase() {
    $q = query("SELECT custom_less FROM website LIMIT 1");
    if (num_rows($q) > 0) {
        $row = fetch_assoc($q);
        return $row['custom_less'] ?? '';
    }
    return '';
}

Wenn die DB-Spalte leer ist, faellt der Build auf die Datei _public/src/css/frontend/custom.less zurueck. Das heisst:

  • Fresh-Install: Datei-Tokens sind aktiv
  • Nach erstem Save via /admin/design: DB-Tokens ueberschreiben die Datei-Tokens (Datei bleibt unveraendert)
  • Reset via Admin: lockes DB-Snapshot, Datei wieder als Quelle

Migration 013_add_custom_less_to_website.sql legt die Spalte an.

Komponenten nutzen Tokens

Widgets und Theme-Komponenten referenzieren die Tokens direkt:

less
// Im Widget-Template oder Theme-LESS
.my-widget {
    background: @colorPrimary;
    color: @colorWhite;
    padding: @spacingMedium;
    border-radius: @radiusBase;
    font-family: @fontBody;
    font-size: @fontSizeBase;
}

Oder per CSS-Custom-Property (z. B. fuer dynamische Switches):

css
.my-widget {
    background: var(--color-primary);
    color: var(--color-white);
    padding: var(--spacing-medium);
}

Haeufige Fehler

Breakpoints als CSS-Variable nutzen

@media (max-width: var(--breakpoint-mobile)) funktioniert nicht — Media-Queries akzeptieren keine CSS-Custom-Properties im Selektor. Breakpoints immer als LESS-Variable verwenden: @media (max-width: @breakpointMobile).

Token in custom.less geaendert, Frontend zeigt alten Wert

Cache-Rebuild fehlt. Entweder in Admin-UI nochmal "Speichern" klicken (triggert Rebuild automatisch) oder /admin/cache → "Cache leeren".

Datei-Aenderungen an custom.less werden ignoriert

Sobald einmal in der DB ein Wert steht (website.custom_less != ''), ignoriert der Build die Datei. Entweder "Reset"-Button in /admin/design (laedt Datei-Default zurueck) oder DB-Spalte manuell leeren: UPDATE website SET custom_less = NULL.

LESS-Syntax-Fehler beim Save

Der save_less-Endpoint validiert via Less_Parser. Syntax-Fehler werden mit Zeilennummer zurueckgegeben, Save wird abgelehnt — der alte Wert bleibt aktiv. Fuer komplexe Aenderungen: vorher lokal mit dem LESS-Compiler testen.

AI-generiertes CSS ueberschreibt Tokens

Der AI-CSS-Generator schreibt direkt in custom_css-Felder pro Widget/Row/Column (nicht in die globalen Tokens). Wenn eine AI-Response in Richtung "Set primary color to red" geht, sollte das nicht ueber @colorPrimary: red; im Widget-CSS landen — das ueberschreibt nur lokal. Fuer globale Token-Aenderungen immer den Design-Editor nutzen.

Siehe auch