Architecture Decision Record · 0005

SOLCOM Bubble Card: SVG-Notch mit JS-getriebener Pille-Width-Anpassung

TL;DR — Der SVG-Notch der Bubble Card wird per ResizeObserver-Drupal-Behavior zur Layout-Time auf die tatsächliche Pille-Width abgestimmt; SSR liefert einen plausiblen statischen Fallback.

Kontext

Figma 4.3 (profile-2-2, Node 691:14029 aus File CHHDfbpX8Ys2LBiGs5HVK0) zeigt eine Bubble Card mit einem S-förmigen Notch unten-rechts, in dem eine CTA-Pille sitzt. Die Notch-Geometrie selbst ist Figma-fest: 28-px-Radius S-Curve aus zwei verbundenen Quarter-Circles, 56-px-Step-Down, 36-px-Outer-Corner-Radius. Variabel ist nur die horizontale Position der S-Curve — sie muss bündig mit dem linken Rand der Pille (+4 px Tuck-Under) abschließen.

Constraints aus dem Design

  1. Card-Width skaliert auf 100 % des Containers (Container-fluid-Layout).
  2. Card-Height ist content-driven (kein min-height, keine fixe Höhe).
  3. Pille-Width ist content-driven — der Site-Builder pflegt das Button-Label in einem Drupal-Canvas-Slot; mögliche Texte reichen von „OK" bis „Mehr Informationen anfragen".

Initial-Implementierung war ein einzelner SVG-<path> mit hardcoded viewBox aus den Figma-Maßen (544×581) plus preserveAspectRatio="none". Das streckt den Path proportional zur Card-Width — Notch und S-Curve werden bei breiten Cards horizontal verzerrt, und die S-Curve sitzt bei festem prozentualem Offset, nicht an der Pille.

Entscheidung

Single SVG-Path im SDC, zur Layout-Time refined durch Drupal-Behavior mit ResizeObserver. Konkret:

Reversibel: wenn der Look doch nicht passt, byte_theme/bubble-card-notch aus byte_theme.libraries.yml entfernen und das JS-File löschen — Cards rendern wieder mit dem statischen Figma-Path im Twig.

Rejected alternatives

Twig-Prop button_width (Site-Builder pflegt Notch-Width manuell) rejected

Pure server-side, kein JS, predictable. Funktioniert aber nur bei fester Card-Width — der Path-Generator braucht absolute Maße. Kollidiert frontal mit der 100-%-Width-Anforderung.

3-Layer-DOM mit Flexbox-Sized Notch rejected

Pure CSS, content-driven via flex-shrink: 0, runtime-dynamic ohne JS. Vier blockierende Implementierungs-Issues: (1) Border-Gradient-Continuity über vier Sub-Elemente, (2) border-image macht Corners square, (3) würde den Slot-Wrapper-Selektor für Drupal-Canvas Edit-Mode brechen, (4) Geometrie ist asymmetrisch. Realistisch 2–3 h Aufwand statt der initialen 1-h-Schätzung.

CSS-only mit Pille-Halo-Pseudo-Element (::before) rejected

Pure CSS, kein JS, content-driven. Visuell aber NICHT der Figma-S-Curve — die Halo-Form ist eine Pille-mit-Rim, kein Step-Down mit S-Curve-Übergang. Brand-Drift-Risiko.

CSS Houdini Paint API rejected

Technisch elegant, content-driven via CSS-Variablen. Browser-Baseline disqualifiziert (Chromium-only, kein Safari, kein Firefox).

<path style="d: path('M ...')"> mit CSS-Variablen rejected

Das d-CSS-Property mit dynamischer path()-Funktion ist in Safari < 16 nicht supported, fehlende SVG-2-Adoption macht das fragil. Außerdem können CSS-Variablen nicht direkt in der path()-Funktion interpoliert werden.

Sub-SVG-Composition im Bottom-Frame rejected

Kombiniert die Probleme aus 3-Layer-DOM (Border-Continuity über Segmente) mit der CSS-Variable-Restriction für SVG-Path-d. Kein Vorteil gegenüber der JS-Lösung.

Consequences

FAQ

Was passiert, wenn JavaScript deaktiviert ist?
Cards rendern mit dem statischen Figma-Original-Path (SSR-Default) — Notch sitzt nicht pixel-perfekt an der Pille, aber die Card ist voll funktional. Bewusster Graceful-Degradation-Trade-off.
Wie wird ein Figma-Update der Geometrie eingespielt?
Geometrie-Konstanten in bubble-card-notch.js UND den SSR-Default-Path in bubble-card-frame.twig parallel aktualisieren. Beide Stellen sind im Code kommentiert.