Communitygithub.com

karero/website-design-system

Zuständig für die visuelle Schicht: Mobilgrafik, Dark Mode und die Theme-Tokens. Stellt das einheitliche Erscheinungsbild der Website sicher.

Was ist website-design-system?

Dieses Skill definiert das visuelle Design-System einer Website. Es verwaltet die CSS-Custom-Properties für Dark Mode, Light Mode und responsive Grafiken. Die Regeln für Bilder (WebP/AVIF via `astro:assets`), die Einhaltung der WCAG-AA-Kontrastwerte für beide Modi und die Behandlung von Tabellen (Stack vs. Figures) sind detailliert spezifiziert. Besonderer Fokus liegt auf der Längenanpassung für übersetzte Texte (z.B. Deutsch kann 20-35% länger sein), damit Layouts bei allen Sprachen stabil bleiben. Es nutzt Komponenten wie `EmailLink.astro` zur E-Mail-Verschleierung und verlangt, dass alle visuellen Änderungen mit den Tests (`images.spec.ts`, `tables.spec.ts`, a11y-Tests) übereinstimmen. Fertig bedeutet: `BRAND.md` ist ausgefüllt und konsistent, Bilder sind optimiert, alle Themes bestehen die Kontrastprüfung, das Layout ist bei 360/768/1280 Pixeln stabil und die Echt-Übersetzungen (nicht Platzhalter) wurden geprüft.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/karero/croftweaver/tree/HEAD/skills/website-design-system

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht website-design-system?

Zuständig für die visuelle Schicht (Aussehen und Performance): Mobilgrafik, Dark Mode und die Theme-Tokens. Erzeugt/pflegt BRAND.md (Vorlage: die templates/brand.md des new-website-Skills) und den Token-Block in der Datei templates/astro/src/styles/global.css dieses Skills. Bildregeln sind unten aufgeführt (WebP/AVIF via Astros astro:assets); der Test images.spec.ts setzt sie durch. Verwende das image-Skill zur Erzeugung von Bild-Assets.

Dark Mode (erstklassig)

  • Tokens, keine hartcodierten Farben. Alle Farben fließen durch CSS-Custom-Properties; Light ist der :root-Standard, Dark überschreibt unter :root[data-theme="dark"], plus ein @media (prefers-color-scheme: dark)-Block für Besucher ohne JavaScript. Das Starterpaket bringt genau diese Struktur mit.
  • No-FOUC-Skript im <head> setzt data-theme aus localStorage.theme oder der Systemeinstellung vor dem ersten Rendern (bereits in Base.astro eingebunden). Der Schalter schreibt localStorage.theme (das Starterpaket enthält keinen; falls du einen hinzufügst, erwähne dies in Abschnitt 3 der Datenschutzseite).
  • Kontrast in beiden Modis: Jedes Text/Hintergrund-Paar erfüllt WCAG AA (4,5:1 für Fließtext, 3:1 für große / UI-Elemente). Eine Farbe, die im Light-Modus funktioniert, versagt oft im Dark-Modus – der a11y-Test durchläuft die gesamte Light+Dark-Matrix, also überprüfe beide.

Mobile & responsive Grafiken

  • Mobile First: Gestaltung ab 360px; Zielgrößen ≥ 44px; kein horizontaler Scroll. Prüfe bei 360 / 768 / 1280 (preview_resize).
  • Moderne Formate: WebP (oder AVIF) statt JPEG/PNG für Fotos.
  • Größe passend zum Anzeigebereich, nicht zur Quelle. Versende niemals ein 2000px-Bild in einen 80px-Slot; erzeuge Breitenvarianten und verwende srcset/sizes (oder <picture>).
  • Keine Layoutverschiebung: Setze explizite width/height-Attribute, damit der Kasten reserviert wird, bevor das Bild geladen wird (schützt CLS/LCP). Astros <Image> setzt sie automatisch; images.spec.ts erfordert die Attribute (ein reines CSS-aspect-ratio erfüllt den Test nicht).
  • Lazy vs. Eager: loading="lazy" unterhalb des Falzes; das LCP/Hero-Bild lädt eager mit fetchpriority="high" (nicht lazy laden).
  • Alt-Text auf jedem Bild (alt="" nur bei rein dekorativen Bildern).
  • Schriften: Selbst gehostete woff2 mit font-display: swap; vorladen nur die 1–2 Schriften, die oberhalb des Falzes verwendet werden. Vermeide Layoutverschiebung durch späte Schriftwechsel.

