Właściwość CSS appearance: base-select umożliwia stylizowanie elementu <select> i jego selektora (za pomocą ::picker(select)) jak zwykłych elementów HTML.
W połączeniu z nowoczesnymi technikami układu CSS, takimi jak Grid czy Flexbox, możesz odejść od tradycyjnej listy pionowej i stworzyć bogate wrażenia wizualne bez niestandardowego kodu JS.
Możesz na przykład użyć display: grid, aby nadać opcjom styl dwuwymiarowej siatki kart.
Jest to idealne rozwiązanie w przypadku selektorów kolorów, selektorów emotikonów lub wersji produktów, gdzie rozbudowane menu wizualne jest skuteczniejsze niż lista.
Jak to zrobić?
1. Aktywuj podstawowy styl
Zastosuj appearance: base-select zarówno do elementu <select>, jak i jego wewnętrznego pseudoelementu selektora select::picker(select):
select.grid-picker {
&, &::picker(select) {
appearance: base-select;
}
}
2. Stylizowanie kontenera selektora
Ustaw element docelowy select:open::picker(select) i zastosuj display: grid (lub display: flex).
Zdefiniuj kolumny i odstępy tak samo jak w przypadku każdego kontenera.
select.grid-picker:open::picker(select) {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
WAŻNE: :open jest niezbędny. Jeśli nadasz styl elementowi select::picker(select), selektor będzie widoczny nawet wtedy, gdy element select będzie zamknięty.
3. Stylizowanie opcji
Ustaw kierowanie na elementy <option>, aby nadać im styl elementów siatki lub kart.
Możesz w nich dodawać obrazy, pliki SVG lub złożone układy.
/* 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. Stylizowanie wybranej opcji
Aby nadać styl wybranej opcji, użyj option:checked. Na przykład:
.grid-picker option:checked {
position: relative;
border: 2px solid var(--primary-color);
background-color: oklab(from var(--primary-color) l a b / 8%);
}
Podobnie jak w przypadku każdego elementu sterującego interfejsu, nie przekazuj informacji o stanie tylko za pomocą koloru.Używaj wielu wskaźników wizualnych (np. kolorów, grubości obramowania, znacznika wyboru), aby wskazać, która opcja jest wybrana.
5. (Opcjonalnie) Nadaj styl znacznikowi wyboru wybranej opcji
Domyślnie przeglądarka renderuje znacznik wyboru jako pierwszy element podrzędny każdego elementu <option>.
Działa jak ::before z content: "✓" / "", renderowany przed elementem ::before podanym przez autora, jeśli taki istnieje.
Jeśli opcja nie jest zaznaczona, znacznik wyboru jest ukryty za pomocą visibility: hidden.
Możesz go stylizować za pomocą pseudoelementu ::checkmark lub całkowicie ukryć, jeśli chcesz przekazać informację o wyborze za pomocą samego stylu lub użyć niestandardowego wskaźnika.
Aby na przykład umieścić go w prawym górnym rogu opcji, możesz zrobić coś takiego:
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;
}
}
}
Wskazówka: gdy rysujesz kontener (np. okrąg) wokół znacznika wyboru, przesuń go nieco w górę (tak jak tutaj z padding-bottom i padding-left), aby uzyskać optyczne wyśrodkowanie uwzględniające jego kształt.
NIE używaj do tego celu padding-inline-start ani padding-block-end, ponieważ będą się zmieniać w zależności od trybu pisania, podczas gdy kształt znacznika wyboru nie ulega zmianie.
6. (Opcjonalnie) Dostosuj wyświetlanie wybranej opcji.
Domyślnie <select> będzie wyświetlać tylko tekstową wersję wybranej opcji.
Aby wyświetlić szczegółowe treści dla wybranej wartości, użyj <selectedcontent> wewnątrz <button> lub wyświetl wybraną opcję w inny sposób (np. ukryj niektóre szczegóły).
NIE używaj elementu <selectedcontent> bez otaczającego go elementu <button>, ponieważ <selectedcontent> stanie się częścią selektora, tak jak każdy inny element treści.
Sprawdzone metody
- Przetestuj działanie układu. Ustawienie
appearance: base-selectusuwa domyślne działanie przeglądarki polegające na określaniu rozmiaru elementu select na podstawie szerokości najdłuższej opcji. Aby zapobiec przesunięciom układu, może być konieczne ustawienie stałej szerokości lub użycie ograniczeń flex/grid. - Upewnij się, że element
<select>ma atrybutnamei powiązany element<label>. Dzięki temu nawet w przypadku niestandardowego interfejsu komponent pozostaje dostępny dla czytników ekranu i działa prawidłowo ze standardowymi formularzami. - Użyj standardowych atrybutów
valuew opcjach, aby przesyłanie formularzy działało dokładnie tak jak wcześniej.
Ułatwienia dostępu
Natywny element <select> obsługuje tylko liniową nawigację za pomocą strzałek w górę i w dół, więc strzałki w lewo i w prawo nie działają w otwartym selektorze, a strzałki w górę i w dół nadal umożliwiają nawigację po elementach sekwencyjnie, niezależnie od wierszy i kolumn.
Aby wdrożyć nawigację przestrzenną, która podąża za siatką, możesz przechwycić keydown i przekierować zaznaczenie do najbliższej opcji w kierunku naciśnięcia (np. za pomocą getBoundingClientRect()), gdy używane są klawisze strzałek.
Aby określić odpowiedni następny lub poprzedni element, użyj metod DOM, które działają na rzeczywistej geometrii (np. getBoundingClientRect()), zamiast analizować ciągi CSS, takie jak grid-template-columns lub grid-column, które mogą być niestabilne i podatne na błędy w przypadku złożonych siatek, podsiatek, układów od prawej do lewej i innych scenariuszy układu.
Nie komplikuj jednak niepotrzebnie kodu. Aby uprościć tę logikę, użyj niezmienników, które są prawdziwe w przypadku układu.
Uwaga: dotyczy to tylko nawigacji za pomocą klawiatury. Elementy <select> i ::picker() nadal mają swoje domyślne role (menu lub listbox), których nie można zastąpić. Nie mogą też zawierać elementu z atrybutem role="grid".
Zagnieżdżenie kontenera z atrybutem role="grid" w selektorze działa w praktyce, ale jest nieprawidłowe i może zaskoczyć użytkowników technologii wspomagających.
W niektórych przypadkach użycie elementu <optgroup> do grupowania opcji może zapewnić dobrą obsługę czytnika ekranu bez elementu role="grid".
W przeciwnym razie może być konieczne przejście na rozwiązanie niestandardowe z użyciem interfejsu Popover API, pozycjonowania zakotwiczonego i atrybutu role="grid", aby zapewnić użytkownikom czytników ekranu odpowiednie wrażenia.
Strategia zastępcza
Kreacje zastępcze i obsługa przez przeglądarki w przypadku formatu <select> z możliwością dostosowania
W przypadku przeglądarek, które nie obsługują jeszcze appearance: base-select, element <select> jest zastępowany standardowym menu rozwijanym systemu operacyjnego.
- Ignorowanie treści nietekstowych: starsze przeglądarki usuwają tagi HTML (takie jak
<svg>lub<div>) wewnątrz tagów<option>i renderują tylko węzły tekstowe. Upewnij się, że treść tekstowa elementu<option>jest czytelna i ma sens sama w sobie. - Obsługa struktury HTML: standardowe parsery mogą ignorować tagi
<button>i<selectedcontent>wewnątrz tagu<select>lub traktować je jako nieprawidłowe. Jeśli standardowy tekst jest dla Ciebie czytelną opcją zastępczą, do progresywnego ulepszania nie są wymagane żadne obciążające skrypty polyfill JavaScript.
document.addEventListener("DOMContentLoaded", () => {
// Check if browser supports base-select value
if (!CSS.supports("appearance", "base-select")) {
// Custom select overrides are not supported natively.
}
});