TØRR å Bytte med CSS Variabler: Forskjellen på En Erklæring

0
6

Dette er det første innlegget i en todelt serie som ser ut til måten CSS variabler kan brukes til å gjøre koden for komplekse layouter og vekselsvirkningene mindre vanskelig å skrive og er mye lettere å vedlikeholde. Denne første avbetaling går gjennom ulike bruke tilfeller hvor denne teknikken gjelder. Andre innlegget (kommer i morgen!) vil dekke bruken av fallbacks og ugyldige verdier for å utvide teknikken til ikke-numeriske verdier.

Hva hvis jeg fortalte deg en enkel CSS-erklæringen gjør forskjellen i følgende bilde mellom den brede skjermen tilfelle (til venstre) og den andre (høyre)? Og hva hvis jeg fortalte deg en enkel CSS-erklæringen gjør forskjellen mellom odd og even elementer i den brede skjermen tilfelle?

Skjermbilde collage.

Eller som en enkel CSS-erklæringen gjør forskjellen mellom det skjulte og utvidede tilfeller nedenfor?

Utvide søket.

Hvordan er det mulig?

Vel, som du kanskje har gjettet fra tittelen, det er alt i kraft av CSS variabler.

Det er allerede mange artikler der ute om hva CSS variabler er og hvordan komme i gang med dem, så vi ikke skal komme inn på det her.

I stedet, vi vil dykke rett inn i hvorfor CSS variabler er nyttige for å nå disse sakene og andre, så vi vil gå videre til en detaljert forklaring av hvordan forskjellige tilfeller. Vi vil koden på et faktisk eksempel fra scratch, trinn for trinn, og, til slutt, vil du få en fryd for øyet i form av noen flere demoer som bruker samme teknikk.

Så la oss komme i gang!

Hvorfor CSS variabler er nyttige

For meg er den beste tingen om CSS variablene er at de har åpnet døren for styling ting i en logisk, matematisk og uanstrengt måte.

Et eksempel på dette er CSS variabel versjon av yin og yang loader jeg kodet siste året. For denne versjonen, og vi skaper de to halvdelene med to pseudo-elementer av loader element.

Roterende ☯ symbol, med sine to kammer øke og minske i størrelse.

Vi bruker de samme bakgrunn, kantlinje-farge, transform-opprinnelse og animasjon-forsinkelse verdier for de to halvdelene. Disse verdiene alt avhenger av en bryter variabel –jeg det er i utgangspunktet satt til 0 på begge halvdeler (pseudo-elementer), men da vi endre det til 1 for den andre halvdelen (: etter pseudo-element), og dermed dynamisk endring av den beregnede verdien av alle disse egenskapene.

Uten CSS variabler, ville vi må sette alle disse egenskapene (border-color, transform-opprinnelse, bakgrunn, animasjon og forsinkelse) igjen på :etter pseudo-element og risiko for å gjøre noen skrivefeil eller selv glemmer å sette noen av dem.

Hvordan bytte fungerer i det generelle tilfellet

Veksle mellom en null og en ikke-null verdi

I den enkelte sak av yin og yang loader, alle egenskaper vi bytte mellom de to halvdelene (pseudo-elementer) gå fra en null-verdi for en tilstand av bryteren, og en ikke-null verdi for den andre staten.

Hvis vi ønsker at våre verdien til å være null når bryteren er slått av (–jeg: 0) og ikke-null når bryteren er på (–jeg: 1), så vi multiplisere det med bryteren verdi (var (–)). Denne måten, hvis ikke-null-verdien bør være, la oss si en kantete verdien av 30deg, vi har:

  • når bryteren er av (–jeg: 0), calc(var (–)*30deg) regner ut til 0*30deg = 0deg
  • når bryteren er (–jeg: 1), calc(var (–)*30deg) regner ut til å 1*30deg = 30deg

Imidlertid, hvis vi ønsker at vår verdi som ikke er null når bryteren er slått av (–jeg: 0) og null når bryteren er på (–jeg: 1), så vi multiplisere det med utfyllende bryteren verdi (1 – var (–)). På denne måten, for den samme ikke-null kantete verdien av 30deg, vi har:

  • når bryteren er av (–jeg: 0), calc((1 – var (–))*30deg) regner ut til å (1 – 0)*30deg = 1*30deg = 30deg
  • når bryteren er (–jeg: 1), calc((1 – var (–))*30deg) regner ut til å (1 – 1)*30deg = 0*30deg = 0deg

Du kan se dette konseptet illustrert nedenfor:

Veksle mellom en null og en ikke-null-verdi (live demo, ingen Edge-støtte på grunn av calc – () ikke fungerer for vinkler)

For den enkelte sak av loader, vi bruker HSL-verdier for kant-farge og bakgrunn-farge. HSL står for kulør, metning, lysstyrke og kan være best representert visuelt ved hjelp av en bicone (som består av to kjegler med baser limt sammen).

HSL bicone.

Nyansene gå rundt bicone, 0° likestilt med 360° for å gi oss et rødt i begge tilfeller.

Hue hjulet.

Metning går fra 0% på den vertikale aksen av bicone til 100% på bicone overflaten. Når metning 0% (på den vertikale aksen av bicone), hue spiller ingen rolle lenger; vi får nøyaktig samme grå for alle nyanser i samme horisontale plan.

“Samme horisontale plan” betyr å ha den samme letthet, noe som øker langs den vertikale bicone aksen, som går fra 0% på black bicone toppunktet til 100% på den hvite bicone toppunktet. Når letthet er enten 0% eller 100%, verken hue eller metning rolle lenger – vi alltid får svart for en letthet verdi på 0% og hvitt for en letthet-verdi på 100%.

Siden vi trenger bare svart og hvitt for våre ☯ symbol, kulør og metning er irrelevant, så vi null dem og deretter bytte mellom svart og hvit ved å bytte letthet mellom 0% og 100%.

