Questo è lepisodio 20 di una serie che esamina le soluzioni CSS moderne ai problemi che ho risolto negli ultimi 13+ anni come sviluppatore di frontend.
Il CSS moderno ci offre una gamma di proprietà per ottenere stili di selezione personalizzati che hanno un quasi identico aspetto iniziale per elementi select
singoli, multipli e disabilitati nei browser principali.
Alcune proprietà e tecniche che verranno utilizzate dalla nostra soluzione:
-
clip-path
per creare la freccia del menu a discesa personalizzata - layout della griglia CSS per allineare la selezione nativa e la freccia
- variabili CSS personalizzate per stile flessibile
-
em
unità per il dimensionamento relativo
Problemi comuni con le selezioni native #
Come con tutti i tipi di campo modulo, <select>
varia da browser a browser nel suo aspetto iniziale.
Da sinistra a destra, ecco laspetto iniziale di <select>
in Firefox, Chrome e Safari:
Le differenze includono la dimensione del riquadro, la dimensione del carattere, laltezza della riga e, soprattutto, la differenza nello stile dellindicatore a discesa.
Il nostro lobiettivo è creare lo stesso aspetto iniziale su questi browser, incluse selezioni multiple e stati disabilitati.
Nota: lelenco a discesa non è ancora modificabile, quindi, una volta aperto
<select>
, continuerà a rilevare gli stili dei singoli browser per lelencooption
. Va bene – possiamo occuparcene per mantenere laccessibilità gratuita di una selezione nativa!
HTML di base #
Noi ” Per iniziare, mi concentrerò su un singolo <select>
.
Letichetta non fa parte del nostro esercizio di stile, ma è inclusa come requisito generale, in particolare con il for
attributo con il valore di id
su <select>
.
Per realizzare i nostri stili personalizzati, abbiamo inserito la selezione nativa in un div aggiuntivo con la classe select
per semplicità in questo tutorial.
Reimposta e rimuovi stili ereditati #
Poiché è incluso in tutti i miei tutorial come best practice moderna, aggiungiamo prima il seguente ripristino:
Successivamente, possiamo iniziare la regola per il nativo select
e applicare quanto segue per mantenerne laspetto:
Mentre la maggior parte di questi sono probabilmente familiari, la strana cosa è . Questa è una proprietà usata di rado e noterai che non è esattamente dove “vorremmo ricevere supporto, ma ciò che ci fornisce principalmente in questo caso è la rimozione della freccia a discesa del browser nativo.
Nota: CodePen è impostato per utilizzare il prefissatore automatico che aggiungerà le versioni prefissate richieste della proprietà
appearance
. Potrebbe essere necessario impostarlo in modo specifico per il progetto o aggiungerli manualmente. Il mio HTML / Sass Jumpstart include lautoprefixer come parte della build di produzione.
La buona notizia è che possiamo aggiungere unaltra regola per ottenere la rimozione della freccia per le versioni inferiori di IE se ne hai bisogno:
Questo suggerimento si trova nella ottimo articolo di Filament Group che mostra un metodo alternativo per creare stili selezionati.
Lultima parte consiste nel rimuovere il valore predefinito outline
. Non ti preoccupare – noi ” in seguito aggiungerò una sostituzione per :focus
state!
Ed ecco una gif dei nostri progressi. Puoi vedere che ora non cè alcuna indicazione visiva che si tratta di un select
prima di fare clic su di esso:
Stili casella di selezione personalizzati #
Per prima cosa, impostiamo alcune variabili CSS. Ciò consentirà alla nostra selezione di essere ricolorata in modo flessibile in modo da rappresentare uno stato di errore.
Nota sullaccessibilità: come elemento dellinterfaccia utente, il bordo selezionato deve avere un contrasto 3: 1 o maggiore rispetto al colore della superficie circostante.
Ora è il momento di creare gli stili di selezione personalizzati che applicheremo al nostro wrapping div.select
:
Per prima cosa, abbiamo impostato alcuni vincoli di larghezza. I valori min-width
e max-width
si riferiscono principalmente a questa demo e puoi scegliere di eliminarli o modificarli in base al tuo caso duso.
Quindi applichiamo alcune proprietà del box model, tra cui border
, border-radius
e padding
. Nota luso dellunità em
che manterrà queste proprietà proporzionali allinsieme font-size
.
Negli stili di ripristino, impostiamo diverse proprietà su inherit
, quindi qui le definiamo, tra cui font-size
, cursor
e line-height
.
Infine, forniamo le proprietà dello sfondo, inclusa una sfumatura per la minima parte di dimensione. Se rimuovi le proprietà dello sfondo, la selezione sarà trasparente e riprenderà lo sfondo della pagina. Ciò può essere desiderabile, tuttavia, essere consapevoli e testare gli effetti sul contrasto.
Ed ecco i nostri progressi:
Personalizzato Seleziona la freccia a discesa #
Per la nostra freccia a discesa, utilizzeremo una delle proprietà CSS moderne più interessanti: clip-path
.
I tracciati dei clip ci consentono di creare tutti i tipi di forme “ritagliando” le forme altrimenti quadrate e rettangolari che riceviamo come impostazioni predefinite dalla maggior parte degli elementi. Mi sono divertito a usare clip-path
nella riprogettazione del mio sito portfolio.
Prima di clip-path
avere un supporto migliore, metodi alternativi inclusi:
-
background-image
– tipicamente un png, leggermente più moderno sarebbe un SVG - un SVG in linea come elemento aggiuntivo
- il trucco del bordo per creare un triangolo
SVG può sembrare la soluzione ottimale, tuttavia se usato come background-image
perde la capacità di agire come unicona nel senso di non essere in grado di t o alterare le sue proprietà come il colore di riempimento senza ridefinirlo completamente. Ciò significa che non possiamo utilizzare la nostra variabile personalizzata CSS.
Posizionare un SVG inline risolve il problema del colore fill
, tuttavia significa includere un elemento in più ogni volta che un <select>
è definito.
Con clip-path
, otteniamo una freccia “grafica” nitida e scalabile che sembra un SVG ma con il vantaggio di poter utilizzare la nostra variabile personalizzata e di essere contenuto nello stile rispetto al markup HTML.
Per creare la freccia, la definiremo come ::after
pseudo-elemento.
La sintassi clip-path
è un po strana, e poiché “s non proprio al centro di questo articolo, consiglio le seguenti risorse:
- Colby Fayock esplora la sintassi con un esempio in questo video testa duovo
- Clippy è uno strumento online che consente selezionare una forma e regolare i punti generando dinamicamente il
clip-path
CSS
Se stai seguendo ala lungo, potresti aver notato che la freccia non viene visualizzata nonostante la definizione di width
e height
. Quando viene ispezionato, si è riscontrato che ::after
non è effettivamente consentito per la sua larghezza.
Risolveremo questo problema aggiornando il nostro .select
per utilizzare il layout della griglia CSS.
Questo fa apparire la freccia essenzialmente estendendola a un valore di visualizzazione simile a “block”.
A questo punto possiamo verificare che abbiamo effettivamente creato un triangolo.
Per correggere lallineamento, useremo il mio hack griglia CSS preferito (vecchio cappello per te se hai letto alcuni articoli qui intorno!).
Vecchia soluzione CSS: position: absolute
Nuova soluzione CSS: un unico grid-template-areas
per contenerli tutti
Prima definiremo la nostra area, quindi definiremo che select
e ::after
lo utilizzano entrambi. Il nome è limitato allelemento per il quale è stato creato e noi “lo manterremo semplice chiamandolo” select “:
che ci dà una sovrapposizione di la freccia sopra la selezione nativa a causa del contesto di impilamento tramite lordine di origine:
Ora possiamo utilizzare le proprietà della griglia per finalizzare lallineamento di ogni elemento:
Ta-da!
: focus State #
Oh sì, ricordi come abbiamo rimosso outline
? Dobbiamo risolvere il :focus
dalleliminazione.
Cè una proprietà imminente che potremmo usare chiamata :focus-within
ma è comunque meglio includere un polyfill per questo tempo.
Per questo tutorial, utilizzeremo un metodo alternativo che ottiene lo stesso risultato, solo un po più pesante.
Sfortunatamente, questo significa che dobbiamo aggiungere un altro elemento il DOM.
Dopo lelemento select nativo, come ultimo figlio allinterno di .select
, aggiungi:
Perché dopo? Poiché si tratta di una soluzione CSS pura, posizionarla dopo la selezione nativa significa che possiamo modificarla quando select
è focalizzata utilizzando il selettore di pari livello adiacente – +
.
Questo ci permette di creare la seguente regola:
Forse ti starai chiedendo perché” torniamo a position: absolute
dopo aver appreso il precedente grid-area
hack.
Il motivo è evitare di ricalcolare le regolazioni in base al riempimento. Se lo provi da solo, vedrai che anche limpostazione di width
e height
al 100% lo fa comunque rimanere allinterno del padding .
Il lavoro position: absolute
fa meglio è abbinare la dimensione di un elemento. Lo stiamo trascinando un pixel in più in ogni direzione per assicurarci che si sovrapponga al bordo proprietà.
Tuttavia, dobbiamo fare unulteriore aggiunta a .select
per assicurarci che sia relativo alla nostra selezione da – beh, position: relative
.
Ed ecco la nostra selezione personalizzata tutti insieme come si vede in Chrome:
Selezione multipla #
Le selezioni sono disponibili in una seconda versione, che consente a un utente di selezionare più di unopzione. Dal punto di vista HTML, ciò significa semplicemente aggiungere lattributo multiple
, ma aggiungeremo anche una classe per creare aggiustamenti di stile denominati select--multiple
:
E guardandolo, possiamo vedere che ha ereditato favorevolmente la maggior parte dei nostri stili, tranne che non abbiamo bisogno della freccia in questa vista.
Questa è una soluzione rapida per regolare il nostro selettore che definisce la freccia. Usiamo :not()
per escludere la nostra nuova classe:
Abbiamo un paio di piccole modifiche da apportare per la selezione multipla, la prima è la rimozione del riempimento che è stato precedentemente aggiunto per fare spazio alla freccia:
Per impostazione predefinita, le opzioni con un valore lungo supereranno larea visibile e verranno troncate, ma ho scoperto che i browser principali consentono loverride del wrapping se lo desideri:
Facoltativamente, possiamo impostare un height
sulla selezione per portare un comportamento cross-browser un po più affidabile. Testando questo, ho appreso che Chrome e Firefox mostreranno unopzione parziale, ma Safari nasconderà completamente unopzione che non è in grado di essere completamente in vista.
Laltezza deve essere impostata direttamente sulla selezione nativa . Dati i nostri altri stili, il valore 6rem
sarà in grado di mostrare 3 opzioni:
A questo punto, a causa dellattuale supporto del browser, abbiamo apportato tutte le modifiche possibili.
Lo stato
:selected
dioptions
è abbastanza personalizzabile in Chrome, un po in Firefox e per niente in Safari. Vedere la demo di CodePen per una sezione che può essere decommentata per visualizzarne lanteprima.
: disabled Styles #
Anche se vorrei sostenere semplicemente non mostrando i controlli disabilitati, dovremmo preparare gli stili per quello stato solo per coprire le nostre basi.
Per enfatizzare lo stato disabilitato, vogliamo applicare uno sfondo grigio. Ma poiché “abbiamo impostato gli stili di sfondo su .select
e non esiste un selettore” ta :parent
, dobbiamo creare unultima classe da gestire questo stato:
Qui abbiamo aggiornato il cursore come ulteriore suggerimento che non è possibile interagire con il campo e aggiornato i valori di sfondo impostati in precedenza essere bianco per essere ora più grigio per lo stato disabilitato.
Ciò si traduce nelle seguenti apparenze:
Demo #
Puoi testarlo tu stesso, ma qui “unanteprima della soluzione completa su (da sinistra) Firefox, Chrome e Safari:
di Stephanie Eckles (@ 5t3ph)