Mit der CSS-Property appearance: base-select können Sie ein <select>-Element und die zugehörige Auswahl (über ::picker(select)) wie normale HTML-Elemente gestalten.
In Kombination mit modernen CSS-Layouttechniken wie Grid oder Flexbox können Sie sich von der herkömmlichen vertikalen Liste lösen und ohne benutzerdefiniertes JS eine ansprechende visuelle Darstellung erstellen.
Sie können beispielsweise display: grid verwenden, um die Optionen als 2D-Raster von Karten zu formatieren.
Das ist ideal für Farbauswahl, Emoji-Auswahl oder Produktvarianten, bei denen ein visuelles Menü effektiver ist als eine Liste.
Implementierung
1. Basisstil aktivieren
Wenden Sie appearance: base-select sowohl auf das <select>-Element als auch auf das interne Pseudoelement select::picker(select) für die Auswahl an:
select.grid-picker {
&, &::picker(select) {
appearance: base-select;
}
}
2. Auswahlcontainer gestalten
Legen Sie das Ziel select:open::picker(select) fest und wenden Sie display: grid (oder display: flex) an. Definieren Sie Spalten und Abstände wie für jeden anderen Container.
select.grid-picker:open::picker(select) {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
WICHTIG: Der :open ist erforderlich. Wenn Sie select::picker(select) formatieren, wird die Auswahl auch dann angezeigt, wenn das Auswahlfeld geschlossen ist.
3. Optionen gestalten
Richten Sie die <option>-Elemente so aus, dass sie als Rasterelemente oder Karten formatiert werden.
Sie können Bilder, SVGs oder komplexe Layouts darin einfügen.
/* Style options as grid cards */
.grid-picker option {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
/* padding, border-radius, background, etc. */
}
4. Ausgewählte Option formatieren
Verwenden Sie option:checked, um die ausgewählte Option zu formatieren. Beispiel:
.grid-picker option:checked {
position: relative;
border: 2px solid var(--primary-color);
background-color: oklab(from var(--primary-color) l a b / 8%);
}
Wie bei jedem UI-Steuerelement sollten Sie den Status nicht nur über die Farbe kommunizieren, sondern mehrere visuelle Indikatoren (z.B. Farben, Rahmenstärke, Häkchen) verwenden, um zu zeigen, welche Option ausgewählt ist.
5. Optional: Häkchen für die ausgewählte Option formatieren
Standardmäßig rendert der Browser ein Häkchen als erstes untergeordnetes Element jedes <option>-Elements.
Es verhält sich wie ein ::before mit content: "✓" / "", das vor einem vom Autor bereitgestellten ::before gerendert wird, falls vorhanden.
Wenn die Option nicht ausgewählt ist, wird das Häkchen über visibility: hidden ausgeblendet.
Sie können es mit dem Pseudoelement ::checkmark formatieren oder ganz ausblenden, wenn Sie die Auswahl nur über die Formatierung vermitteln oder eine benutzerdefinierte Anzeige verwenden möchten.
Wenn Sie es beispielsweise in der oberen rechten Ecke der Option platzieren möchten, können Sie Folgendes tun:
select.grid-picker {
> option::checkmark {
/* Hide the checkmark for unselected options */
display: none;
}
> option:checked {
position: relative;
&::checkmark {
position: absolute;
inset-block-start: -.4em;
inset-inline-end: -.5em;
display: flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
min-inline-size: 1.6em;
aspect-ratio: 1;
padding-right: 0.12em;
padding-left: 0.05em;
border-radius: 50%;
background: var(--primary-color);
color: white;
font-size: 70%;
font-weight: bold;
}
}
}
Tipp: Wenn Sie einen Container (z.B. einen Kreis) um das Häkchen zeichnen, verschieben Sie ihn ein wenig nach oben (wie wir es hier mit padding-bottom und padding-left getan haben), um ihn optisch zu zentrieren.
Verwenden Sie dafür NICHT padding-inline-start oder padding-block-end, da sich diese je nach Schreibmodus ändern, die Form des Häkchens jedoch nicht.
6. Optional: Anzeige der ausgewählten Option anpassen
Standardmäßig wird in der <select> eine reine Textversion der ausgewählten Option angezeigt.
Wenn Sie Rich Content für den ausgewählten Wert anzeigen möchten, verwenden Sie <selectedcontent> in einem <button> und/oder zeigen Sie die ausgewählte Option anders an (z.B. durch Ausblenden bestimmter Details).
Verwenden Sie <selectedcontent> NICHT ohne die umgebenden <button>, da <selectedcontent> sonst wie jedes andere Inhaltselement Teil der Auswahl wird.
Best Practices
- Layoutverhalten testen Wenn Sie
appearance: base-selectfestlegen, wird das Standardverhalten des Browsers entfernt, bei dem die Größe des Auswahlfelds anhand der Breite der längsten Option festgelegt wird. Möglicherweise müssen Sie eine feste Breite festlegen oder Flex-/Grid-Einschränkungen verwenden, um Layout Shifts zu verhindern. - Achte darauf, dass dein
<select>einname-Attribut und ein zugehöriges<label>hat. So bleibt die Komponente auch bei einer benutzerdefinierten UI für Screenreader zugänglich und funktioniert korrekt mit Standardformularübermittlungen. - Verwenden Sie standardmäßige
value-Attribute für Optionen, damit das Senden von Formularen genau wie zuvor funktioniert.
Bedienungshilfen
Ein nativer <select> unterstützt nur die lineare Navigation mit den Pfeiltasten nach oben und unten. Die Pfeiltasten nach links und rechts haben im geöffneten Auswahlmenü keine Funktion und mit den Pfeiltasten nach oben und unten wird weiterhin sequenziell durch die Elemente navigiert, unabhängig von Zeilen und Spalten.
Wenn du eine räumliche Navigation implementieren möchtest, die dem Raster folgt, kannst du keydown abfangen und den Fokus auf die nächste Option in der gedrückten Richtung (z.B. mit getBoundingClientRect()) lenken, wenn die Pfeiltasten verwendet werden.
Verwenden Sie DOM-Methoden, die mit der tatsächlichen Geometrie arbeiten (z. B. getBoundingClientRect()), um das entsprechende nächste/vorherige Element zu bestimmen, anstatt CSS-Strings wie grid-template-columns oder grid-column zu parsen. Letzteres kann bei komplexen Rastern, Unterrastern, RTL und anderen Layoutszenarien fehleranfällig sein.
Übertreiben Sie es jedoch nicht. Verwenden Sie die Invarianten, die Sie über das Layout kennen, um diese Logik zu vereinfachen.
Hinweis: Dies betrifft nur die Tastaturnavigation. <select> und ::picker() haben weiterhin ihre Standardrollen (menu oder listbox). Diese können nicht überschrieben werden und dürfen kein Element mit role="grid" enthalten.
Das Verschachteln eines Wrappers mit role="grid" innerhalb der Auswahl funktioniert in der Praxis, ist aber nicht gültig und kann Nutzer von assistiven Technologien überraschen.
In einigen Fällen kann die Verwendung von <optgroup> zum Gruppieren von Optionen eine gute Screenreader-UX ohne role="grid" erzeugen.
Andernfalls kann es erforderlich sein, auf eine benutzerdefinierte Lösung mit der Popover API, der Ankerpositionierung und role="grid" umzusteigen, um die gewünschte UX für Screenreader-Nutzer zu erreichen.
Fallback-Strategie
Fallbacks und Browserunterstützung für anpassbare <select>
In Browsern, die appearance: base-select noch nicht unterstützen, wird das <select>-Element zu einem Standard-Dropdown-Menü des Betriebssystems herabgestuft.
- Nicht-Text-Inhalte werden ignoriert: Ältere Browser entfernen HTML-Tags (wie
<svg>oder<div>) innerhalb von<option>-Tags und rendern nur die Textknoten. Der Textinhalt des<option>-Elements muss lesbar und für sich genommen aussagekräftig sein. - Umgang mit HTML-Strukturen: Standardparser ignorieren möglicherweise die
<button>- und<selectedcontent>-Tags innerhalb von<select>oder behandeln sie als ungültig. Für die progressive Verbesserung sind keine umfangreichen JavaScript-Polyfills erforderlich, wenn Sie Standardtext als lesbaren Fallback betrachten.
document.addEventListener("DOMContentLoaded", () => {
// Check if browser supports base-select value
if (!CSS.supports("appearance", "base-select")) {
// Custom select overrides are not supported natively.
}
});