Ein eingeblendetes Aktionsfeld oder eine Popover-Schaltflächengruppe ist ein nützliches Muster, mit dem Nutzer auf zusätzliche Funktionen zugreifen können, ohne dass viel Platz benötigt wird. Dieses Overlay-Muster ist mit einer gewissen Layoutkomplexität verbunden, da das Steuerfeld an ein Triggerelement gebunden bleiben muss, während es sich an die Einschränkungen des Darstellungsbereichs anpasst. Bisher waren dafür komplexe JavaScript-Bibliotheken (wie Popper.js oder Floating UI) erforderlich, um Positionen zu berechnen und Kollisionen zu verarbeiten.
Die CSS-Ankerpositionierung bietet eine deklarative, leistungsoptimierte Möglichkeit, diese Beziehungen vollständig in CSS zu verarbeiten. So können Browser die Positionierungs- und Überlauflogik nativ verwalten.
1. Beziehung zwischen Schaltfläche und Steuerfeld definieren
Im ersten Schritt erstellen Sie einen Trigger-Button, der den Overlay-Container mithilfe der Popover API öffnet.
OBLIGATORISCHE Unterscheidung der Barrierefreiheit im Internet: Dieses Muster modelliert explizit eine Schaltflächengruppe, die in einem Popover angezeigt wird, und kein echtes ARIA-Menü. Wende role="menu" oder role="menuitem" nur an, wenn du den entsprechenden Vertrag für die Tastaturnavigation vollständig implementierst (z. B. die räumliche Navigation mit den Pfeiltasten zwischen Elementen). Fügen Sie dem Trigger aus demselben Grund nicht aria-haspopup hinzu. Der Wert (menu, listbox, tree, grid oder das Legacy-true) ist ein Versprechen, dass das Ziel eine übereinstimmende Rolle verfügbar macht, was bei diesem Muster nicht der Fall ist.
<button popovertarget="action-panel">
Open Actions
</button>
<!-- Use the Popover API (`popover="auto"`) for the overlay to ensure it is placed in the top layer and handled accessibly by the browser. -->
<div id="action-panel" popover="auto" class="panel">
<button class="action-item" type="button">Edit</button>
</div>
Dadurch wird eine implizite Ankerverknüpfung zwischen der Schaltfläche und dem Steuerfeld erstellt, sodass das Steuerfeld nativ relativ zur Schaltfläche positioniert werden kann, ohne dass anchor-name für die Schaltfläche oder position-anchor für das Steuerfeld erforderlich ist.
2. Positionierung mit position-area
Anstatt manuelle top/left-Offsets zu verwenden, können Sie mit position-area das Ziel in einem 3x3-Raster relativ zum Anker platzieren.
.panel {
/*
Position the panel below the anchor (block-end),
aligned to the start of the anchor and spanning to its end (span-inline-end).
*/
position-area: block-end span-inline-end;
/* Reset insets to allow the grid to take control */
inset: auto;
}
Verwenden Sie logische Keywords (span-inline-end, block-start) anstelle von physischen (left, top), um RTL und verschiedene Schreibmodi automatisch zu unterstützen.
OBLIGATORISCH: Mischen Sie keine physischen und logischen Schlüsselwörter in position-area.
3. Edge-Resilienz (Fallbacks) implementieren
Damit das Steuerfeld nicht am Bildschirmrand abgeschnitten wird, können Sie „Ausweichstrategien“ definieren, die der Browser versuchen soll, wenn die Standardposition überläuft.
.panel {
/*
If the panel overflows the bottom, flip it to the top (flip-block).
If it overflows the inline edges, flip it horizontally (flip-inline).
If it overflows both (e.g., in a corner), flip on both axes (flip-block flip-inline).
*/
position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;
}
Wenn Ihr Drop-down- oder Flyout-Menü einen Richtungspfeil oder einen Rahmen enthält, dessen Stil sich je nach gewählter Fallback-Position ändern muss, lesen Sie den Abschnitt Positionsabhängige Kurzinfos. Informationen zum deklarativen Aufruf von Dialogfeldern und Popovers ohne JavaScript finden Sie unter Deklarative Dialogfeld- und Popover-Steuerung.
Fallback-Strategien
Fallbacks und Browserunterstützung für Popover
Die Popover API ist größtenteils eine progressive Verbesserung, aber ihre definierenden Verhaltensweisen – die Hochstufung auf die oberste Ebene, das Schließen durch Klicken außerhalb des Popovers und der Aufruf von popovertarget – haben kein CSS-Äquivalent. Ältere Browser benötigen ein Polyfill oder ein manuelles Fallback, wenn Sie kein Polyfill bereitstellen möchten.
Polyfill: Damit das Attribut popover in älteren Browsern unterstützt wird, lade @oddbird/popover-polyfill bedingt. OBLIGATORISCH: Prüfe, ob die Funktion unterstützt wird, indem du nach der Property popover in HTMLElement.prototype suchst, und lade das Polyfill nur, wenn die native Unterstützung fehlt. Lade es NICHT bedingungslos.
Mit einem Bundler oder einer Importzuordnung:
// MANDATORY: Feature detect 'popover' on HTMLElement.prototype.
if (!("popover" in HTMLElement.prototype)) {
import("@oddbird/popover-polyfill");
}
Ohne Bundler importieren Sie aus einem CDN in einem <script type="module">:
<script type="module">
if (!("popover" in HTMLElement.prototype)) {
import("https://unpkg.com/@oddbird/popover-polyfill@latest/dist/popover.min.js");
}
</script>
Einschränkung beim Styling: Das Polyfill kann die echte Pseudoklasse :popover-open nicht definieren, daher wird stattdessen die Klasse .\:popover-open angewendet. OBLIGATORISCH: Kombinieren Sie die beiden mit :is() oder :where(). Andernfalls verwerfen Browser, die :popover-open nicht unterstützen, die gesamte Regel:
[popover]:is(:popover-open, .\:popover-open) {
display: block;
}
Alternativ können Sie für einen Legacy-Fallback ohne Polyfill position: fixed verwenden und die Koordinaten manuell über getBoundingClientRect() berechnen oder die Standardpositionierung mit inset: auto verwenden, wenn das für den Anwendungsfall akzeptabel ist.
Damit Browser ohne Ankerpositionierung unterstützt werden, müssen Sie eine angemessene Position festlegen. Standardmäßig werden Pop-over in der Mitte des Bildschirms angezeigt, was für Ihren Anwendungsfall möglicherweise geeignet ist.
Für einige Anwendungsfälle können Sie das @oddbird/css-anchor-positioning-Polyfill verwenden, das Unterstützung für einige Anwendungsfälle der Ankerpositionierung bietet. Implizite Anker werden nicht unterstützt. Sie MÜSSEN dem Trigger also Ankernamen hinzufügen. Außerdem wird position-area vom Polyfill nicht für Popovers unterstützt. Sie MÜSSEN also anchor() für die gewünschten Insets verwenden.
<!-- MANDATORY: Conditionally install the anchor positioning polyfill -->
<script type="module">
if (!("anchorName" in document.documentElement.style)) {
await import("https://unpkg.com/@oddbird/css-anchor-positioning");
}
</script>
.panel {
/* Mandatory: use explicit anchor name */
position-anchor: --kebab-anchor;
/* Mandatory: use insets rather than position-area for positioning */
bottom: auto;
right: auto;
top: anchor(bottom);
left: anchor(left);
margin: 0;
}