Gemeinsames Designsystem für alle Repositories und Tools der Grünen Österreich. Es stellt konsistente Farben, ein einheitliches Layout und wiederverwendbare UI-Bausteine aus dem grünen Corporate Design bereit, damit alle Grüne-AT-Anwendungen dasselbe Erscheinungsbild teilen.
Das Designsystem wird als statische Site über GitHub Pages gehostet: https://design-system.gruene.at/
Das gehostete Stylesheet lässt sich aus jedem Projekt per <link> einbinden:
<link rel="stylesheet" href="https://design-system.gruene.at/design-system.css">Damit erhalten konsumierende Tools automatisch die zentral gepflegten
Design-Tokens und Komponenten. Die URL ist seit v1.0 stabil und ändert sich
auch in v2.0 nicht — npm, Build-Schritte oder andere Tooling-Aufwände sind
auf der Konsumenten-Seite nicht nötig.
design-system.css setzt bewusst keine Tag-Defaults — es stylt also kein
body, kein h1 und keine anderen HTML-Elemente direkt. Eine konsumierende
Seite muss ihr Grundlayout daher selbst setzen, sonst rendert sie in der
Browser-Standardschrift (serif) und ohne Hintergrund. Das Minimum sind vier
Eigenschaften am body, aufgebaut aus den --gat-*-Tokens:
body {
margin: 0;
background: var(--gat-color-surface);
color: var(--gat-color-text);
font-family: var(--gat-font-copy);
}Ein vollständiges, lauffähiges Minimal-Beispiel für ein konsumierendes Tool liegt unter examples/minimal.html und ist live abrufbar unter https://design-system.gruene.at/examples/minimal.html.
Konsumenten ausserhalb der Grünen Österreich — eine Partei in einem anderen
Land, ein Landesverband mit eigener Akzentfarbe, ein Verein — passen das
Erscheinungsbild über Tokens an, ohne das Stylesheet zu forken oder zu
kopieren: eine eigene lokal.css nach dem Design-System einbinden und darin
rund ein Dutzend Tokens in einem :root-Block überschreiben.
<link rel="stylesheet" href="https://design-system.gruene.at/design-system.css">
<link rel="stylesheet" href="lokal.css">Ein schlichter :root-Block genügt, weil die Defaults in @layer-Regeln
stehen — ungelayerte Deklarationen gewinnen unabhängig von der Reihenfolge.
Komponentenklassen werden dabei nie neu definiert.
- Kopiervorlage mit allen Tokens: examples/lokal.css
- Lauffähiges Beispiel mit anderer Marke: examples/theming.html
- Vollständige Token-Liste, Rollen und Kontrast-Anforderungen: Abschnitt „Für andere Organisationen" im Style Guide
Der wichtigste Punkt dabei: --gat-color-dunkelgruen, --gat-color-magenta
und --gat-web-green-deep tragen weisse Schrift und brauchen mindestens
4,5:1 gegen Weiss. Viele Markenfarben wurden für Logo und Druck gewählt und
fallen durch. --gat-web-green trägt dagegen nirgends Text — es ist Rahmen
und Akzentfläche.
Eine Falle, die der Style-Guide-Abschnitt ausführlich behandelt:
--gat-color-gelb ist die Textfarbe des Hochkontrast-Modus und keine
Schmuckfarbe. Für Diagramme siehe „Chart-Helfer" weiter oben — die
Funktionen palette(), ink() und schrift() folgen den Tokens, die
statischen Exporte PALETTE/INK nicht.
Für ECharts-basierte Datenwerkzeuge liefert das DS ein zusätzliches ES-Modul mit Palette und Helfern:
import {
PALETTE, INK, LABEL_SIZE, AXIS_SIZE,
BAR_MAX_DICHT, BAR_MAX_WEIT,
tip, legende, grid, planIstLegende
} from 'https://design-system.gruene.at/gat-charts.js';Die Palette spiegelt die CSS-Tokens --gat-web-chart-1..8 1:1. ECharts
selbst wird vom Konsumenten unabhängig (eigener CDN-Import) geladen — das
DS bündelt keine fremden Bibliotheken.
Statisch oder zur Laufzeit. Das Modul bietet beides, bewusst getrennt:
| Export | Verhalten |
|---|---|
PALETTE, INK |
statische Werte, identisch zu den DS-Defaults. Lesbar auf Modulebene und ohne DOM (Node-Tests). Kennen kein Theming. |
palette(), ink(), schrift() |
lesen dieselben Werte zur Aufrufzeit aus den CSS-Tokens und folgen damit einer lokalen Überschreibung. Ohne DOM oder ohne geladenes Stylesheet fallen sie auf die statischen Werte zurück. |
Konsumenten der Grünen AT können bei PALETTE/INK bleiben — nichts ändert
sich. Wer das Design-System auf eine andere Marke umstellt (siehe
Für andere Organisationen), nutzt die
Funktionen; sonst bleiben die Diagramme grün, während der Rest der
Oberfläche die neue Marke trägt.
import { palette, ink, schrift } from 'https://design-system.gruene.at/gat-charts.js';
chart.setOption({
color: palette(), // folgt --gat-web-chart-1..8
textStyle: { color: ink().text, fontFamily: schrift() },
});tip() und legende() lesen ebenfalls zur Aufrufzeit — wer sie verwendet,
bekommt das richtige Verhalten ohne Zutun. ink().gridline und ink().axis
bleiben immer statisch, weil es für sie im DS kein Token gibt.
Ab v2.3 liefert das DS eine Such-Vorlage: die .gat-search-CSS-Familie
(Suchfeld + Ergebnis-Overlay) plus ein engine-neutrales Verhaltensmodul
gat-search.js, ausgeliefert wie gat-charts.js von der Pages-URL:
<div class="gat-search">
<input type="search" class="gat-input gat-search__field" id="suche">
<div class="gat-search__overlay" id="suche-overlay" hidden></div>
</div>
<script type="module">
import { createSearch }
from 'https://design-system.gruene.at/gat-search.js';
createSearch({
input: '#suche',
overlay: '#suche-overlay',
// eigener Adapter: irgendeine async-Funktion query -> Treffer
search: async (query, { signal }) => meinIndex.find(query, { signal }),
});
</script>Das Modul übernimmt das generische Verhalten zentral: Open/Close des
Overlays ohne Layout-Shift, Pfeiltasten-Navigation, ARIA
(combobox/listbox/option mit aria-activedescendant),
Enter/Esc, Debounce mit Race-Guard und prefers-reduced-motion. Für die
Modal-/Strg+K-Variante setzt man mode: 'modal' und legt das Feld in
ein <dialog class="gat-modal gat-modal--blur gat-modal--wide"> mit
.gat-search--modal — Focus-Trap und Esc liefert der native <dialog>, das
Modul ergänzt returnFocus auf den Auslöser. Beide Varianten sind im
Style Guide live demonstriert (index.html, Abschnitt Suche).
Rendert ein Konsument seine Treffer in ein eigenes Panel ausserhalb des
DS-Overlays (z. B. weil der Adapter [] zurueckgibt und die App selbst malt),
registriert man dieses Panel via extraContainers, damit Klicks darin die Suche
nicht schliessen:
createSearch({
input: '#suche',
overlay: '#suche-overlay',
extraContainers: ['#mein-ergebnis-panel'], // Elemente und/oder Selektoren
search: async (query, { signal }) => { /* … */ return []; },
});Jeder Treffer folgt dem SearchResult-Slot-Schema:
{ id, title, excerpt?, url, badge?, meta? }XSS-Hinweis: Der Default-Renderer escaped vom Konsumenten gelieferte
title via textContent. excerpt wird als HTML eingesetzt (z. B. für
<mark>-Hervorhebungen) — nur befüllen, wenn der Adapter es selbst escaped
hat.
Die konkrete Such-Engine bleibt Konsumenten-Aufgabe (Framework-agnostisch, kein Vendoring). Ein fertiges Beispiel für Pagefind liegt unter examples/pagefind-adapter.js; es lädt das Pagefind-Bundle des Konsumenten zur Laufzeit und mappt es auf das Slot-Schema. Auf dieser Vorlage bauen die Folge-Adoptionen in den Tool-Repos (werkzeuge#15, Gemeindeordnung#15) auf.
Das Designsystem ist produktiv: Design-Tokens (Farben, Typografie, Abstände,
Radien), UI-Komponenten und ein ausgearbeiteter Style Guide (index.html) sind
vorhanden und einsatzbereit.
Konsumierende Tools verlinken die feste, gehostete CSS-URL und erhalten damit immer den aktuellen Stand — es gibt keine versionierten URLs oder Pfade. Ein Update des Designsystems wirkt automatisch auf alle einbindenden Tools.
Damit dieser stetige Fluss nachvollziehbar bleibt, werden alle nennenswerten Änderungen — insbesondere Breaking Changes — in der CHANGELOG.md dokumentiert. Das Projekt folgt Semantic Versioning: Ein Major-Versionssprung kündigt Breaking Changes an (entfernte oder umbenannte Klassen bzw. Tokens), ein Minor-Sprung neue Komponenten oder Tokens, ein Patch-Sprung reine Wert-Korrekturen ohne Auswirkung auf die Klassen-API.
Ab v2.0 ist das Stylesheet Tailwind-v4-getrieben. Konsumenten merken davon
nichts — die <link>-URL bleibt identisch, die --gat-*-Namen bleiben
stabil. Migrations-Anleitung für Token-Wert- und optische Änderungen siehe
MIGRATION.md.
Das Stylesheet wird aus src/design-system.css per Tailwind-CLI gebaut.
Lokal:
npm install
npm run build # einmal bauen — schreibt design-system.css
# oder
npm run watch # bei Änderungen automatisch neu bauenWer src/ editiert, muss den frisch gebauten design-system.css mit
committen — der CI-Workflow build-check.yml prüft auf jedem PR per
git diff --exit-code design-system.css, dass committed Output und
Source-Build übereinstimmen.
Der Pages-Workflow (.github/workflows/pages.yml) baut auf jedem push
nach main ebenfalls neu, bevor er die Repo-Inhalte hochlädt — die
gehostete URL spiegelt also immer den aktuellen Source-Stand wider.
Barlow Semi Condensed und Vollkorn werden selbst ausgeliefert, aus
assets/fonts/. Konsumierende Seiten binden nur design-system.css ein und
bekommen die Schriften automatisch mit — es ist kein zusätzlicher <link>
nötig und keine Verbindung zu Dritten.
Bis dahin standen die Schriften als @import von fonts.googleapis.com in
der ersten Zeile des Stylesheets. Damit baute jede konsumierende Seite bei
jedem Aufruf eine Verbindung zu Google auf und übertrug die IP-Adresse der
Besucherin dorthin — ohne dass im Quelltext der Konsumenten etwas davon zu
sehen war. Für Werkzeuge, die mit dem Versprechen „alles bleibt auf deinem
Gerät" arbeiten, war das ein Widerspruch (#30).
Das ist kein Vendoring. Die Schriften sind Teil des Corporate Designs und
werden hier zentral gehostet, genau wie assets/gruene-logo.svg. Konsumenten
kopieren weiterhin nichts — sie verlinken eine Adresse.
Ausgeliefert werden die Zeichensätze latin und latin-ext (16 Dateien,
zusammen 376 KB; ein Browser lädt davon je nach Seite zwei bis vier). Die von
Google zusätzlich angebotenen Sätze — kyrillisch, griechisch, vietnamesisch —
entfallen bewusst. Wer sie braucht, ergänzt sie in src/design-system.css.
Der Preis dafür: GitHub Pages liefert mit cache-control: max-age=600, Google
lieferte die Schriften mit einem Jahr. Wiederkehrende Besucherinnen
revalidieren die Schriften also häufiger. Es sind bedingte Anfragen, die mit
304 und null Bytes enden — keine Neu-Downloads —, aber es sind zusätzliche
Rundreisen. Dieselbe Cache-Dauer gilt ohnehin schon für design-system.css
selbst.
Beide Schriften stehen unter der SIL Open Font License 1.1, die das Selbst-Ausliefern ausdrücklich erlaubt. Die Lizenztexte liegen bei: assets/fonts/OFL-Barlow.txt und assets/fonts/OFL-Vollkorn.txt.
Lizenziert unter der Creative Commons Attribution 4.0 International (CC BY 4.0).
Urheber: Die Grünen.