Custom Select Styles with Pure CSS

Dette er episode nr. 20 i en serie som undersøker moderne CSS-løsninger på problemer jeg har løst i løpet av de siste 13+ årene med å være frontend-utvikler.

Moderne CSS gir oss en rekke egenskaper for å oppnå tilpassede utvalgte stiler som har nesten identiske innledende utseende for enkelt-, flere og deaktiverte select -elementer i de beste nettleserne.

Noen få egenskaper og teknikker løsningen vår vil bruke:

  • clip-path for å lage den egendefinerte rullegardinpilen
  • CSS-rutenettoppsett for å justere de opprinnelige valg- og pilen
  • tilpassede CSS-variabler fleksibel styling
  • em enheter for relativ størrelse

Vanlige problemer med innfødte valg #

Som med alle skjemafelttyper, varierer <select> mellom nettlesere i utgangspunktet.

Fra venstre til høyre, her er det første utseendet for <select> i Firefox, Chrome og Safari:

Forskjellene inkluderer boksstørrelse, skriftstørrelse, linjehøyde og mest fremtredende er forskjellen i hvordan rullegardinindikatoren er utformet.

Vår Målet er å skape det samme utseendet på tvers av disse nettleserne, inkludert flere valg og deaktiverte tilstander.

Merk: rullegardinlisten er fremdeles ikke stilbar, så når <select> er åpnet, vil den fremdeles hente de individuelle nettleserens stiler for option -listen. Dette er ok – vi kan takle det for å beholde den gratis tilgjengeligheten til et innfødt utvalg!

Base HTML #

We » Vi vil fokusere på en enkelt <select> som skal begynne.

Etiketten er ikke en del av vår stylingøvelse, men den er inkludert som et generelt krav, spesielt med for attributt med verdien av id<select>.

For å oppnå våre tilpassede stiler har vi «pakket innfødte selekter i en ekstra div med klassen select for enkelhet i denne opplæringen.

Tilbakestill og fjern arvede stiler #

Som er inkludert i alle veiledningene mine som en moderne best praksis, legger vi til følgende tilbakestilling først:

Etter det, vi kan begynne regelen for den innfødte select og bruke følgende for å hvile utseendet:

Selv om de fleste av dem sannsynligvis er kjent, er oddball ut . Dette er en sjelden brukt eiendom, og du vil være oppmerksom på at det ikke er der vi ønsker det for støtte, men det som det primært gir oss i dette tilfellet er fjerning av den opprinnelige nettleserens rullegardinpil.

Merk: CodePen er konfigurert til å bruke autofrefixer som vil legge til nødvendige forhåndsfaste versjoner av egenskapen appearance. Du må kanskje konfigurere dette spesifikt for prosjektet ditt, eller legge til dem manuelt. Min HTML / Sass Jumpstart inkluderer autofrefixer som en del av produksjonsbyggingen.

Den gode nyheten er at vi kan legge til en regel til for å fjerne pilen for lavere IE-versjoner hvis du trenger det:

Dette tipset finnes i utmerket artikkel fra Filament Group som viser en alternativ metode for å lage utvalgte stiler.

Den siste delen er å fjerne standard outline. Ikke bekymre deg – vi » Legg til en erstatning senere for :focus state!

Og her er en gif av fremgangen vår. Du kan se at det nå er null visuell indikasjon på at dette er en select før du klikker på den:

Egendefinerte valgboksstiler #

La oss først sette opp noen CSS-variabler. Dette vil gjøre at vårt utvalg kan farges om fleksibelt slik at det representerer en feiltilstand.

Tilgjengelighetsmerknad: Som et brukergrensesnittelement må den valgte rammen ha en kontrast på 3: 1 eller større mot den omkringliggende overflatefargen.

Nå er det på tide å lage de tilpassede valgstiler som vi vil bruke på vår innpakning div.select:

Først setter vi opp noen breddehindringer. Verdiene min-width og max-width er for denne demonstrasjonen, og du kan velge å slippe eller endre den for din brukstilfelle.

Deretter bruker vi noen boksmodellegenskaper, inkludert border, border-radius og padding. Legg merke til bruken av em -enheten som vil holde disse egenskapene proporsjonale med settet font-size.

I tilbakestillingsstilene setter vi flere egenskaper til inherit, så her definerer vi de, inkludert font-size, cursor, og line-height.

Til slutt gir vi det bakgrunnsegenskaper, inkludert en gradient for den minste bit av dimensjon. Hvis du fjerner bakgrunnsegenskapene, vil merket være gjennomsiktig og plukke opp bakgrunnen for siden. Dette kan være ønskelig, men vær oppmerksom på og test effekten av kontrasten.

Og her er vår fremgang:

Egendefinert Velg rullegardinpil #

For rullegardinpilen vår skal vi bruke en av de mest spennende moderne CSS-egenskapene: clip-path.

Klippbaner lar oss lage alle slags former ved å «klippe» de ellers firkantede og rektangulære figurene vi mottar som standard fra de fleste elementene. Jeg hadde det gøy med å bruke clip-path på det siste redesignet av porteføljesiden min.

Før clip-path hadde bedre støtte, inkluderte alternative metoder:

  • background-image – vanligvis en png, litt mer moderne ville være en SVG
  • en innebygd SVG som et ekstra element
  • grensetrikset for å lage en trekant

SVG kan føles som den optimale løsningen, men når den brukes som et background-image, mister den evnen til å fungere som et ikon i den forstand at det ikke er mulig o endre egenskapene som fyllfarge uten å omdefinere den helt. Dette betyr at vi ikke kan bruke vår tilpassede CSS-variabel.

Plassering av en SVG inline løser fill fargeproblemet, men det betyr å inkludere ett element til hver gang en <select> er definert.

