Uklare Grenser i CSS

0
15

Si at vi ønsker å målrette et element og bare visuelt visker ut grensen av det. Det er ingen enkel, enkel innebygd web-plattformen har vi kan strekke seg etter. Men vi kan få det gjort med litt CSS lureri.

Her er hva vi er ute etter:

Ønsket resultat.

La oss se hvordan vi kan kode denne effekten, hvordan vi kan forbedre den med avrundede hjørner, utvide støtte, slik det fungerer kryss-nettleser, hva fremtiden vil bringe i denne avdelingen, og hva andre interessante resultater vi kan få starte fra samme idé!

Koding grunnleggende uklare grensen

Vi starter med et element som vi har satt noen dummy dimensjoner, en delvis gjennomsiktig (kun litt synlig) grensen, og har en bakgrunn som størrelsen er i forhold til border-box, men hvis synlighet vi begrense til padding-boksen:

$b: 1.5 em; // border-width

div {
border: solid $b rgba(#000, .2);
høyde: 50vmin;
maks bredde: 13em;
maks høyde: 7em;
bakgrunn: url(oranges.jpg) 50%/ cover
border-box /* background-origin */
padding-box /* bakgrunn-clip */;
}

Boksen er angitt av background-origin er den boksen som har øvre venstre hjørne er det 0 0 punkt for background-position og også den boksen som bakgrunn-størrelse (satt til å dekke i vårt tilfelle) er i forhold til. Boksen er angitt av bakgrunn-klipp er safe i som begrenser bakgrunn som er synlig.

De opprinnelige verdiene er padding-boksen for background-origin and border-box for bakgrunnen-klipp, så vi trenger å angi dem begge i denne saken.

Hvis du trenger en mer i dybden oppfriskning på bakgrunn opprinnelse og bakgrunn-klippet, kan du sjekke ut denne detaljert artikkel om emnet.

Koden over gir oss følgende resultat:

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

Neste, vil vi legge til en absolutt posisjonert pseudo-element som dekker hele sin forelder, border-box, og er plassert bak (z-index: -1). Vi også gjøre denne pseudo-element arve sine foreldres ramme og bakgrunn, så vi endre grensen-farge gjennomsiktige og bakgrunn-klipp til grensen-boksen:

$b: 1.5 em; // border-width

div {
position: relative;
/* samme stiler som før */

og:før {
position: absolute;
z-index: -1;
/* gå utenfor padding-boks ved
* en border-width ($b) i hver retning */
øverst: -$b; høyre: -$b; nederst: -$b; venstre: -$b;
grensen: arve;
border-color: transparent;
bakgrunn: arve;
bakgrunn-klipp: border-box;
innhold:”
}
}

Nå kan vi også se bakgrunnen bak knapt synlig ramme:

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

Alright, kan det hende du ser allerede hvor dette går! Neste trinn er å blur() pseudo-element. Siden denne pseudo-elementet er bare synlig bare under delvis gjennomsiktig ramme (resten er dekket av sine foreldre padding-safe-begrenset bakgrunn), er det resultater grenseområdet er det eneste området av bildet vi ser uskarpt.

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

Vi har også brakt alpha av elementet er border-color ned til .03 fordi vi ønsker uskarphet til å gjøre det meste av jobben med å markere hvor grensen ligger.

Dette kan se gjort, men det er noe jeg fortsatt ikke liker: kantene av pseudo-element er nå uklart, så vel. Så la oss fikse det!

En praktisk ting når det kommer til for nettlesere gjelder egenskaper på er at filtre brukes før klipping. Mens dette er ikke hva vi ønsker oss og får oss til å ty til hensiktsmessige løsninger i en rekke andre tilfeller… akkurat her, det viser seg å være veldig nyttig!

Det betyr at, etter å tåkelegge pseudo-element, kan vi klippet det til sin border-box!

Min foretrukne måten å gjøre dette på er ved å sette klipp-bane til inset(0) fordi… det er den enkleste måten å gjøre det, virkelig! polygon(0 0, 100% 0, 100% 100%, 0 100%) ville være overkill.

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

I tilfelle du lurer på hvorfor du ikke angi klipp-banen på den faktiske element i stedet for å sette det på :før pseudo-element, dette er fordi innstillingen klipp-banen på elementet ville gjøre det til en stabling sammenheng. Dette vil tvinge alle sine barn elementer (og følgelig dens uklare :før pseudo-element) for å være inneholdt i det og, derfor, i front av sin bakgrunn. Og så atomanlegg z-index-eller !viktig å kunne endre det.

Vi kan prettify dette ved å legge til litt tekst med en penere skrift, en box-shadow og noen layout egenskaper.

Hva hvis vi har avrundede hjørner?

Det beste ting om hvordan du bruker inset() i stedet for polygon() for å få klippet-banen er at inset() kan også plass for alle border-radius kan vi ønske!

Og når jeg sier alle border-radius, jeg mener det! Sjekk ut dette!

div {
–r: 15% 75px 35vh 13vw/ 3em 5rem 29vmin 12.5 vmax;
border-radius: var(–r);
/* samme stiler som før */

og:før {
/* samme stiler som før */
border-radius: arve;
klipp-bane: inset(0 runde var(–r));
}
}

Det fungerer som en sjarm!

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

Utvide støtte

Noen mobile nettlesere trenger fortsatt -webkit – prefiks for både filter og clip-banen, så sørg for å inkludere de versjoner også. Merk at de er inkludert i CodePen demoer integrer her, selv om jeg valgte å hoppe over dem i koden som presenteres i kroppen av denne artikkelen.

Ok, men hva hvis vi trenger å støtte Kanten? klipp-banen fungerer ikke i Kanten, men filteret gjør, noe som betyr at vi får den uklare grensen, men ingen skarpe skjær grenser.

Vel, hvis vi ikke trenger hjørne avrunding, kan vi bruke mindre klipp eiendom som et tilbakefall. Dette betyr å legge til følgende linje rett før klipp-banen som:

klipp: rect(0 100% 100% 0)

Og vår demo arbeider nå i Kanten… liksom! Høyre, bunn og venstre kantene er kuttet kraftig, men den øverste er fortsatt uklart (bare i Debug-modus av Pennen, alt virker fint for iframe-i Visningen for redigering). Og åpning DevTools eller ved å høyreklikke i Kanten vinduet eller klikke hvor som helst utenfor dette vinduet gjør at effekten av denne eiendommen forsvinne. Bug i måneden akkurat der!

Alright, siden dette er så upålitelig og det trenger ikke engang hjelpe oss hvis vi vil ha avrundede hjørner, la oss prøve en annen tilnærming!

Dette er litt som å skrape bak på venstre øret med høyre fot (eller den andre veien rundt, avhengig av på hvilken side som er mer fleksible), men det er den eneste måten jeg kan tenke på å gjøre det arbeidet i Kanten.

Noen av dere har kanskje allerede vært skriker på skjermen noe sånt som “men Ana… overflow: hidden!” – og ja, det er det vi går for nå. Jeg har unngått det i utgangspunktet grunn av måten det fungerer: det kutter ut alle etterkommer innhold utenfor padding-boksen. Ikke utenfor, border-box, som vi har gjort ved klipping!

Dette betyr at vi trenger å droppe den virkelige grensen og ta det med polstring, som jeg er ikke akkurat glad om fordi det kan føre til mer komplikasjoner, men la oss ta det ett skritt av gangen!

Så langt som endringer i koden er opptatt av, er det første vi gjør er å fjerne alle border-relaterte egenskaper og angir grensen-bredde verdi som polstring. Vi deretter sette overflow: hidden samt begrense bakgrunn av den faktiske element til innhold-boksen. Til slutt, vi reset pseudo-element bakgrunn-klipp til padding-boksen verdi og null sine kvoter.

$falske-b: 1.5 em; // falske border-width

div {
/* samme stiler som før */
overflow: hidden;
polstring: $falske-b;
bakgrunn: url(oranges.jpg) 50%/ cover
padding-box /* background-origin */
innhold-box /* bakgrunn-clip */;

og:før {
/* samme stiler som før */
øverst: 0; høyre: 0; nederst: 0; left: 0;
bakgrunn: arve;
bakgrunn-klipp: padding-boks;
}
}

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

Hvis vi ønsker at den knapt er synlig “grensen” overlay, vi trenger en annen bakgrunn lag på den faktiske element:

$falske-b: 1.5 em; // falske border-width
$c: rgba(#000, .03);

div {
/* samme stiler som før */
overflow: hidden;
polstring: $falske-b;
–img: url(oranges.jpg) 50%/ cover;
bakgrunn: var(–img)
padding-box /* background-origin */
innhold-box /* bakgrunn-clip */,
linear-gradient($c, $c);

og:før {
/* samme stiler som før */
øverst: 0; høyre: 0; nederst: 0; left: 0;
bakgrunn: var(–img);
}
}

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

Vi kan også legge til avrundede hjørner med noe stress:

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

Så hvorfor har vi ikke gjøre dette helt fra begynnelsen?!

Husker da jeg sa litt tidligere som ikke bruker en faktisk grensen kan komplisere ting senere?

Vel, la oss si at vi ønsker å ha det litt tekst. Med den første metoden, ved hjelp av en faktiske grensen og clip-banen, er alt det tar for å hindre tekst innhold fra å berøre den uklare grensen er å legge til en padding (la oss si 1em) på våre element.

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

Men med overflow: hidden metode, har vi allerede brukt polstring egenskapen til å skape uklare “grensen”. Øke dens verdi ikke hjelpe fordi det øker bare falske grensen bredde.

Vi kan legge til tekst i et barn element. Eller vi kan også bruke :etter pseudo-element!

Måten dette fungerer på er ganske lik den første metoden, med det :etter å ha byttet den faktiske element. Forskjellen er at vi kutter uskarpe kanter med overflow: hidden i stedet for klipp-bane: inset(0) og polstring på selve elementet er pseudos’ border-width ($b) pluss uansett polstring verdi vi ønsker:

$b: 1.5 em; // border-width

div {
overflow: hidden;
position: relative;
polstring: calc(1em + #{$b});
/* prettifying stiler */

og:før, &:etter {
position: absolute;
z-index: -1; /* sett dem *bak* foreldre */
/* null alle mellomregninger */
øverst: 0; høyre: 0; nederst: 0; left: 0;
border: solid $b rgba(#000, .03);
bakgrunn: url(oranges.jpg) 50%/ cover
border-box /* background-origin */
padding-box /* bakgrunn-clip */;
innhold:”
}

og:før {
border-color: transparent;
bakgrunn-klipp: border-box;
filter: blur(9px);
}
}

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

Hva med å ha både tekst og noen ganske ekstreme avrundede hjørner? Vel, det er noe vi vil diskutere i en annen artikkel – stay tuned!

Hva om bakteppe-filter?

Noen av dere lurer kanskje på (som jeg var da jeg begynte å leke med ulike ideer for å prøve å oppnå denne effekten) om bakteppe-filter er ikke et alternativ.

Vel, ja og nei!

Teknisk sett er det mulig å få samme effekt, men siden Firefox ennå ikke gjennomføre det, kan vi kutte ut Firefox support hvis vi velger å ta denne ruten. For ikke å nevne denne tilnærmingen også tvinger oss til å bruke både pseudo-elementer hvis vi ønsker best mulig støtte for saken når våre element har noen tekst-innhold (som betyr at vi trenger pseudos og deres padding-boksen området bakgrunnen for å vise under denne teksten).

For de som ennå ikke vet hva som bakteppe-filteret gjør: det filtrerer ut hva som kan bli sett gjennom (delvis) gjennomsiktige deler av element vi bruker det på.

Veien vi må gå om dette er følgende: både pseudo-elementer har en åpen ramme og bakgrunn plassert og dimensjonert i forhold til padding-boksen. Vi begrense bakgrunn av pseudo-element på toppen (: etter) til padding-boksen.

Nå :når du ikke har en bakgrunn i grenseområdet lenger, og vi kan se frem til :før pseudo-element bak det der. Vi setter et bakteppe-filter på :etter-og kanskje til og med endre som kant-farge fra gjennomsiktig til litt synlig. Nederst (før) pseudo-element har bakgrunn som fortsatt er synlig gjennom den (delvis) gjennomsiktig, knapt gjenkjennelig grensen av :etter over blir uskarpt som et resultat av å bruke bakteppe-filter.

$b: 1.5 em; // border-width

div {
overflow: hidden;
position: relative;
polstring: calc(1em + #{$b});
/* prettifying stiler */

og:før, &:etter {
position: absolute;
z-index: -1; /* sett dem *bak* foreldre */
/* null alle mellomregninger */
øverst: 0; høyre: 0; nederst: 0; left: 0;
border: solid $b transparent;
bakgrunn: $url 50%/ cover
/* background-origin & -clip */
border-box;
innhold:”
}

og:etter {
border-color: rgba(#000, .03);
bakgrunn-klipp: padding-boks;
bakgrunn-filter: blur(9px); /* ingen Firefox support */
}
}

Husk at live-demo for øyeblikket ikke i Firefox og behov den Eksperimentelle Web-Plattformen har flagget er aktivert i chrome://flagg for å jobbe i Chrome.

Eliminere en pseudo-element

Dette er noe jeg ville ikke anbefale å gjøre i naturen fordi det kutter ut Edge-støtte, men vi har en måte å oppnå det resultatet vi ønsker med bare ett pseudo-element.

Vi starter med å angi bildet som bakgrunn på element (vi egentlig ikke trenger å eksplisitt sette en grense, så lenge vi tar sin bredde i polstringen) og deretter en delvis gjennomsiktig, knapt synlig bakgrunnen på absolutt posisjonert pseudo-element som er med på å dekke hele forelder. Vi har også sett bakteppe-filter på denne pseudo-element.

$b: 1.5 em; // border-width

div {
position: relative;
polstring: calc(1em + #{$b});
bakgrunn: url(oranges.jpg) 50%/ cover;
/* prettifying stiler */

og:før {
position: absolute;
/* null alle mellomregninger */
øverst: 0; høyre: 0; nederst: 0; left: 0;
bakgrunn: rgba(#000, .03);
bakgrunn-filter: blur(9px); /* ingen Firefox support */
innhold:”
}
}

Alright, men dette tåkelegger hele element bak nesten gjennomsiktig pseudo-element, inkludert tekst. Og det er ikke feil, dette er hva som bakteppe-filter er ment for å gjøre.

Problemet for hånden.

For å fikse dette, vi trenger å bli kvitt (ikke gjennomsiktig, noe som er helt ubrukelig i dette tilfellet) den indre rektangelet (hvis kantene er en avstand $b unna grensen-boksen kanter) av pseudo-element.

Vi har to måter å gjøre dette på.

Den første måten (live demo) er med clip-bane-og null-bredde tunnel teknikk:

$b: 1.5 em; // border-width
$o: calc(100% – #{$b});

div {
/* samme stiler som før */

og:før {
/* samme stiler som før */

/* fungerer ikke i Kanten */
klipp-bane: polygon(0 0, 100% 0, 100% 100%, 0 100%,
0 0,
#{$b $b}, #{$b $o}, #{$o $o}, #{$o $b},
#{$b $b});
}
}

Den andre måten (live demo) er med to composited maske lag (merk at i dette tilfellet trenger vi å eksplisitt sette en grense på våre pseudo):

$b: 1.5 em; // border-width

div {
/* samme stiler som før */

og:før {
/* samme stiler som før */

border: solid $b transparent;

/* fungerer ikke i Kanten */
–fyll: linear-gradient(rød, rød);
-webkit-maske: var(–fyll) padding-safe, lydisolering,
var(–fyll);
-webkit-mask-kompositt: xor;
maske: var(–fyll) padding-boksen ekskludere,
var(–fyll);
}
}

Siden ingen av disse to egenskapene fungerer i Kanten, dette betyr at støtte er nå begrenset til WebKit nettlesere (og vi trenger fortsatt å aktivere den Eksperimentelle Web-Plattformen har flagget for bakteppe-filter for å jobbe i Chrome).

Fremtidige (og bedre!) løsning

Dette er ikke implementert av en hvilken som helst nettleser på dette punktet, men spec nevner et filter () – funksjonen, som vil tillate oss å bruke filtre på individuelle bakgrunn lag. Dette vil eliminere behovet for en pseudo-element og vil redusere kode som er nødvendig for å oppnå denne effekten til to CSS erklæringer!

border: solid 1.5 em rgba(#000, .03);
bakgrunn: $url
border-box /* background-origin */
padding-box /* bakgrunn-clip */,
filteret($url, blur(9px))
/* bakgrunn-opprinnelse og bakgrunn-clip */
border-box

Hvis du tror dette er noe som er nyttig å ha, kan du legge til din bruk saker og spor implementering pågår for både Chrome og Firefox.

Mer grensen filter alternativer

Jeg har bare snakket om å viske ut grensen opp til nå, men denne teknikken fungerer for ganske mye alle CSS-filter (lagre for drop-shadow() som ikke ville gjøre mye følelse i denne sammenheng). Du kan spille med veksling mellom dem og justere verdier i interaktiv demo nedenfor:

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

Og alt vi har gjort så langt har brukt bare ett filter funksjon, men vi kan også knytte dem og så mulighetene er uendelige – det kule effekter kan du komme opp med denne måten?

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