.yin-yang {
/* andre stiler som er irrelevant her */

og:før, &:etter {
/* andre stiler som er irrelevant her */
–jeg: 0;

/* letthet av kant-farge når
* –jeg: 0(1 – 0)*100% = 1*100% = 100% (hvit)
* –i: 1(1 – 1)*100% = 0*100% = 0% (svart) */
border: solid $d/6 hsl(0, 0%, calc((1 – var (–))*100%));

/* x-koordinaten for transform-når opprinnelse
* –jeg: 0 0*100% = 0% (venstre)
* –jeg: 1 1*100% = 100% (til høyre) */
transform-opprinnelse: calc(var (–)*100%) 50%;

/* letthet av bakgrunn-farge når
* –jeg: 0 0*100% = 0% (svart)
* –jeg: 1 1*100% = 100% (hvit) */
bakgrunn: hsl(0, 0%, calc(var (–)*100%));

/* animasjon-forsinkelse når
* –jeg: 0 0*-$t = 0s
* –jeg: 1 1*-$t = -$t */
animasjon: s $t letthet-i-ut calc(var (–)*#{- $t}) uendelig alternativ;
}

og:etter { –jeg: 1 }
}

Merk at denne tilnærmingen ikke fungerer i Kanten på grunn av det faktum at Kanten ikke støtter calc() verdier for animasjon-forsinkelse.

Men hva hvis vi ønsker å ha en ikke-null verdi når bryteren er slått av (–jeg: 0) og annen annen ikke-null verdi når bryteren er på (–jeg: 1)?

Veksling mellom to ikke-null-verdier

La oss si at vi ønsker et element å ha en grå bakgrunn (#ccc) når bryteren er slått av (–jeg: 0) og en oransje bakgrunn (#f90) når bryteren er på (–jeg: 1).

Det første vi gjør er bytte fra hex til et mer håndterlig format som rgb() eller hsl().

Vi kan gjøre dette manuelt, enten ved hjelp av et verktøy som for eksempel Lea Verou er CSS Farger eller via DevTools. Hvis vi har en bakgrunn satt på et element vi kan bla gjennom formater ved å holde Shift-tasten nede mens du klikker på torget (eller sirkel) i front av verdien i DevTools. Dette fungerer i både Chrome og Firefox, selv om det ikke ser ut til å virke i Kanten.

Endre formatet fra DevTools.

Enda bedre, hvis vi bruker Sass, vi kan pakke ut komponentene med rødt()/ grønt()/ blå() eller fargetone()/ saturation()/ lyshet() funksjoner.

Mens rgb() kan bli bedre kjent format, for jeg har en tendens til å foretrekke hsl() fordi jeg synes det er mer intuitivt og det er lettere for meg å få en idé om hva du kan forvente visuelt bare ved å se på koden.

Så vi trekke ut de tre komponentene av hsl () – ekvivalenter av våre to verdier ($c0: #ccc når bryteren er av og $c1: #f90 når bryteren er på) ved å bruke disse funksjonene:

$c0: #ccc;
$c1: #f90;

$h0: runde(hue($c0)/1deg);
$s0: runde(metning($c0));
$l0: runde(lightness($c0));

$h1: runde(hue($c1)/1deg);
$s1: runde(metning($c1));
$l1: runde(lightness($c1))

Merk at vi har samlet resultatene av kulør (hue), metning() og lyshet() funksjoner som de kan gå tilbake mye av desimaler og vi ønsker å holde våre generert kode ren. Vi har også delt resultatet av fargetone () – funksjonen ved 1deg, så den returnerte verdien er en viss verdi i denne saken, og Kanten bare støtter enhet- / mindre verdier inne i CSS hsl () – funksjonen. Normalt, når du bruker Sass, kan vi ha grad verdier, ikke bare unit-mindre de for hue inni hsl () – funksjonen, fordi Sass behandler det som Sass hsl () – funksjonen, som blir kompilert til en CSS-hsl () – funksjonen med en enhet-mindre hue. Men her, vi har en dynamisk CSS variabel inne, så Sass behandler denne funksjonen som CSS hsl () – funksjonen som ikke blir samlet inn noe annet, så hvis hue har en enhet, dette kan ikke bli fjernet fra den genererte CSS.

Nå har vi at:

  • hvis bryteren er slått av (–jeg: 0), vår bakgrunn er
    hsl($h0, $s0, $l0)
  • hvis bryteren er på (–jeg: 1), vår bakgrunn er
    hsl($h1, $s1, $l1)

Vi kan skrive våre to bakgrunner som:

  • hvis bryteren er slått av (–jeg: 0),
    hsl(1*$h0 + 0*$h1, 1*$s0 + 0*$s1, 1*$l0 + 1*$l1)
  • hvis bryteren er på (–jeg: 1),
    hsl(0*$h0 + 1*$h1, 0*$s0 + 1*$s1, 0*$l0 + 1*$l1)

Ved hjelp av bryteren variabel-jeg, vi kan forene de to tilfellene:

–j: calc(1 – var (–));
bakgrunn: hsl(calc(var(–j)*#{$h0} + var (–)*#{$h1}),
calc(var(–j)*#{$s0} + var (–)*#{$s1}),
calc(var(–j)*#{$l0} + var (–)*#{$l1}))

Her har vi merket med –j utfyllende verdien av –jeg (når –0, –j er 1, og når –jeg er 1, –j er 0).

Veksling mellom to bakgrunner (live demo)

Formelen ovenfor fungerer for å bytte i mellom to HSL-verdier. Imidlertid, i dette tilfellet, kan vi forenkle det fordi vi har en ren grå når bryteren er slått av (–jeg: 0).

Rent grå verdier har samme røde, grønne og blå verdier når man tar hensyn til RGB-modellen.

Når du tar hensyn til HSL-modell, kulør er irrelevant (vår grå ser den samme for alle nyanser), metning (saturation) er alltid 0%, og det er bare letthet saker som bestemmer hvor lys eller mørk vår grå.

I denne situasjonen, kan vi alltid holde hue av den ikke-grå verdi (den vi har for “på” – saken, $h1).

Siden metning av noen grå verdi (den vi har for “off” tilfellet $s0) er alltid 0%, multiplisere det med enten 0 eller 1 gir oss alltid 0%. Så, gitt at det var(–j)*#{$s0} begrep i vår formel er alltid 0%, kan vi bare droppe det og våre metning formel reduserer til produktet mellom metning av “på” case $s1 og slå variabel –jeg.

Dette forlater letthet som den eneste komponenten der vi trenger fortsatt å gjelde hele formelen.

–j: calc(1 – var (–));
bakgrunn: hsl($h1,
calc(var (–)*#{$s1}),
calc(var(–j)*#{$l0} + var (–)*#{d1l}))

Ovenfor kan bli testet i denne demoen.

På samme måte, la oss si at vi ønsker font-størrelsen på tekst å være 2rem når våre bryteren er av (–jeg: 0) og 10vw når bryteren er på (–jeg: 1). Å bruke samme metode, har vi:

font-size: calc((1 – var (–))*2rem + var (–)*10vw)

Veksling mellom to skriftstørrelser (live demo)

Ok, la oss nå gå videre til å oppklare et annet aspekt av dette: hva er det egentlig som gjør at bryteren for å snu fra på til av eller den andre veien rundt?

Hva som utløser bytte

Vi har noen alternativer her.

Element-basert bytte

Dette betyr at bryteren er av for visse elementer og andre elementer. Dette kan For eksempel være bestemt av paritet. La oss si vi ønsker alle selv elementer som skal roteres og har en oransje bakgrunn i stedet for den opprinnelige grå en.

.boksen {
–jeg: 0;
–j: calc(1 – var (–));
forvandle: rotere(calc(var (–)*30deg));
bakgrunn: hsl($h1,
calc(var (–)*#{$s1}),
calc(var(–j)*#{$l0} + var (–)*#{$l1}));

og:nth-child(2n) { –jeg: 1 }
}

Bytte utløst av elementet paritet (live demo, ikke fullt funksjonell i Kanten på grunn av calc – () ikke fungerer for vinkler)

I paritet tilfelle vi slå bryteren på for hvert sekund element (:nth-child(2n)), men vi kan også snu det på for hver syvende element (:nth-child(7n)), for de to første elementene (:nth-child(-n + 2)), for alle elementer unntatt den første og to siste (:nth-child(n + 3):nth-siste-barn(n + 3)). Vi kan også snu det på bare for overskrifter eller bare for elementer som har en bestemt egenskap.

State-basert bytte

Dette betyr at bryteren er av når elementet i seg selv (eller en forelder eller en av sine tidligere søsken) er i en tilstand og av når det er en annen stat. I den interaktive eksempler fra forrige avsnitt, og slå ble snudd når en avmerkingsboks før vår element fikk kontrollert eller ukontrollert.

Vi kan også ha noe som en hvit link som kan skaleres opp og oransje når det fokusert eller svevde:

$c: #f90;

$h: runde(hue($c)/1deg);
$s: runde(metning($c));
$l: runde(lightness($c));

en {
–jeg: 0;
forvandle: skala(calc(1 + var (–)*.25));
farge: hsl($t, $s, calc(var (–)*#{$l} + (1 – var (–))*100%));

og:fokus, &:hover { –jeg: 1 }
}

Siden hvit er noen hsl () – verdi med en letthet av 100% (kulør og metning er irrelevant), kan vi forenkle ting ved alltid å holde kulør og metning av :fokus/ :hold staten og bare endre letthet.

Bytte utløst av staten endres (live demo, ikke fullt funksjonell i Kanten på grunn av calc() verdier ikke blir støttet inside-skala() funksjoner)

Media query-basert bytte

En annen mulighet er at det å slå er utløst av en media query, for eksempel, når retningen endres eller når du går fra ett vindu område til et annet.

La oss si vi har en hvit overskriften med en skrift-størrelse på 1rem opp til 320px, men så viser det oransje ($c) og font-size blir 5vw og starter skalering med viewport bredde.

h5 {
–jeg: 0;
farge: hsl($t, $s, calc(var (–)*#{$l} + (1 – var (–))*100%));
font-size: calc(var (–)*5vw + (1 – var (–))*1rem);

@media (min-width: 320px) { –jeg: 1 }
}

Bytte utløst av viewport endre (live demo)

Koding er en mer komplisert eksempel fra scratch

Eksempelet vi dissekere her er at av de utvide søket vises i begynnelsen av denne artikkelen, som er inspirert av denne Pennen, som du burde virkelig sjekke ut fordi koden er ganske jævla smart.

Utvide søket.

Vær oppmerksom på at fra en brukervennlighet synspunkt, å ha et slikt søk-boksen på et nettsted er kanskje ikke den beste ideen som man normalt ville forvente knappen følgende søkefeltet til å utløse søk, ikke lukke søkefeltet, men det er fortsatt en interessant koding øvelse, som er grunnen til at jeg har valgt å dissekere det her.

Til å begynne med, min idé var å gjøre det bare ved hjelp form elementer. Så, HTML-strukturen ser ut som dette:

<input id=’søk-btn’ type=’boksen’/>
<label for=’søk-btn’>Vis søk bar</label>
<input id=’søk-bar’ type=’tekst’ plassholder=’Søk…’/>

Hva vi gjør her er i utgangspunktet skjule inntasting av tekst og trykk deretter avsløre det når avmerkingsboksen før det blir sjekket — la oss dykke inn i hvordan det fungerer!

First off, kan vi bruke et enkelt tilbakestille og sette en flex-layout på beholderen av våre innspill og merking. I vårt tilfelle, denne beholderen er kroppen, men det kan være et annet element. Vi har også absolutt posisjon i boksen, og flytte det ut av syne (utenfor vinduet).

*, :før :etter {
safe-dimensjonering: border-box;
margin: 0;
padding: 0;
skrifttype: arve
}

html { overløp-x: hidden }

body {
skjerm: flex;
juster-elementer: center;
rettferdiggjøre-innhold: center;
margin: 0 auto;
min. bredde: 400px;
min høyde: 100vh;
bakgrunn: #252525
}

[id=’søk-btn’] {
position: absolute;
venstre: -100vh
}

Så langt, så godt…

Se Pennen av thebabydino (@thebabydino) på CodePen.

Hva så? Vi må innrømme at det er ikke spennende i det hele tatt, så la oss gå videre til neste trinn!

Vi slår avmerkingsboksen etiketten i en stor runde, grønne knappen og flytte tekst-innhold, ute av syne med en stor negativ verdsettes tekst-innrykk og overflow: hidden.

$btn-d: 5em;

/* samme som før */

[for=’søk-btn’] {
overflow: hidden;
bredde: $btn-d;
høyde: $btn-d;
border-radius: 50%;
box-shadow: 0 0 1.5 em rgba(#000, .4);
bakgrunn: #d9eb52;
tekst-strekpunkt: -100vw;
cursor: pointer;
}

Se Pennen av thebabydino (@thebabydino) på CodePen.

Neste, vi polsk selve søkefeltet av:

  • gir det eksplisitte mål
  • å gi en bakgrunn for normal tilstand
  • å definere en annen bakgrunn og en glød for sin fokusert tilstand
  • avrunding av hjørner på venstre side ved hjelp av en border-radius som tilsvarer halvparten av sin høyde
  • Rydde opp litt plassholder

$btn-d: 5em;
$bar-b: 4*$btn-d;
$bar-h: .65*$btn-d;
$bar-r: .5*$bar-h;
$bar-c: #ffeacc;

/* samme som før */

[id=’søk-bar’] {
ramme: ingen;
padding: 0 1em;
bredde: $bar-w;
høyde: $bar-h;
border-radius: $bar-r 0 0 $bar-r;
bakgrunn: #3f324d;
color: #fff;
skrifttype: 1em århundre gotiske, verdana, arial, sans-serif;

&::plassholder {
dekkevne: .5;
farge: arve;
font-size: .875em;
brev-avstand: 1px;
text-shadow: 0 0 1px, 0 0 2px
}

og:fokus {
disposisjon: ingen;
box-shadow: 0 0 1.5 em $bar-c, 0 1.25 em 1.5 em rgba(#000, .2);
bakgrunn: $bar-c;
color: #000;
}
}

Se Pennen av thebabydino (@thebabydino) på CodePen.

På dette punktet, høyre kant av søkefeltet sammenfaller med den venstre kanten av-knappen. Men vi ønsker en bit av overlapping — la oss si en overlapping slik at den rette kanten av søkefeltet sammenfaller med på knappen ‘ s vertikale midtlinjen. Gitt at vi har en flexbox layout med rett-elementer: center på beholderen (kroppen i vårt tilfelle), forsamlingen består av våre to elementer (baren og knappen) fortsatt er midt-på linje horisontalt selv om vi sett en margin på den ene eller den andre eller begge i mellom disse elementene. (På venstre side av venstre element eller på høyre side av det siste elementet er en annen historie, men vi vil ikke være å komme inn på det nå.)

Opprette overlapper hverandre, holde justering (live demo).

Det er en overlapping av .5*$btn-d minus en halv knappen diameter, noe som tilsvarer knappen er radius. Setter vi dette som en negativ margin-rett på bar. Vi har også justere polstring på høyre side av linjen slik at vi kompenserer for overlapp:

$btn-d: 5em;
$btn-r: .5*$btn-d;

/* samme som før */

[id=’søk-bar’] {
/* samme som før */
margin-right: -$btn-r;
padding: 0 calc(#{$btn-r} + 1em) 0 1em;
}

Vi har nå bar og knappen i posisjoner for utvidet state:

Se Pennen av thebabydino (@thebabydino) på CodePen.

Bortsett fra baren følger knappen i DOM-rekkefølge, så det er plassert på toppen av det, når vi faktisk ønsker knappen på toppen. Heldigvis, dette er lett å fikse (i hvert fall for nå — det vil ikke være nok senere, men la oss håndtere en sak på en gang).

[for=’søk-btn’] {
/* samme som før */
position: relative;
}

Nå som vi har gitt knappen et ikke-statisk posisjon verdi, det er på toppen av bar:

Se Pennen av thebabydino (@thebabydino) på CodePen.

I denne tilstanden, vil den totale bredden på bar og knappen for montering er bar bredde $bar-w pluss-knappen radius $btn-r (som er halvparten knappen diameter $btn-d) fordi vi har en overlapp for halve knappen. I sammenslått tilstand, er den totale bredde av forsamlingen er bare på knappen diameter $btn-d.

Utvidet vs. havarert stat (live).

Siden vi ønsker å beholde den samme sentrale aksen når du går fra utvidet til havarert stat, vi trenger å skifte knappen til venstre for halve forsamlingen bredde i det utvidede state (.5*($bar-w + $btn-r)) minus-knappen radius ($btn-r).

Vi kaller dette skiftet $x og vi bruker det med minus på-knappen (siden vi shift-knappen til venstre og venstre er negativ retning på x-aksen). Siden vi ønsker baren for å trekke i knappen, og vi har satt den samme skift $x på det, men i positiv retning (som vi shift stolpen til høyre på x-aksen).

Vi er i sammenslått tilstand når avmerkingsboksen ikke er merket, og i utvidet tilstand når det ikke er det. Dette betyr at vår bar og knappen er flyttet med en CSS transformere når avmerkingsboksen ikke er merket, og i den posisjon vi i dag har dem i (ingen transform) når avmerkingsboksen er merket av.

For å gjøre dette, har vi sett en variabel –jeg på følgende elementer vår avmerkingsboksen — knappen (opprettet med merket for avmerkingsboksen) og søk bar. Denne variabelen er 0 i sammenslått tilstand (når begge elementene er flyttet og boksen er ikke sjekket) og 1 i utvidet tilstand (når vår bar og knappen er i posisjoner de for tiden opptar, ingen skift, og boksen er avmerket).

$x: .5*($bar-w + $btn-r) – $btn-r;

[id=’søk-btn’] {
position: absolute;
venstre: -100vw;

~ * {
–jeg: 0;
–j: calc(1 – var (–)) / * 1 når –jeg er 0, 0 når –jeg er 1 */
}

og:sjekket ~ * { –jeg: 1 }
}

[for=’søk-btn’] {
/* samme som før */
/* hvis-jeg er 0, –j 1 => vår oversettelse beløpet er -$x
* hvis-jeg er 1, –j 0 => vår oversettelse beløpet er 0 */
forvandle: translate(calc(var(–j)*#{-$x}));
}

[id=’søk-bar’] {
/* samme som før */
/* hvis-jeg er 0, –j 1 => vår oversettelse beløpet er $x
* hvis-jeg er 1, –j 0 => vår oversettelse beløpet er 0 */
forvandle: translate(calc(var(–j)*#{$x}));
}

Og nå har vi noe interaktiv! Ved å klikke på knappen veksler avmerkingsboksen state (fordi knappen har blitt laget ved hjelp av etiketten på avmerkingsboksen).

Se Pennen av thebabydino (@thebabydino) på CodePen.

Bortsett fra nå-knappen er litt vanskelig å klikk, siden det er under skriving igjen (fordi vi har sett en transformering på bar og dette etablerer en stabling sammenheng). Løsningen er ganske enkel — vi trenger å legge til en z-index-knappen og dette flytter det over baren.

[for=’søk-btn’] {
/* samme som før */
z-index: 1;
}

Se Pennen av thebabydino (@thebabydino) på CodePen.

Men vi har fortsatt enda større problem: vi kan se bar som kommer ut fra under knappen på høyre side. For å fikse dette, har vi sett klipp-banen med en innfelt () – verdi på bar. Dette angir et utklipp rektangel med hjelp av avstander fra topp, høyre, bunn og venstre kanter av elementet grensen til-boksen. Alt utenfor dette klipping rektangel blir kuttet ut og bare hva som er inni vises.

Hvordan inset () – funksjonen fungerer (live).

I illustrasjonen ovenfor, hver distanse er å gå innover fra kanten av grensen-boksen. I dette tilfellet, de er positive. Men de kan også gå utover, i hvilket tilfelle de er negative og tilhørende kanter av klipping rektangel er utenfor element grensen til-boksen.

Ved første, du kan tro vi hadde ingen grunn til å noensinne gjøre det, men i vårt tilfelle, det gjør vi!

Vi ønsker avstandene fra toppen (dt), bunnen (db) og venstre (dl) for å være negativ og stor nok til å inneholde box-shadow som strekker seg utenfor element grensen til-boksen i :fokus staten som vi ikke vil at den skal bli klippet ut. Så løsningen er å opprette et utklipp rektangel med kantene utenfor element grensen til-boksen i disse tre retningene.

Avstanden fra høyre (dr) er full bar bredde $bar-b minus a-knappen radius $btn-r i skjult tilfelle (avmerkingsboksen ikke er merket, –jeg: 0) og 0 i utvidet tilfelle (huket av, –jeg: 1).

$ut-d: -3em;

[id=’søk-bar’] {
/* samme som før */
klipp-bane: inset($ut-d calc(var(–j)*#{$bar-w – $btn-r}) $ut-d $ut-d);
}

Vi har nå et søk bar og knappen for montering som utvider seg og kollapser på å klikke på knappen.

Se Pennen av thebabydino (@thebabydino) på CodePen.

Siden vi ikke ønsker en brå endring i mellom de to stater, er vi bruke en overgang:

[id=’søk-btn’] {
/* samme som før */

~ * {
/* samme som før */
overgang: .65s;
}
}

Vi ønsker også våre knappen bakgrunn til å være grønn i den sammenraste tilfelle (avmerkingsboksen ikke er merket, –jeg: 0) og rosa i utvidet tilfelle (huket av, –jeg: 1). For dette, kan vi bruke samme teknikk som før:

[for=’søk-btn’] {
/* samme som før */
$c0: #d9eb52; // grønt for havarert stat
$c1: #dd1d6a; // rosa for utvidet staten
$h0: runde(hue($c0)/1deg);
$s0: runde(metning($c0));
$l0: runde(lightness($c0));
$h1: runde(hue($c1)/1deg);
$s1: runde(metning($c1));
$l1: runde(lightness($c1));
bakgrunn: hsl(calc(var(–j)*#{$h0} + var (–)*#{$h1}),
calc(var(–j)*#{$s0} + var (–)*#{$s1}),
calc(var(–j)*#{$l0} + var (–)*#{$l1}));
}

Nå er vi å få et sted!

Se Pennen av thebabydino (@thebabydino) på CodePen.

Det vi fortsatt trenger å gjøre er å opprette ikonet som morphs mellom et forstørrelsesglass i havarert stat og en “x” i utvidet staten for å indikere en avsluttende handling. Dette gjør vi med det :før :etter pseudo-elementer. Vi begynner med å bestemme på en diameter for forstørrer og hvor mye av dette diameter bredde på ikonet linjene representerer.

$ico-d: .5*$bar-h;
$ico-f: .125;
$ico-w: $ico-f*$ico-d;

Vi absolutt posisjon både pseudo-elementer i midten av knappen å ta sine mål i betraktning. Vi så gjøre dem arver sine foreldres overgang. Vi gir :før en bakgrunn, da dette vil være håndtaket på våre forstørrelsesprogram, kan du gjøre :etter runde med border-radius og gi det en innfelt box-shadow.

[for=’søk-btn’] {
/* samme som før */

og:før, &:etter {
position: absolute;
øverst: 50%; left: 50%;
marg: -.5*$ico-d;
bredde: $ico-d;
høyde: $ico-d;
overgang: arve;
innhold:”
}

og:før {
margin-top: -.4*$ico-w;
høyde: $ico-w;
bakgrunn: currentColor
}

og:etter {
border-radius: 50%;
box-shadow: 0 0 0 $ico-w currentColor
}
}

Vi kan nå se forstørrer komponenter på knappen:

Se Pennen av thebabydino (@thebabydino) på CodePen.

For å gjøre våre ikonet for å se mer ut som et forstørrelsesglass, vi oversetter både av dets komponenter utover med en fjerdedel av forstørrelsesprogram diameter. Dette betyr å oversette håndtaket til høyre, i positiv retning på x-aksen ved .25*$ico-d og den viktigste delen til venstre, i negativ retning på x-aksen ved samme .25*$ico-d.

Vi har også skala håndtaket (: før pseudo-element) horisontalt til halv bredde med hensyn til sin høyre kant (som betyr at en transformering-opprinnelsen til 100% langs x-aksen).

Vi bare vil at dette skal skje i det skjulte state (avmerkingsboksen ikke er merket, –jeg er 0, og følgelig –j er 1), så vi multiplisere oversettelse beløp ved –j og også bruke –j til tilstand skaleringsfaktor:

[for=’søk-btn’] {
/* samme som før */

og:før {
/* samme som før */
høyde: $ico-w;
forvandle:
/* kollapset: ikke sjekket, –0, –j er 1
* oversettelse beløpet er 1*.25*$d = .25*$d
* utvidet: sjekket, –jeg er 1, –j 0
* oversettelse beløpet er 0*.25*$d = 0 */
oversette(calc(var(–j)*#{.25*$ico-d}))
/* kollapset: ikke sjekket, –0, –j er 1
* skaleringsfaktor er 1 – 1*.5 = 1 – .5 = .5
* utvidet: sjekket, –jeg er 1, –j 0
* skaleringsfaktor er 1 – 0*.5 = 1 – 0 = 1 */
scalex(calc(1 – var(–j)*.5))
}

og:etter {
/* samme som før */
forvandle: translate(calc(var(–j)*#{-.25*$ico-d}))
}
}

Vi har nå thew forstørrelsesglass-ikonet i sammenslått tilstand:

Se Pennen av thebabydino (@thebabydino) på CodePen.

Siden vi ønsker både ikonet komponenter som skal roteres ved 45deg, legger vi denne rotasjonen på selve knappen:

[for=’søk-btn’] {
/* samme som før */
forvandle: translate(calc(var(–j)*#{-$x})) roter(45deg);
}

Nå har vi det ser vi ønsker for havarert stat:

Se Pennen av thebabydino (@thebabydino) på CodePen.

Dette etterlater likevel utvidet stat, der vi trenger å slå runde :etter pseudo-element i en linje. Dette gjør vi ved å skalere det ned langs x-aksen og å bringe sin border-radius fra 50% til 0%. Den skaleringsfaktor vi bruker er forholdet mellom bredde $ico-w av linjen vi ønsker å få diameter og $ico-d i sirkelen er i sammenslått tilstand. Vi har kalt dette forholdet $ico-f.

Siden vi kun ønsker å gjøre dette i den utvidede staten, når boksen er avmerket, og-jeg er 1, vil vi gjøre både skaleringsfaktor og border-radius avhenger –og –j:

$ico-d: .5*$bar-h;
$ico-f: .125;
$ico-w: $ico-f*$ico-d;

[for=’søk-btn’] {
/* samme som før */

og:etter{
/* samme som før */
/* kollapset: ikke sjekket, –0, –j er 1
* border-radius 1*50% = 50%
* utvidet: sjekket, –jeg er 1, –j 0
* border-radius er 0*50% = 0 */
border-radius: calc(var(–j)*50%);
forvandle:
oversette(calc(var(–j)*#{-.25*$ico-d}))
/* kollapset: ikke sjekket, –0, –j er 1
* skaleringsfaktor er 1 + 0*$ico-f = 1
* utvidet: sjekket, –jeg er 1, –j 0
* skaleringsfaktor er 0 + 1*$ico-f = $ico-f */
scalex(calc(1 – var(–j)*.5))
}
}

Se Pennen av thebabydino (@thebabydino) på CodePen.

Hmm, nesten, men ikke helt. Skalering har også krympet våre inset box-shadow langs x-aksen, så la oss fikse det med en andre inset skyggen som vi bare få i utvidet tilstand (når boksen er avmerket, og-jeg er 1), og derfor, spredning og alfa avhenger –jeg:

$ico-d: .5*$bar-h;
$ico-f: .125;
$ico-w: $ico-f*$ico-d;

[for=’søk-btn’] {
/* samme som før */
–hsl: 0, 0%, 0%;
farge: HSL(var(–hsl));

og:etter{
/* samme som før */
box-shadow:
inset 0 0 0 $ico-w currentcolor,
/* kollapset: ikke sjekket, –0, –j er 1
* spre radius 0*.5*$ico-d = 0
* alpha er 0
* utvidet: sjekket, –jeg er 1, –j 0
* spre radius 1*.5*$ico-d = .5*$ico-d
* alpha er 1 */
inset 0 0 0 calc(var (–)*#{.5*$ico-d}) HSLA(var(–hsl), var (–))
}
}

Dette gir oss det endelige resultatet!

Se Pennen av thebabydino (@thebabydino) på CodePen.

Noen raske eksempler

Følgende er noen flere demoer som bruker samme teknikk. Vi vil ikke være å bygge disse fra scratch — vi skal bare gå gjennom de grunnleggende ideene bak dem.

Responsive bannere

Skjermbilde collage (live demo, ikke fullt funksjonell i Kanten på grunn av bruk av en calc – () verdi for skrift-størrelse).

I dette tilfellet, våre faktiske elementer er mindre rektangler i front, mens antall ruter og større rektangler i ryggen er skapt med det :før :etter pseudo-elementer, henholdsvis.

På bakgrunn av antall firkanter er individuelle og satt med en stopp list-variabelen –slist som er forskjellige for hvert element.

<p style=’–slist: #51a9ad, #438c92′><!– 1. avsnitt tekst –></p>
<p style=’–slist: #ebb134, #c2912a’><!– 2. avsnitt tekst –></p>
<p style=’–slist: #db4453, #a8343f’><!– 3. avsnitt tekst –></p>
<p style=’–slist: #7eb138, #6d982d’><!– 4. avsnitt tekst –></p>

De tingene som påvirker stiler på bannere er det paritet og om vi er i den brede, normal eller smal sak. Disse gir oss vår bytte variabler:

html {
–de smale og: 0;
–comp: calc(1 – var(–de smale og));
–bredt: 1;

@media (maks bredde: 36em) { –bredt: 0 }

@media (maks bredde: 20em) { –de smale og: 1 }
}

p {
–paritet: 0;

og:nth-child(2n) { –paritet: 1 }
}

Antall ruter er absolutt posisjonert, og plasseringen avhenger av paritet. Hvis –paritet-bryteren er slått av (0), så de er på venstre. Hvis den er på (1), så de er på høyre side.

En verdi av venstre: 0% på linje med den venstre kanten av tallet, langs den venstre kanten av morselskapet, mens en verdi av venstre: 100% justerer sin venstre kant langs foreldrenes høyre kant.

For å ha rett kant av tallet på linje med høyre kant av sine foreldre, må vi trekke fra sin egen bredde ut av tidligere 100% – verdien. (Husk at % – verdier i tilfelle av reduksjoner er i forhold til overordnede mål.)

venstre: calc(var(–paritet)*(100% – #{$num-d}))

…hvor $num-d er størrelsen på nummerering square.

I den brede skjermen tilfellet, kan vi også presse nummereringen ut av 1em — dette betyr trekke 1em fra offset så langt har vi for odd elementer (ha –paritet slå av) og legge til 1em offset så langt har vi for enda elementer (ha –paritet slå på).

Nå er spørsmålet her er… hvordan gjør vi bytter fortegn? Den enkleste måten å gjøre det på er ved å bruke krefter på -1. Dessverre, vi har ikke en power-funksjonen (eller en power operatør) i CSS, selv om det ville være svært nyttig i dette tilfellet:

/*
* for-paritet: 0, har vi pow(-1, 0) = +1
* for-paritet: 1, vi har pow(-1, 1) = -1
*/
pow(-1, var(–paritet))

Dette betyr at vi har å gjøre det arbeidet med hva vi har (addisjon, subtraksjon, multiplikasjon og divisjon) og som fører til en merkelig liten formel… men, hey, det fungerer!

/*
* for-paritet: 0, har vi 1 – 2*0 = 1 – 0 = +1
* for-paritet: 1, vi har 1 – 2*1 = 1 – 2 = -1
*/
–sign: calc(1 – 2*var(–paritet))

På denne måten, er vårt endelige formelen for venstre offset, tar hensyn til både paritet og om vi er i den store saken (–bredt: 1) eller ikke (–bredt: 0), blir:

venstre: calc(var(–paritet)*(100% – #{$num-d}) – var(–bredt)*var(–sign)*1em)

Vi har også kontroll bredden av paragrafer med disse variablene og maks bredde som vi vil ha det å ha en øvre grense og bare fullt ut dekke sine foreldre horisontalt i smal sak (–de smale og: 1):

bredde: calc(var(–comp)*80% + var(–de smale og)*100%);
maks bredde: 35em;

Font-størrelse avhenger også av om vi er i smal sak (–de smale og: 1) eller ikke (–de smale og: 0):

calc(.5rem + var(–comp)*.5rem + var(–de smale og)*2vw)

…og så gjøre den horisontale forskyvninger for :etter pseudo-element (større rektangel på baksiden) som de er 0 i smal sak (–de smale og: 1) og en ikke-null offset $off-x ellers (–de smale og: 0):

høyre: calc(var(–comp (fri -)*#{$off-x});
venstre: calc(var(–comp (fri -)*#{$off-x});
Hover og fokus effekter

Effekten opptak (live demo, ikke fullt funksjonell i Kanten på grunn av nestede calc() bug).

Denne effekten er laget med en link-elementet og dens to pseudo-elementer skyve diagonalt på :hover og :fokus stater. Link ‘ s mål er fast, og så er de av sine pseudo-elementer, satt til den diagonale av sine overordnede $btn-d (beregnet som hypotenuse i høyre triangelet som, formes av en bredde og en høyde) horisontalt og foreldrenes høyde vertikalt.

Av :før du er plassert slik at dens nedre venstre hjørne faller sammen som sin forelder, mens den :når du er posisjonert slik at de øverste høyre hjørne sammenfaller med sin overordnede. Siden begge skal ha samme høyde som foreldrene sine, vertikal plassering er løst ved å sette øverst: 0 og bunn: 0. Den horisontale plasseringen er behandlet i nøyaktig på samme måte som i forrige eksempel, bruker –jeg som bytter variabel som endrer verdi mellom de to pseudo-elementer og –j, sin komplementære (calc(1 – var (–))):

venstre: calc(var(–j)*(100% – #{$btn-d}))

Vi satt transform-opprinnelse :før du til venstre nederst i hjørnet (0% 100%) og :etter sin høyre øverste hjørne (100% 0%), igjen, med hjelp av bryteren-jeg og dens utfyllende –j:

transform-opprinnelse: calc(var(–j)*100%) calc(var (–)*100%)

Vi roterer både pseudo-elementer til vinkelen mellom diagonale og horisontale $btn-en (også regnet ut fra det triangelet som, formes av en høyde og bredde, som arctangens av forholdet mellom de to). Med denne rotasjonen, vil den horisontale kantene møtes langs diagonalen.

Vi så skift dem ut av sin egen bredde. Dette betyr at vi vil bruke et annet tegn for hver av de to, igjen avhengig bytte variabel som endrer verdi i mellom :før :etter, akkurat som i forrige eksempel med bannere:

forvandle: rotere($btn-a) oversett(calc((1 – 2*var (–))*100%))

I :hover og :fokus stater, denne oversettelsen har behov for å gå tilbake til 0. Dette betyr at vi multiplisere mengden av oversettelsen over av komplementære –q-bryteren variabel –p som er 0 i normal tilstand og 1 i :hover eller :fokus state:

forvandle: rotere($btn-a) oversett(calc(var(–q)*(1 – 2*var (–))*100%))

For å gjøre pseudo-elementer skyv ut den andre veien (ikke tilbake den veien de kom inn) på mus-ut eller blir ute av fokus, vi setter bryteren variabel –jeg til verdien av –p for :før og til verdien av –q :etter, reversere tegn på oversettelsen, og sørge for at vi bare overgangen forvandle eiendommen.

Responsive infographic

Skjermbilde collage med linjene i rutenettet og hull markert (live demo, ingen Edge-støtte på grunn av CSS variabel og calc() bugs).

I dette tilfellet har vi en tre-rad, to-kolonne rutenett for hvert element (artikkelen element), med den tredje raden kollapset den brede skjermen scenariet og den andre kolonnen kollapset i den smale skjermen scenario. I den brede skjermen scenario, breddene av kolonnene avhenger av paritet. I den smale skjermen scenario, den første kolonnen spenner over hele innhold-boksen av element og den andre har bredde 0. Vi har også et gap i mellom kolonnene, men bare i den brede skjermen scenario.

// formler for kolonnene i den brede skjermen tilfelle, hvor
// $col-en-brede er for andre nivået overskriften + avsnitt
// $col-b-brede er for det første nivået overskriften
$col-1-wide: calc(var(–q)*#{$col-en-bredt} + var(–p)*#{$col-b-bredt});
$col-2-wide: calc(var(–q)*#{$col-b-bredt} + var(–p)*#{$col-en-bredt});

// formler for det generelle tilfellet, og kombinerer det store og vanlige scenarier
$rad-1: calc(var (–)*#{$rad-1-bredt} + var(–j)*#{$rad-1-norm});
$rad-2: calc(var (–)*#{$rad-2-bredt} + var(–j)*#{$rad-2-norm});
$row-3: minmax(0, auto);
$col-1: calc(var (–)*#{$col-1-bredt} + var(–j)*#{$col-1-norm});
$col-2: calc(var (–)*#{$col-2-bredt});

$kunst-g: calc(var (–)*#{$kunst-g-bredt});

html {
–jeg: var(–bredt, 1); // 1 i den brede skjermen sak
–j: calc(1 – var (–));

@media (maks bredde: $kunst-w-bred + 2rem) { –bredt: 0 }
}

artikkelen {
–s: var(–paritet, 0);
–q: calc(1 – var(–p));
–s: calc(1 – 2*var(–p));
visning: rutenett;
grid-mal: #{$rad-1} #{$rad-2} #{$row-3}/ #{$col-1} #{$col-2};
grid-gap: 0 $kunst-g;
grid-auto-flow: kolonne tett;

og:nth-child(2n) { –paritet: 1 }
}

Siden vi har sett grid-auto-flow: kolonne tett, vi kan komme unna med å bare sette det første nivået overskriften for å dekke en hel kolonne (andre en for odd elementer og første for selv elementer) i den store skjermen på saken og la det andre nivået overskrift og avsnitt tekst fylle den første gratis tilgjengelig celler.

// bredt tilfelle, odd elementer: – jeg er 1, –p er 0, –q 1
// vi er på kolonnen 1 + 1*1 = 2
// bredt tilfelle, selv elementer: – jeg er 1, –p er 1, –q 0
// vi er på kolonnen 1 + 1*0 = 1
// trange saken: – jeg er 0, så var (–)*var(–q) er 0, og vi er på kolonne 1 + 0 = 1
grid-kolonnen: calc(1 + var (–)*var(–q));

// alltid starte fra første rad
// span 1 + 2*1 = 3 rader i den brede skjermen tilfelle (–jeg: 1)
// span 1 + 2*0 = 1 rad annet (–jeg: 0)
grid-rad: 1/ span calc(1 + 2*var (–));

For hvert element, et par andre egenskaper avhenger av om vi er i den brede skjermen scenario eller ikke.

Den vertikale margin, vertikal og horisontal polstring verdier, box-shadow-forskyvning og uskarphet er alt større i den brede skjermen saken:

$kunst-mv: calc(var (–)*#{$kunst-mv-bredt} + var(–j)*#{$kunst-mv-norm});
$kunst-pv: calc(var (–)*#{$kunst-pv-bredt} + var(–j)*#{$kunst-p-norm});
$kunst-tlf.: calc(var (–)*#{$kunst-ph-bredt} + var(–j)*#{$kunst-p-norm});
$kunst-sh: calc(var (–)*#{$kunst-sh-bredt} + var(–j)*#{$kunst-sh-norm});

artikkelen {
/* andre stiler */
margin: $kunst-mv auto;
polstring: $kunst-pv $kunst-ph;
box-shadow: $kunst-sh $kunst-sh calc(3*#{$kunst-sh}) rgba(#000, .5);
}

Vi har en ikke-null border-width og border-radius i den brede skjermen saken:

$kunst-b: calc(var (–)*#{$kunst-b-bredt});
$kunst-r: calc(var (–)*#{$kunst-r-bredt});

artikkelen {
/* andre stiler */
border: solid $kunst-b transparent;
border-radius: $kunst-r;
}

I den brede skjermen scenario, vi begrense elementer’ bredde, men la det være 100% ellers.

$kunst-w: calc(var (–)*#{$kunst-w-bred} + var(–j)*#{$kunst-w-norm});

artikkelen {
/* andre stiler */
bredde: $kunst-w;
}

Retning av padding-boksen gradient også endringer med paritet:

bakgrunn:
linear-gradient(calc(var(–s)*90deg), #e6e6e6, #ececec) padding-safe, lydisolering,
linear-gradient(til høyre nederst, #fff, #c8c8c8) border-box;

På en lignende måte, margin, border bredde, padding, bredde, border-radius, bakgrunn gradient retning, font-size-eller linje-høyde for overskrifter og avsnitt tekst også avhenge av om vi er i den brede skjermen scenario eller ikke (og, i tilfelle av det første nivået overskriften er border-radius eller gradient bakgrunn retning, også på paritet).