Med clip-path får vi en skarp, skalerbar pil «grafikk» som føles som en SVG, men med fordelene ved å kunne bruke vår tilpassede variabel og være inneholdt i stilen mot HTML-markeringen.

For å opprette pilen vil vi definere den som en ::after pseudo-element.

clip-path syntaksen er litt rart, og siden den «s egentlig ikke fokuset på denne artikkelen, jeg anbefaler følgende ressurser:

  • Colby Fayock utdyper syntaksen med et eksempel i denne eggheadvideoen
  • Clippy er et online verktøy som tillater du velger en figur og justerer punktene mens du genererer clip-path CSS dynamisk

Hvis du følger langs vingen, har du kanskje lagt merke til at pilen ikke vises til tross for at du definerer width og height. Når det ble inspisert, fant det at ::after faktisk ikke får lov til det.

Vi løser dette ved å oppdatere .select for å bruke CSS-rutenettoppsett.

Dette lar pilen vises ved i hovedsak å utvide den til en visningsverdi som «block».

På dette stadiet kan vi bekrefte at vi virkelig har opprettet en trekant.

For å fikse justeringen, vi vil bruke min favoritt CSS grid hack (gammel hatt til deg hvis du har lest noen få artikler her!).

Gammel CSS-løsning: position: absolute Ny CSS-løsning: En enkelt grid-template-areas for å inneholde dem alle

Først definerer vi vårt område, og definer deretter at select og ::after bruker den begge. Navnet er rettet mot elementet det er opprettet for, og vi vil holde det enkelt ved å kalle det «select»:

Som gir oss en overlapping av pilen over det opprinnelige valget på grunn av stabling av kontekst via kildefølget rekkefølge:

Vi kan nå bruke rutenettegenskaper for å fullføre justeringen av hvert element:

Ta-da!

: fokusstatus

Å ja – husk hvordan vi fjernet outline? Vi må løse den manglende :focus tilstand fra å slippe det.

Det er en kommende egenskap vi kan bruke kalt :focus-within men det er fortsatt best å inkludere en polyfyll for den på dette tid.

For denne opplæringen bruker vi en alternativ metode som oppnår det samme resultatet, bare litt tyngre.

Dessverre betyr dette at vi må legge til ett element til DOM.

Etter det opprinnelige valgelementet, som det siste barn i .select, legg til:

Hvorfor etter? Fordi siden dette er en ren CSS-løsning, betyr det at vi kan endre den når select fokuseres ved å bruke den tilstøtende søskenvelgeren – .

Dette lar oss lage følgende regel:

Du lurer kanskje på hvorfor vi» er tilbake til position: absolute etter å bare ha lært det forrige grid-area hacket.

Årsaken er å unngå omberegning av justeringer basert på polstring. Hvis du prøver det på egen hånd, vil du se at selv om du setter width og height til 100%, blir det fortsatt sittende i polstringen .

Jobben position: absolute er best å matche størrelsen på et element. Vi trekker det en ekstra piksel i hver retning for å sikre at det overlapper grensen. eiendom.

Men vi må gjøre et tillegg til .select for å sikre at det er relativt til vårt utvalg av – vel, position: relative.

Og her er vår skikk tilpasset alle som vi ser i Chrome:

Flere valg #

Valgene kommer i en annen smak, som lar brukeren velge mer enn ett alternativ. Fra HTML-perspektivet betyr dette ganske enkelt å legge til multiple attributtet, men vi vil også legge til en klasse for å lage stiljusteringer kalt select--multiple :

Og når vi ser på den, kan vi se at den arvet de fleste av stilene våre gunstig, bortsett fra at vi ikke trenger pilen i denne visningen.

Dette er en rask løsning for å justere velgeren vår som definerer pilen. Vi bruker :not() for å ekskludere vår nylig definerte klasse:

Vi har et par mindre justeringer å gjøre for multiple select, den første er å fjerne polstring som tidligere ble lagt til for å gi plass til pilen:

Som standard vil alternativer med lang verdi overløpe det synlige området og bli klippet, men jeg fant ut at hovedleserne lar innpakningen overstyres hvis du ønsker:

Eventuelt kan vi angi en height på select for å bringe en litt mer pålitelig atferd på tvers av nettlesere. Gjennom å teste dette lærte jeg at Chrome og Firefox vil vise et delvis alternativ, men Safari vil helt skjule et alternativ som ikke er i stand til å være fullt synlig.

Høyden må settes direkte på det opprinnelige valget. . Gitt våre andre stiler, vil verdien 6rem kunne vise tre alternativer:

På dette punktet, på grunn av nåværende nettleserstøtte har vi gjort så mange justeringer som vi kan.

:selected -tilstanden av options er ganske tilpassbar i Chrome, noe i Firefox, og ikke i det hele tatt i Safari. Se CodePen-demoen for en del som ikke kan kommenteres for å forhåndsvise dette.

: deaktiverte stiler #

Mens jeg vil anbefale for rett og slett ikke viser deaktiverte kontroller, vi bør forberede stilene for den tilstanden bare for å dekke basene våre.

For å vektlegge den deaktiverte staten, vil vi bruke en grå bakgrunn. Men siden vi har satt bakgrunnsstiler på .select og det ikke er «ta :parent velger, må vi lage en siste klasse å håndtere for denne tilstanden:

Her har vi oppdatert markøren som et ekstra hint om at feltet ikke kan samhandles med, og oppdatert bakgrunnsverdiene vi tidligere har satt til være hvit for nå å være mer grå for den deaktiverte tilstanden.

Dette resulterer i følgende fremtoninger:

Demo #

Du kan teste det selv, men her er en forhåndsvisning av den fulle løsningen over (fra venstre) Firefox, Chrome og Safari:

Av Stephanie Eckles (@ 5t3ph)

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *