Gestaltungsleitlinien
So setzt du ranui auf einer echten Oberfläche ein: Wähle eine Rolle und einen Zustand, und lass die Tokens die Werte liefern.
Die Regeln selbst stehen an zwei Stellen, und diese Seite verlinkt sie, statt sie zu wiederholen: der
Designleitfaden für die Methode, die für jedes Produkt gilt, und der
ranui-Implementierungsadapter
für ranuis Tokens, Stufen und Komponentenregeln. Beide werden in node_modules/ranui/docs/DESIGN.md ausgeliefert. Das
Designsystem listet jedes Token und seinen Wert, die
Themengestaltung behandelt Überschreibungen zur Laufzeit und die
Informationsarchitektur den Aufbau der Seite.
Einsetzen, wenn du Farbe, Abstand, Schrift, Tiefe oder Bewegung für eine Oberfläche aus
<r-*>-Elementen wählst.
Grundsätze
- Klarheit vor Eigenart. Zuerst müssen die Hauptaufgabe und die Hauptaktion unverkennbar sein.
- Bestehende Steuerelemente wiederverwenden.
r-button,r-input,r-selectundr-modalbringen Formular-, Tastatur- und Barrierefreiheitsverhalten bereits mit; gestalte sie um, statt sie nachzubauen. - Nach Rolle und Zustand entscheiden. „Was ist dieser Text?“ hat eine Antwort; „welche Größe sieht richtig aus?“ hat keine. Das Token der Rolle liefert den Wert, und er folgt dem Theme.
- Entwirf jeden erreichbaren Zustand und sieh dir das Ergebnis an. Der Normalzustand ist einer von acht, und einen Schatten, den niemand sieht, bemerkt man erst im Browser.
Das sind Ausgangspunkte. Weiche von einem ab, wenn die Oberfläche dadurch besser wird, und sag, warum.
Eine Farbe wählen
Die Leiter legt bereits fest, wie Überfahren und Gedrücktsein aussehen; deine Aufgabe ist es, die Rolle zu benennen.
| Das Element ist… | Nimm |
|---|---|
| Der Hintergrund einer Seite oder Fläche | --ran-color-bg / -bg-subtle / -bg-elevated / -bg-muted |
| Unter dem Zeiger / wird gedrückt | --ran-color-bg-hover / -bg-active |
| Text | --ran-color-text / -text-secondary / -text-disabled |
| Ein Rahmen | --ran-color-border / -hover / -active |
| Die eine Aktion, für die es die Seite gibt | --ran-color-primary (darauf --ran-color-primary-text) |
| Ein Status | --ran-color-success / -warning / -danger |
| Ein Link | --ran-color-link |
Jede Akzentfarbe hat genau eine Bedeutung. Primär ist einfarbig, also bleibt Blau für Links und den Fokusring; Grün ist Erfolg, Bernstein Warnung, Rot Gefahr. Wer Rot zur Betonung nutzt, hat später nichts mehr, um „Gefahr“ zu sagen.
Ein roher Hex-Wert, ein Fallback, der nicht mit dem Theme wechselt, oder ein Fallback, der ein nicht
existierendes Token nennt, bricht im Dunkelmodus still oder verwirft die ganze Deklaration; die
Farbregeln des Adapters
erklären jeden Fall, und verify:design findet sie in ranuis eigenem Quellcode.
Abstand und Rhythmus
Nimm Abstände aus der 4px-Skala und lass die Entfernung Bedeutung tragen:
- 8px zwischen Elementen innerhalb einer Gruppe.
- 16px zwischen Gruppen.
- 24–32px zwischen Bereichen.
Ein kleinerer Abstand bedeutet eine engere Beziehung, also bricht schon ein einziger Abstand außerhalb der Skala den Rhythmus. Gib jedem Abstand genau einen Verantwortlichen: Zähl den Margin des Kindes und das Padding des Elternelements, bevor du einen dritten Abstand dazwischen setzt.
Schrift wählen
Frag, welche Rolle der Text spielt (Überschrift, Beschriftung, Fließtext, Schaltfläche, dicktengleich); Schriftart, Größe, Stärke und Zeilenhöhe ergeben sich aus der Schriftskala. Wirklich einmaliger Text, etwa eine Gesteneinblendung auf einem Video, fährt mit einem eigenen Komponenten-Token besser, als in die nächstliegende Rolle gezwängt zu werden.
Tiefe: Schatten und Stapelung
Wähle die Schattenstufe danach, was das Element ist: eine Fläche im Fluss, ein schwebendes Overlay oder ein blockierender Dialog. Ein Overlay, das auf die Kartenstufe zurückfällt, wirkt wie an die Seite geheftet.
ranui-Overlays in dein eigenes Rahmenwerk einbetten. Die z-index-Leiter
beginnt bei 1000, also überragt ein portaltes Overlay gewöhnliches Seitenrahmenwerk von selbst. Ein Overlay mit position: fixed,
das in seinem eigenen Shadow DOM bleibt (der Dialog von r-modal), entkommt nur bis zu seinem nächsten übergeordneten
Stapelkontext. Wenn du eingebetteten Inhalt in etwas einwickelst, das einen erzeugt
(isolation, opacity < 1, transform, filter, will-change), heb diese Hülle nur an, solange ein
Overlay tatsächlich offen ist:
.embed {
isolation: isolate; /* cheap: no z-index of its own, so nothing is promoted */
}
/* Escalate only while a real overlay is open — never "just in case" */
.embed:has(r-modal[open]),
.embed:has(r-modal[closing]) {
position: relative;
z-index: 100;
}Ein dauerhafter z-index auf der Hülle hebt alles darin, statischen Inhalt eingeschlossen, über deine
fixierte Kopfzeile, und zwar während des gesamten Scrollens; so wurde diese Seite einmal ausgeliefert. Berücksichtige closing ebenso
wie open: Die Maske wird während ihres Schließübergangs weiter gezeichnet.
Bewegung
Häufiges Feedback (Überfahren, Fokus, Drücken) erfolgt sofort. Wenn Bewegung eine Änderung erklärt, bleibt Rückmeldung
bei 0–100ms, Einblenden dauert 250–400ms und bremst ab, Ausblenden dauert 150–200ms und beschleunigt.
Halte sie unterbrechbar und beachte prefers-reduced-motion.
Lass niemals eine Farbeigenschaft animieren. CSS kann nicht wissen, warum sich eine Farbe geändert hat, also feuert eine transition
auf background-color, color, border-color, box-shadow, fill oder stroke auch beim Wechsel des
Themes: Jedes Element blendet in seinem eigenen Tempo über, während die Seite längst umgeschaltet hat. Animiere
stattdessen transform und opacity. Auch transition: all und ein nacktes transition: 0.2s schließen Farbe ein.
Zustände und Texte
Jeder erreichbare Zustand gehört zum Entwurf: Überfahren, Gedrückt, Fokus, Deaktiviert, Ladend, Leer, Fehler.
Überfahren entspricht bg-hover / border-hover, Gedrückt bg-active, Fokus dem Fokusring. Nichts, was man nicht
anklicken kann, darf anklickbar aussehen: r-card reagiert nur mit hoverable auf das Überfahren.
Auch Texte gehören zum System:
- Schaltflächen benennen das Ergebnis, mit dem Objekt, wenn der Kontext es nicht liefert: „Mitglied löschen“. Ein eindeutig benannter Dialog darf „Löschen“ sagen; vermeide ein allgemeines „OK“.
- Fehler sagen, was passiert ist, und dann, wie man es behebt. ✅ „Bauen fehlgeschlagen: Das Bündel überschreitet die Größengrenze. Verkleinere es oder erhöhe die Grenze.“ ❌ „Vorgang fehlgeschlagen, bitte erneut versuchen.“
- Bestätigungen nennen die Änderung, nicht den Erfolg, und erscheinen erst, wenn sie bestätigt ist. ✅ „Projekt gelöscht“ ❌ „Vorgang erfolgreich“.
- Lass den Zusammenhang das Überflüssige wegnehmen: Ein Dialog mit dem Titel „Projekt löschen“ braucht keine Schaltfläche „Projekt endgültig und für immer löschen“.
Barrierefreiheit
- Erfülle den Kontrast nach WCAG AA für Text gegen seinen Hintergrund.
- Signalisiere einen Zustand nie allein über Farbe: Verbinde sie mit einem Symbol, einer Beschriftung oder Text.
- Jedes interaktive Element behält einen sichtbaren Fokusring (
--ran-focus-ring, oderoutline: 2px solid var(--ran-color-focus); outline-offset: 2px). - Alles ist mit der Tastatur erreichbar.
- Achte auf
prefers-reduced-motionundprefers-color-scheme.
Maus und Finger, schmal und breit
Weder die Eingabeart noch die Fenstergröße ist das zweitrangige Ziel.
- Ziehen, Schieberegler und Gesten nutzen Pointer Events, mit
touch-action: nonegenau auf der Ziehfläche.touch-action: noneohne Zeiger-Handler dahinter ist ein kaputtes Steuerelement. - Was nur beim Überfahren erscheint, braucht eine Tipp-Alternative.
trigger="hover"anr-selectoderr-popoverwird auf Touch-Geräten zum Klick; alles, was du selbst baust, sollte es genauso machen. - Bevorzuge viewportbezogene Größen (
min(560px, calc(100vw - 32px)),clamp()), statt einen Breakpoint zu erfinden: ranui hat kein Breakpoint-Token, also ist jeder feste Breakpoint eine Zahl, die jemand pflegen muss. - Verstecke auf Mobilgeräten nie den einzigen Weg, etwas zu tun. Ordne stattdessen um.
- Eine gemessene Position stimmt nur bis zum nächsten Reflow. Alles, was aus
getBoundingClientRect()abgeleitet ist, veraltet beim Ändern der Fenstergröße, beim Reflow des Containers und, bei einem portalten Panel, beim Scrollen. Bei schmaler Breite zu laden testet nicht das Verkleinern auf diese Breite, und genau dort bricht es.
Was die Bibliothek maschinell durchsetzt
pnpm -F ranui verify:design prüft neun Regeln in ranuis eigenem Quellcode: Farb-Fallbacks, die nicht
mit dem Theme wechseln, rohe Farbliterale, die Abstands- und Größenskalen, reine Maus-Ziehvorgänge, :host-Regeln, die
hidden aushebeln, Fallbacks mit nicht deklarierten Tokens, Komponenten, die ihren eigenen Shadow-Baum durchsuchen, und Shadow-Bäume,
die außerhalb des Konstruktors gebaut werden. Eine Zeile, die eine Regel absichtlich bricht, sagt das mit
design-ok: <rule> <reason>. Die Prüfungen decken nur die konfigurierten Quellverzeichnisse ab; eine Anwendung, die
ranui nutzt, führt ihre eigenen Prüfungen aus und sieht sich ihre eigenen Seiten an.
Gestaltungsbeispiele
Schematische Darstellungen aus ranui-Basistokens, keine echten Komponenten.
Zeilen ausrichten
Auch wenn eine Zeile zusätzlichen Inhalt erhält, bleiben Textbeginn und Aktionsspalte an den anderen Zeilen ausgerichtet.
Verschachtelte Rundungen abstimmen
Sind beide Begrenzungen nötig, den Einzug vom Außenradius abziehen: 16 − 4 = 12. Die Kurven haben denselben Mittelpunkt und einen gleichmäßigen Abstand.
--ran-radius-lg − --ran-space-1 = --ran-radius-mdKleine Symbole leichter anklickbar machen
Das Symbol ist 16px groß, seine Klickfläche wird für leichtere Bedienung auf 32px erweitert. Die Größe auf Maus- oder Touch-Eingabe abstimmen und benachbarte Flächen getrennt halten.
--ran-size-1 · --ran-size-7Nachweise und Abnahme
Der Abschnitt eine Änderung prüfen des Leitfadens sagt, was in einem echten Browser zu prüfen und was zu berichten ist: was du beobachtet hast, was du nur gefolgert hast und was du nicht prüfen konntest. Die Prüfung durch einen Agenten ist keine Abnahme durch den Nutzer.