Detta är avsnitt 20 i en serie som undersöker moderna CSS-lösningar på problem jag har löst under de senaste 13+ åren av att vara en frontend-utvecklare.
Modern CSS ger oss en rad egenskaper för att uppnå anpassade valstilar som har nästan identiska initialt utseende för enskilda, flera och inaktiverade select
-element över de bästa webbläsarna.
Några egenskaper och tekniker som vår lösning kommer att använda:
-
clip-path
för att skapa den anpassade rullgardinspilen - CSS-rutnätlayout för att anpassa de ursprungliga markerings- och pil
- anpassade CSS-variablerna för flexibel styling
-
em
enheter för relativ storlek
Vanliga problem med infödda val #
Som med alla formulärfälttyper varierar <select>
mellan webbläsare i sitt ursprungliga utseende.
Från vänster till höger är här det första utseendet för <select>
i Firefox, Chrome och Safari:
Skillnaderna inkluderar boxstorlek, teckensnittsstorlek, radhöjd och mest utmärkta är skillnaden i hur rullgardinsindikatorn är utformad.
Vår Målet är att skapa samma ursprungliga utseende i dessa webbläsare, inklusive flera val och inaktiverade tillstånd.
Obs! I rullgardinslistan är det fortfarande inte möjligt att formatera, så när
<select>
öppnas kommer den fortfarande att hämta de enskilda webbläsarens stilar föroption
-listan. Detta är ok – vi kan hantera det för att bibehålla den fria tillgängligheten för en native select!
Base HTML #
We ” Fokuserar på en enda <select>
som ska börja.
Etiketten är inte en del av vår stylingövning, men den ingår som ett allmänt krav, särskilt med for
attribut med värdet av id
på <select>
.
För att uppnå våra anpassade stilar har vi ”förpackat det inhemska valet i en extra div med klassen select
för enkelhet i denna handledning.
Återställ och ta bort ärvda stilar #
Som ingår i alla mina självstudier som en modern bästa praxis lägger vi till följande återställning först:
Efter det, vi kan börja regeln för den infödda select
och tillämpa följande för att vila sitt utseende:
Även om de flesta av dem sannolikt är bekanta är oddball out . Det här är en egendom som används sällan och du kommer att notera att det inte är precis där vi skulle vilja ha det för support, men vad det främst ger oss i detta fall är att ta bort den inbyggda webbläsarens nedrullningspil.
Obs: CodePen är inställd på att använda autofrefixer som lägger till nödvändiga förinställda versioner av egenskapen
appearance
. Du kan behöva ställa in detta specifikt för ditt projekt eller lägga till dem manuellt. Min HTML / Sass Jumpstart innehåller autoprefixer som en del av produktionsbyggnaden.
Den goda nyheten är att vi kan lägga till ytterligare en regel för att få bort pilen för lägre IE-versioner om du behöver det:
Detta tips finns i utmärkt artikel från Filament Group som visar en alternativ metod för att skapa valda stilar.
Den sista delen är att ta bort standard outline
. Oroa dig inte – vi ” Lägg till en ersättare senare för :focus
state!
Och här är en gif av våra framsteg. Du kan se att det nu finns noll visuell indikation på att detta är en select
innan du klickar på den:
Anpassade markeringsrutor #
Låt oss först ställa in några CSS-variabler. Detta gör att vårt val kan färgas flexibelt så att det representerar ett felläge.
Anmärkning om tillgänglighet: Som användargränssnittselement måste vald ram ha en kontrast på 3: 1 eller större mot den omgivande ytfärgen.
Nu är det dags att skapa de anpassade markeringsstilar som vi kommer att tillämpa på vår inslagning div.select
:
Först ställer vi in några breddbegränsningar. Värdena min-width
och max-width
är mest för denna demo, och du kan välja att släppa eller ändra den för ditt användningsfall.
Sedan tillämpar vi några boxmodellegenskaper, inklusive border
, border-radius
och padding
. Observera användningen av em
-enheten som håller dessa egenskaper proportionella med uppsättningen font-size
.
I återställningsformaten ställer vi in flera egenskaper till inherit
, så här definierar vi de, inklusive font-size
, cursor
och line-height
.
Slutligen ger vi det bakgrundsegenskaper, inklusive en lutning för den minsta biten av dimensionera. Om du tar bort bakgrundsegenskaperna blir markeringen transparent och plockar upp sidans bakgrund. Detta kan vara önskvärt, men var medveten om och testa effekterna på kontrasten.
Och här är våra framsteg:
Anpassad Välj nedrullningspil #
För vår nedrullningspil ska vi använda en av de mest spännande moderna CSS-egenskaperna: clip-path
.
Klippvägar låter oss skapa alla typer av former genom att ”klippa” de annars kvadratiska och rektangulära formerna som vi får som standardvärden från de flesta element. Jag hade kul med att använda clip-path
på min senaste redesign av portföljwebbplatsen.
Innan clip-path
har bättre stöd inkluderade alternativa metoder:
-
background-image
– vanligtvis en png, något modernare skulle vara en SVG - en inbyggd SVG som ett ytterligare element
- gränstricket för att skapa en triangel
SVG kan kännas som den optimala lösningen, men när den används som en background-image
förlorar den förmågan att fungera som en ikon i betydelsen av att inte kunna o ändra dess egenskaper, såsom fyllfärg utan att omdefiniera den helt. Det betyder att vi inte kan använda vår anpassade CSS-variabel.
Att placera en SVG inline löser fill
färgproblem, men det innebär att inkludera ytterligare ett element varje gång en <select>
definieras.
Med clip-path
får vi en skarp, skalbar pil ”grafik” som känns som en SVG men med fördelarna med att kunna använda vår anpassade variabel och ingå i stilen jämfört med HTML-markeringen.
För att skapa pilen definierar vi den som en ::after
pseudo-element.
Syntaxen clip-path
är lite konstigt och eftersom det är inte riktigt fokus för denna artikel, jag rekommenderar följande resurser:
- Colby Fayock utforskar syntaxen med ett exempel i denna egghead-video
- Clippy är ett onlineverktyg som tillåter du väljer en form och justerar punkterna medan du genererar
clip-path
CSS dynamiskt
Om du följer längs med kan du ha märkt att pilen inte visas trots att du definierar width
och height
. När den inspekterades fann den att ::after
faktiskt inte tillåts bredden.
Vi löser detta genom att uppdatera vår .select
för att använda CSS-rutnätlayout.
Detta låter pilen visas genom att i huvudsak utöka det ett visningsvärde som ”block”.
I detta skede kan vi verifiera att vi verkligen har skapat en triangel.
För att fixa inriktningen, vi kommer att använda mitt favorit CSS-rasterhack (gammal hatt för dig om du har läst några artiklar här!).
Gammal CSS-lösning: position: absolute
Ny CSS-lösning: En enda grid-template-areas
för att innehålla dem alla
Först definierar vi vårt område och definierar sedan att select
och ::after
använder båda den. Namnet omfattas av det element som det har skapats för, och vi kommer att hålla det enkelt genom att kalla det ”select”:
Vilket ger oss en överlappning av pilen ovanför det ursprungliga valet på grund av stapling av sammanhang via källordning:
Vi kan nu använda rutnätegenskaper för att slutföra justeringen för varje element:
Ta-da!
: fokusläge #
Åh ja – kom ihåg hur vi tog bort outline
? Vi måste lösa den saknade :focus
tillstånd från att släppa det.
Det finns en kommande egenskap som vi kan använda som heter :focus-within
men det är fortfarande bäst att inkludera en polyfyll för den här tid.
För den här handledningen använder vi en alternativ metod som uppnår samma resultat, bara lite kraftigare.
Tyvärr betyder det att vi måste lägga till ytterligare ett element i DOM.
Efter det ursprungliga markeringselementet, som det sista barn inom .select
, lägg till:
Varför efter? Eftersom det här är en ren CSS-lösning betyder det att vi kan ändra den när select
fokuseras genom att använda den intilliggande syskonväljaren – +
.
Detta gör att vi kan skapa följande regel:
Du undrar kanske varför vi” återgår till position: absolute
efter att ha lärt sig föregående grid-area
hack.
Anledningen är att undvika att räkna om justeringar baserat på vaddering. Om du försöker på egen hand kommer du att se att även inställningen width
och height
gör att den fortfarande sitter i stoppningen .
Jobbet position: absolute
är bäst att matcha storleken på ett element. Vi drar en extra pixel i varje riktning för att se till att den överlappar gränsen -egenskap.
Men vi måste göra ytterligare ett tillägg till .select
för att säkerställa att det är relativt vårt val av – ja, position: relative
.
Och här är vår anpassade markera alla tillsammans som vi ser i Chrome:
Multiple Select #
Väljer kommer i en andra smak, vilket tillåter en användare att välja mer än ett alternativ. Ur HTML-perspektivet betyder detta helt enkelt att lägga till multiple
-attributet, men vi lägger också till en klass för att skapa stiljusteringar som heter select--multiple
:
Och när vi tittar på den kan vi se att den ärvt de flesta av våra stilar med fördel, förutom att vi inte behöver pilen i den här vyn.
Detta är en snabb lösning för att justera vår väljare som definierar pilen. Vi använder :not()
för att utesluta vår nyligen definierade klass:
Vi har ett par mindre justeringar att göra för multipelvalet, det första är att ta bort vaddering som tidigare lades till för att göra plats för pilen:
Som standard kommer alternativ med ett långt värde att rinna över det synliga området och klippas ut, men jag tyckte att de viktigaste webbläsarna tillåter att omslaget åsidosätts om du vill:
Valfritt kan vi ställa in en height
för att välja en lite mer pålitligt beteende mellan webbläsare. Genom att testa detta lärde jag mig att Chrome och Firefox kommer att visa ett delvis alternativ, men Safari döljer helt ett alternativ som inte kan visas helt.
Höjden måste ställas in direkt på det ursprungliga valet . Med tanke på våra andra stilar kommer värdet 6rem
att kunna visa 3 alternativ:
Vid denna punkt, på grund av nuvarande webbläsarsupport har vi gjort så mycket justeringar som vi kan.
:selected
avoptions
är ganska anpassningsbar i Chrome, något i Firefox och inte alls i Safari. Se CodePen-demo för ett avsnitt som inte kan kommenteras för att förhandsgranska detta.
: inaktiverade stilar #
Medan jag skulle förespråka helt enkelt inte visar funktionshindrade kontroller, vi bör förbereda stilarna för det tillståndet bara för att täcka våra baser.
För att betona det inaktiverade tillståndet vill vi använda en grå bakgrund. Men eftersom vi har ställt in bakgrundsstilar på .select
och det inte finns någon ”ta :parent
väljare, måste vi skapa en sista klass att hantera för detta tillstånd:
Här har vi uppdaterat markören som en extra ledtråd att fältet inte kan interageras med och uppdaterat bakgrundsvärdena som vi tidigare ställt in vara vit för att nu vara mer grå för det funktionshindrade tillståndet.
Detta resulterar i följande framträdanden:
Demo #
Du kan testa det själv, men här är en förhandsgranskning av hela lösningen över (från vänster) Firefox, Chrome och Safari:
Av Stephanie Eckles (@ 5t3ph)