Textlängen-Responsivität (übersetzte Texte)

  • Übersetzte Texte sind länger. Deutsch (und viele andere Sprachen) ist meist 20–35 % länger als der entsprechende englische Text. Ein Button, Navigationslink oder eine Karte, die auf englischen Platzhaltertext zugeschnitten ist, läuft beim Einsetzen der echten Übersetzung über, bricht unschön um oder wird abgeschnitten.
  • Bevorzuge flexible Breiten. Verwende min-width / Flex / Grid auto/fr für Elemente mit übersetztem Text, keine feste width, die auf den englischen String zugeschnitten ist.
  • Überlauf ≠ Breite: Flexibles Maß verhindert nicht, dass ein einzelnes langes zusammengesetztes Nomen (z. B. „Datenschutzerklärung“) eine schmale Spalte sprengt – dafür braucht es hyphens: auto (korrekt pro Sprache über das lang-Attribut, das Base.astro bereits setzt) plus overflow-wrap: break-word als Fallback; das Starterpakets global.css liefert beides auf dem body. Tabellenzellen schalten die Silbentrennung aus (siehe Tabellen).
  • Verlasse dich nicht nur auf white-space: nowrap + text-overflow: ellipsis für Navigationslinks oder Button-Label – das Abschneiden eines Nav-Links ist in der Regel keine akzeptable UX (der Besucher kann nicht mehr erkennen, wohin es führt). In Ordnung für Inhalte, bei denen Abschneiden ein akzeptierter Kompromiss ist (z. B. eine Tabellenzelle), nicht für Navigation.
  • Prüfe mit echten übersetzten Labels, nicht mit englischen Platzhaltern. Wenn eine Site astro-i18n-setups LanguageSwitcher.astro oder eine mehrsprachige Navigation verwendet, überprüfe das Layout bei 360/768/1280 (preview_resize) mit dem tatsächlichen Text in jeder Sprache – nicht nur mit dem englischen Platzhalter.

Tabellen

Ein Stil für alle Tabellen; eine Seite enthält kein layout-CSS für eine Tabelle. Er lebt im Starterpaket in src/styles/tables.css (nach global.css importiert von Base.astro) und tests/tables.spec.ts prüft ihn. Eine Seite, die vor diesem Abschnitt erstellt wurde, kopiert tables.css hinein, fügt die Importzeile in ihr Layout ein und entfernt zuerst das eigene tabellen-CSS jeder Seite.

Zwei Arten, unterschieden nach dem Inhalt der Zellen:

  • stack (Sätze): eine Tabelle oberhalb von 40rem; darunter stapelt sich jede Zeile, der Zeilenkopf als Titel und jede Zelle unter dem Spaltennamen. Vier Spalten mit Prosa passen nicht auf 320px.
  • figures (kurze Zahlen, class="num" auf einer Zahl-Zelle): bleibt auf dem Handy eine Tabelle und muss in 320px passen. Wenn es nicht mehr passt, mach es zu stack; eine Bildlaufleiste ist nicht die Lösung. stack figures zusammen ergibt das Zahlen-Look mit dem gestapelten Layout.

Auszeichnung, jede Tabelle:

<div class="table-wrap stack" role="region" aria-label="Was die Tabelle zeigt" tabindex="0">
  <table role="table">
    <thead role="rowgroup"><tr role="row">
      <th scope="col" role="columnheader">{cols[0]}</th><th scope="col" role="columnheader">{cols[1]}</th>
    </tr></thead>
    <tbody role="rowgroup">{rows.map((r) => (
      <tr role="row"><th scope="row" role="rowheader">{r.item}</th><td role="cell" data-label={cols[1]}>{r.text}</td></tr>
    ))}</tbody>
  </table>
