Was macht Oberflächen?
Dieser Skill legt fest, woraus jedes Element besteht: seine Füllung, Kante, Schatten, Radien, Zustände und Symbole. Er wählt aus einer kurzen Liste von Rezepten, sodass zwei Bildschirme niemals zwei unterschiedliche Karten enthalten.
Vor jeder Entscheidung wende product-ui §1 (das Geschmacksjournal und die Rangfolge) und §5 (welcher Skill was besitzt) an.
Entscheide in dieser Reihenfolge
- Wird eine Oberfläche benötigt? Entfernen, bevor du hinzufügst. Eine Überschrift mit ausreichendem Abstand drumherum braucht keine Karte. Verschachtele niemals eine Karte in einer Karte. Warum: Jeder Behälter fügt eine Kante hinzu, die das Auge lesen muss.
- Welche Ebene? Seite, angehoben, schwebend oder Overlay. Eine Ebene pro Element, ausgewählt nach seiner Funktion, nicht danach, wie sehr es hervorstechen soll. elevation.md.
- Was zeichnet die Kante? Erhöhung bekommt einen Schattenring. Struktur bekommt einen Rahmen. Niemals beides an einer Kante. elevation.md.
- Welcher Radius? Nimm das Token für die Rolle des Elements, dann mache verschachtelte Radien konzentrisch. elevation.md.
- Welche Zustände? Gestalte Hover, Pressed, Selected, Disabled und Focus-visible als Änderungen der Oberfläche, bevor du den Standardzustand polierst. states-and-icons.md.
- Welche Symbolbehandlung? Ein Satz,
currentColor, Strichstärke passend zum Text. states-and-icons.md. - Ist ein Material erlaubt? Nur schwebendes Chrome über scrollendem Inhalt. materials-and-edges.md.
- Kanten des Scrollbereichs. Trennlinien, Ausblendungen, Überscrollen. materials-and-edges.md.
Die vier Ebenen
| Ebene | Verwendung | Hell | Dunkel |
|---|---|---|---|
| Seite | Der Grund | Grundfüllung, kein Schatten | Dunkelste Füllung, kein Schatten |
| Angehoben | Karten, Steuerelemente, die ausgewählte Option | Weiß, Ring + 1px Schlagschatten + 3px enger Schlagschatten | Eine Stufe heller, weißer Ring, enger schwarzer Schlagschatten |
| Schweben | Menüs, Popover, Tooltips, Toasts | Weiß, Ring + 1px Schlagschatten + 4px enger Schlagschatten | Zwei Stufen heller, weißer Ring, enger schwarzer Schlagschatten |
| Overlay | Dialoge, Sheets, Befehlspalette (mit einer Verdunkelung) | Weiß, Ring + 1px Schlagschatten + 6px enger Schlagschatten | Drei Stufen heller, weißer Ring, enger schwarzer Schlagschatten |
Die genauen Token findest du in elevation.md. Die Regeln dahinter:
- Ein Ring plus ein enger Schlagschatten. Weichzeichnung ≤ 8px, Versatz ≤ 6px, Schlagschatten mit negativer Streuung. Warum: Große weiche Weichzeichnungen wirken wie Leuchten, machen die Seite matschig und sehen generiert aus.
- Der Dunkelmodus steigt, indem er heller wird. Schatten sind im Dunkeln kaum sichtbar, daher trägt die Helligkeit die Höhe, und ein weißer Ring mit niedrigem Alpha-Wert trägt die Kante.
- Schatten sind durchscheinend und einfarbig. Undurchsichtige Grautöne hinterlassen einen Hof. Dunkle Schlagschatten bleiben schwarz.
- Geschwister teilen sich eine Ebene. Karten in einer Reihe haben einen Schatten, einen Radius, einen Innenabstand.
- Hover ändert die Füllung, nicht den Schatten.
Regeln, die keine Referenz benötigen
- Rahmen zeigen Struktur, Schatten zeigen Erhöhung. Trennlinien, Eingabefelder, Tabellenzellen und ausgewählte Zustände behalten Rahmen. Eine Karte, deren Rahmen nur dazu da ist, sie anzuheben, bekommt stattdessen einen Ring.
- Behalte
border: 1px solid transparentunter einem Schattenring. Warum: Der Farbzwangsmodus entfernt Schatten, und der Rahmen zeichnet trotzdem eine Kante. - Bilder bekommen eine 1px innere Umrandung:
outline: 1px solidschwarz mit 10% (weiß mit 10% im Dunkelmodus),outline-offset: -1px. Niemals eine getönte Farbe, die wie ein Rand wirkt. Überspringe Logos und transparente Grafiken. - Konzentrischer Radius. Außen = Innen + Innenabstand (+ Rahmen), bis zu 24px Innenabstand. Darüber hinaus sind es separate Oberflächen.
- Fokus ist ein Ring, niemals nichts.
:focus-visiblezeigt eine 2px breite Akzentumrandung mit 2px Abstand; Eingabefelder nehmen sie bündig, als 2px breite Akzentkante ohne Lücke.outline: noneohne Ersatz ist ein Fehler. Der Ring nimmt keinen Layoutplatz ein. - Deaktivierte Steuerelemente reagieren nicht auf Hover, Drücken oder Skalierung.
- Symbole: ein Satz pro Oberfläche,
currentColor, standardmäßig Umriss und gefüllt, wenn aktiv. Die Strichstärke folgt dem Gewicht des benachbarten Textes, 1,5px bei 400 bis zu 2px bei 600. - Weichzeichner im Hintergrund nur bei schwebendem Chrome. Niemals auf Inhalten, Karten oder Tabellen.
- Scrollbare Overlays (Dialoge, Schubladen, Menüs) erhalten
overscroll-behavior: contain.
Paare
| Fehlerhaft | Richtig | Warum |
|---|---|---|
border: 1px solid #e5e5e5 auf einer Karte | box-shadow: var(--elev-raised); border: 1px solid transparent | Ein reiner Tiefenrahmen wird zu einem Ring; der Farbzwangsmodus zeichnet trotzdem eine Kante |
box-shadow: 0 10px 40px rgba(0,0,0,.2) | 0 0 0 1px a.08, 0 1px 2px a.12, 0 4px 8px -4px a.16 | Eng und klar schlägt groß und weich |
Dunkle Karte mit 0 8px 24px #000 | Hellere Füllung plus 0 0 0 1px oklch(1 0 0 / .08) | Schatten verschwinden auf Dunkel; Helligkeit zeigt Höhe |
| Kartenradius 8, innerer Bildradius 8, Innenabstand 8 | Innen 8, außen 16 | Konzentrische Ecken sorgen für einen gleichmäßigen Abstand |
<img> verschmilzt mit einer weißen Karte | outline: 1px solid oklch(0 0 0 / .1); outline-offset: -1px | Die Kante ist lesbar, ohne einen Rahmen |
button:focus { outline: none } | button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px } | Tastaturnutzer behalten ihre Position |
| 1,5px Symbolstrich neben einer 600er-Schrift | 2px Strich | Die Strichstärke entspricht der Stammstärke |
| Gefüllte Symbole in jedem Symbolleistenplatz | Standardmäßig Umriss, gefüllt für das aktive | Füllung ist das Zustandssignal |
backdrop-filter: blur(20px) auf einer Karte | Eine undurchsichtige Oberfläche | Weichzeichnung gehört zu Chrome, das über scrollendem Inhalt schwebt |
Bevor du fertig bist
| Muster | Behebung |
|---|---|
box-shadow mit Weichzeichnung > 8px oder Alpha > .2 auf heller UI | Verwende ein Ebenen-Token |
border plus box-shadow, die die gleiche Aufgabe erfüllen | Nur Ring plus transparenter Rahmen |
Schattenring ohne border: 1px solid transparent | Füge es hinzu |
Gleicher border-radius auf einem Eltern- und seinem gepolsterten Kind | inner + padding für das Elternelement |
outline: none oder outline: 0 ohne :focus-visible Ersatz | Füge den Ring hinzu |
:focus (nicht :focus-visible) gestaltet einen Ring | Wechsle zu :focus-visible |
border-width ändert sich in einem Zustand | Farbe, Füllung oder ein transparenter Rahmen gleicher Breite |
Hartcodiertes fill="#…" oder stroke="#…" in einem Symbol | currentColor |
| Zwei importierte Symbolbibliotheken auf einem Bildschirm | Eine |
backdrop-filter außerhalb einer fixierten Leiste, Seitenleiste oder eines schwebenden Menüs | Entferne es |
Overlay-Liste ohne overscroll-behavior: contain | Füge es hinzu |
Harter Schnitt am Rand eines Scrollers oder ein durch overflow: hidden abgeschnittener Schatten | Blende die Kante aus; polstere den Scroller |
Überprüfe durch Darstellung in Hell und Dunkel bei 2× und beschneide eine Kante jeder Ebene. Fahre mit der Maus darüber, drücke, tabbe zum Fokus, wähle aus und deaktiviere jedes Steuerelement und vergleiche die Kastengröße vorher und nachher. Schalte den Farbzwangsmodus um (Chrome DevTools, Rendering-Emulation) und bestätige, dass jede Karte noch eine Kante hat.