</div>
  • Schreibe die Spaltennamen einmal in eine Liste und verwende sie für den Header und für jedes data-label: das Label einer gestapelten Zelle muss dem Spalten-Header entsprechen, und der Test vergleicht beide. Eine figures-Tabelle benötigt keine rollenspezifischen Attribute pro Zelle und kein data-label.
  • Eine gestapelte Tabelle hat nicht mehr display: table. Die Rollen sind ein Fallback für Browser, die die Tabelle beim Layoutwechsel fallen lassen; ob sie dort funktionieren, wird nicht geprüft. In Chromium, gemessen an einer echten Tabelle, behält der Accessibility-Baum die Tabelle auch ohne sie.
  • class="tap" bei einem Link, der allein in einer Zelle steht, macht ihn auf dem Handy zu einem 44px-Ziel. nowrap hält einen kurzen Wert („1, 3, 6“) in einer Zeile. long-head (mit stack) verbreitert die erste Spalte, wenn die Zeilenköpfe Sätze sind.
  • Wörter werden in Zellen nicht getrennt. Die hyphens: auto des Body zerlegt eine schmale erste Spalte in Fragmente („An-thropic“), daher setzt der Block dort hyphens: manual.
  • Eine Seite, deren Tabellen von außen kommen und die Auszeichnung nicht tragen können, kommt in TABLE_EXEMPT in der Spezifikation, mit Begründung. PAGES bleibt vollständig: Die Sitemap und die llms.txt-Prüfungen benötigen jede lebende Route darin.

Was tables.spec.ts prüft: Jede Tabelle befindet sich in einem .table-wrap einer Art mit ihrer Region, Label und tabindex, scope="col" auf jeder Header-Zelle und ein <th scope="row"> als erste Zelle jeder Zeile, mit <td> für den Rest; eine gestapelte Tabelle hat ihre Rollen und ein Label, das dem Header auf jeder Zelle entspricht; bei 360 und 320px scrollt weder eine Seite noch eine Tabelle seitwärts; bei 641px und darüber ist eine gestapelte Tabelle wieder eine Tabelle mit ihrer Header-Zeile und kein Wort gebrochen (dies fängt Regeln wie overflow-wrap: anywhere ab, die eine Spalte ein Wort quetschen lassen); keine Zelle hat hyphens: auto. Sie testet auch das CSS an einem Fixture, das sie auf der Startseite platziert, mit aXe in beiden Modi, sodass eine Seite ohne Tabelle dennoch den Block belegt. Headless Chromium trennt nicht, daher liest die Silbentrennungsprüfung den berechneten Style, nicht das Layout. Safari und VoiceOver werden nicht geprüft.

E-Mail-Verschleierung (Adressen vor Crawlern verbergen)

Setze niemals eine Klartext-E-Mail oder mailto:deine@adresse in den HTML-Quelltext – Scraper ernten sie innerhalb von Stunden für Spam. Rendere jede Adresse durch die EmailLink.astro-Komponente (src/components/EmailLink.astro im new-website-Skills templates/astro/, plus ihr lib/obfuscate.ts-Helper): Die Adresse wird zur Build-Zeit umgekehrt + base64-kodiert und im Browser wieder zusammengesetzt, sodass das ausgelieferte HTML keine lesbare Adresse enthält. Besucher ohne JavaScript sehen einen dennoch nutzbaren Hinweis „Name [at] Domain [dot] com“.

<EmailLink address="[email protected]" subject="Projektanfrage" text="Mail an uns" />

Regel: Kein roher mailto:-Link und keine wörtliche @-Adresse im gebauten HTML – website-qa prüft dies. Gleiches Prinzip für jede Telefonnummer, die du nicht geerntet haben möchtest.

Brand-Tokens

Spiegle die Palette von BRAND.md in den Token-Block und halte sie synchron. Definiere: Brand (fest) sowie pro Theme heading/ink/muted/accent/link/line/bg/bg-soft/surface. Das Akzent und die Link-Farbe müssen AA auf dem Hintergrund in beiden Modi erfüllen – daher hat jeder Modus seine eigenen. Das optionale website-brand-kit erledigt das Spiegeln mit einer Prüfung: Seine Aufnahme liest die Tabellen von BRAND.md, hält jeden Textfarbe gegen 4,5:1 auf jedem Hintergrund in beiden Modi und schreibt die Werte in alle drei Farbblöcke von global.css (Light, Dark und den Dark-Block für Besucher ohne JavaScript). Von Hand müssen alle drei Blöcke zusammen geändert werden.

Fertig bedeutet

BRAND.md ausgefüllt und konsistent mit dem Token-Block; Bilder sind WebP, dimensioniert, lazy/eager-korrekt, mit Alt; der a11y-Test (Light+Dark) ist grün; das Layout hält bei 360/768/1280 ohne Verschiebung; jede Tabelle ist stack oder figures und tables.spec.ts ist grün. Performance-Zahlen (FCP/LCP) sind in website-qa verifiziert. Das Layout hält auch bei 360/768/1280 mit echtem (nicht Platzhalter-)Text in jeder ausgelieferten Sprache, nicht nur in der Standard-Locale.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Verwandte Skills