CSS-rutenett og tilpassede former, del 2 PlatoBlockchain Data Intelligence. Vertikalt søk. Ai.

CSS-rutenett og tilpassede former, del 2

Greit, så sist vi sjekket inn, brukte vi CSS Grid og kombinerte dem med CSS clip-path og mask teknikker for å lage rutenett med fancy former.

Her er bare ett av de fantastiske rutenettene vi har laget sammen:

Klar for andre runde? Vi jobber fortsatt med CSS Grid, clip-pathog mask, men mot slutten av denne artikkelen vil vi ende opp med forskjellige måter å ordne bilder på rutenettet, inkludert noen rad sveveeffekter som gir en autentisk, interaktiv opplevelse for å se bilder.

Og gjett hva? Vi bruker samme markering som vi brukte forrige gang. Her er det igjen:

<div class="gallery">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <!-- as many times as we want -->
</div>

I likhet med forrige artikkel trenger vi bare en beholder med bilder inni. Ikke noe mer!

Nestet bilderutenett

Forrige gang var rutenettene våre, vel, typiske bilderuter. Bortsett fra de pene formene vi maskerte dem med, var de ganske standard symmetriske rutenett så langt som hvordan vi plasserte bildene inni.

La oss prøve å neste et bilde i midten av rutenettet:

Vi starter med å sette et 2✕2 rutenett for fire bilder:

.gallery {
  --s: 200px; /* controls the image size */
  --g: 10px; /* controls the gap between images */

  display: grid;
  gap: var(--g);
  grid-template-columns: repeat(2, auto);
}
.gallery > img {
  width: var(--s);
  aspect-ratio: 1;
  object-fit: cover;
}

Ikke noe komplisert ennå. Det neste trinnet er å kutte hjørnet av bildene våre for å skape plass til det nestede bildet. Jeg har allerede en detaljert artikkel om hvordan kutte hjørner ved hjelp av clip-path og mask. Du kan også bruke min online generator for å få CSS for maskering av hjørner.

Det vi trenger her er å kutte ut hjørnene i en vinkel lik 90deg. Vi kan bruke det samme kjeglegradientteknikk fra den artikkelen for å gjøre det:

.gallery > img {
   mask: conic-gradient(from var(--_a), #0000 90deg, #000 0);
}
.gallery > img:nth-child(1) { --_a: 90deg; }
.gallery > img:nth-child(2) { --_a: 180deg; }
.gallery > img:nth-child(3) { --_a: 0deg; }
.gallery > img:nth-child(4) { --_a:-90deg; }

Vi kunne bruke clip-path metode for å kutte hjørner fra den samme artikkelen, men maskering med gradienter er mer egnet her fordi vi har samme konfigurasjon for alle bildene - alt vi trenger er en rotasjon (definert med variabelen --_a) får effekten, så vi maskerer fra innsiden i stedet for ytterkantene.

CSS-rutenett og tilpassede former, del 2

Nå kan vi plassere det nestede bildet inne i det maskerte rommet. Først, la oss sørge for at vi har et femte bildeelement i HTML:

<div class="gallery">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
</div>

Vi kommer til å stole på den gode, absolutte posisjoneringen for å plassere den der:

.gallery > img:nth-child(5) {
  position: absolute;
  inset: calc(50% - .5*var(--s));
  clip-path: inset(calc(var(--g) / 4));
}

De inset egenskapen lar oss plassere bildet i sentrum ved hjelp av en enkelt erklæring. Vi vet størrelsen på bildet (definert med variabelen --s), og vi vet at beholderens størrelse tilsvarer 100 %. Vi regner litt, og avstanden fra hver kant skal være lik (100% - var(--s))/2.

Diagram over breddene som trengs for å fullføre designet.
CSS-rutenett og tilpassede former, del 2

Du lurer kanskje på hvorfor vi bruker clip-path i det hele tatt her. Vi bruker det med det nestede bildet for å ha et konsistent gap. Hvis vi skulle fjerne det, ville du lagt merke til at vi ikke har samme gap mellom alle bildene. På denne måten kutter vi litt fra det femte bildet for å få riktig avstand rundt det.

Den komplette koden igjen:

.gallery {
  --s: 200px; /* controls the image size */
  --g: 10px;  /* controls the gap between images */
  
  display: grid;
  gap: var(--g);
  grid-template-columns: repeat(2, auto);
  position: relative;
}

.gallery > img {
  width: var(--s);
  aspect-ratio: 1;
  object-fit: cover;
  mask: conic-gradient(from var(--_a), #0000 90deg, #000 0);
}

.gallery > img:nth-child(1) {--_a: 90deg}
.gallery > img:nth-child(2) {--_a:180deg}
.gallery > img:nth-child(3) {--_a:  0deg}
.gallery > img:nth-child(4) {--_a:-90deg}
.gallery > img:nth-child(5) {
  position: absolute;
  inset: calc(50% - .5*var(--s));
  clip-path: inset(calc(var(--g) / 4));
}

Nå lurer kanskje mange av dere også: hvorfor alle de komplekse tingene når vi kan plassere det siste bildet på toppen og legge til en kant til det? Det ville skjule bildene under det nestede bildet uten en maske, ikke sant?

Det er sant, og vi får følgende:

Nei mask, Nei clip-path. Ja, koden er lett å forstå, men det er en liten ulempe: kantfargen må være den samme som hovedbakgrunnen for å gjøre illusjonen perfekt. Denne lille ulempen er nok for meg til å gjøre koden mer kompleks i bytte mot reell åpenhet uavhengig av bakgrunnen. Jeg sier ikke at en grensetilnærming er dårlig eller feil. Jeg vil anbefale det i de fleste tilfeller der bakgrunnen er kjent. Men vi er her for å utforske nye ting og, viktigst av alt, bygge komponenter som ikke er avhengige av miljøet.

La oss prøve en annen form denne gangen:

Denne gangen gjorde vi det nestede bildet til en sirkel i stedet for en firkant. Det er en enkel oppgave med border-radius Men vi må bruke en sirkulær utskjæring for de andre bildene. Denne gangen vil vi imidlertid stole på en radial-gradient() i stedet for a conic-gradient() for å få det fine avrundede utseendet.

.gallery > img {
  mask: 
    radial-gradient(farthest-side at var(--_a),
      #0000 calc(50% + var(--g)/2), #000 calc(51% + var(--g)/2));
}
.gallery > img:nth-child(1) { --_a: calc(100% + var(--g)/2) calc(100% + var(--g)/2); }
.gallery > img:nth-child(2) { --_a: calc(0%   - var(--g)/2) calc(100% + var(--g)/2); }
.gallery > img:nth-child(3) { --_a: calc(100% + var(--g)/2) calc(0%   - var(--g)/2); }
.gallery > img:nth-child(4) { --_a: calc(0%   - var(--g)/2) calc(0%   - var(--g)/2); }

Alle bildene bruker samme konfigurasjon som forrige eksempel, men vi oppdaterer midtpunktet hver gang.

Diagram som viser senterverdiene for hver kvadrant i rutenettet.
CSS-rutenett og tilpassede former, del 2

Figuren ovenfor illustrerer midtpunktet for hver sirkel. Likevel, i den faktiske koden, vil du legge merke til at jeg også tar høyde for gapet for å sikre at alle punktene er i samme posisjon (sentrum av rutenettet) for å få en kontinuerlig sirkel hvis vi kombinerer dem.

Nå som vi har layouten vår, la oss snakke om sveveeffekten. I tilfelle du ikke la merke til det, øker en kul sveveeffekt størrelsen på det nestede bildet og justerer alt annet deretter. Å øke størrelsen er en relativt enkel oppgave, men å oppdatere gradienten er mer komplisert siden gradienter som standard ikke kan animeres. For å overvinne dette, vil jeg bruke en font-size hack for å kunne animere den radielle gradienten.

Hvis du sjekker koden til gradienten, kan du se at jeg legger til 1em:

mask: 
    radial-gradient(farthest-side at var(--_a),
      #0000 calc(50% + var(--g)/2 + 1em), #000 calc(51% + var(--g)/2 + 1em));

Det er kjent det em enheter er i forhold til det overordnede elementets font-size, så endre font-size av .gallery vil også endre den beregnede em verdi – dette er trikset vi bruker. Vi animerer font-size fra en verdi på 0 til en gitt verdi, og som et resultat blir gradienten animert, noe som gjør den utklippede delen større, etter størrelsen på det nestede bildet som blir større.

Her er koden som fremhever delene som er involvert i sveveeffekten:

.gallery {
  --s: 200px; /* controls the image size */
  --g: 10px; /* controls the gaps between images */

  font-size: 0; /* initially we have 1em = 0 */
  transition: .5s;
}
/* we increase the cut-out by 1em */
.gallery > img {
  mask: 
    radial-gradient(farthest-side at var(--_a),
      #0000 calc(50% + var(--g)/2 + 1em), #000 calc(51% + var(--g)/2 + 1em));
}
/* we increase the size by 2em */
.gallery > img:nth-child(5) {
  width: calc(var(--s) + 2em);
}
/* on hover 1em = S/5 */
.gallery:hover {
  font-size: calc(var(--s) / 5);
}

De font-size triks er nyttig hvis vi ønsker å animere gradienter eller andre egenskaper som ikke kan animeres. Egendefinerte egenskaper definert med @property kan løse et slikt problem, men støtte for det mangler fortsatt i skrivende stund.

Jeg oppdaget font-size lure fra @SelenIT2 mens du prøver å løse en utfordring på Twitter.

En annen form? La oss gå!

Denne gangen klippet vi det nestede bildet i form av en rombe. Jeg lar deg dissekere koden som en øvelse for å finne ut hvordan vi kom hit. Du vil legge merke til at strukturen er den samme som i eksemplene våre. De eneste forskjellene er hvordan vi bruker gradienten til å lage formen. Grav inn og lær!

Sirkulært bilderutenett

Vi kan kombinere det vi har lært her og i tidligere artikler for å lage et enda mer spennende bilderutenett. Denne gangen, la oss gjøre alle bildene i rutenettet vårt sirkulære og, mens du holder musepekeren, utvide et bilde for å avsløre det hele mens det dekker resten av bildene.

HTML- og CSS-strukturen til rutenettet er ikke noe nytt fra før, så la oss hoppe over den delen og fokusere i stedet på den sirkulære formen og sveveeffekten vi ønsker.

Vi skal bruke clip-path og dens circle() funksjon til - du gjettet riktig! — klipp en sirkel ut av bildene.

Viser de to tilstandene til et bilde, den naturlige tilstanden til venstre og tilstanden til høyre, inkludert klippbaneverdiene for å lage dem.
CSS-rutenett og tilpassede former, del 2

Den figuren illustrerer clip-path brukt til det første bildet. Venstre side viser bildets begynnelsestilstand, mens høyre viser tilstanden som svever. Du kan bruke dette nettbaserte verktøyet å spille og visualisere clip-path verdier.

For de andre bildene kan vi oppdatere midten av sirkelen (70% 70%) for å få følgende kode:

.gallery > img:hover {
  --_c: 50%; /* same as "50% at 50% 50%" */
}
.gallery > img:nth-child(1) {
  clip-path: circle(var(--_c, 55% at 70% 70%));
}
.gallery > img:nth-child(2) {
  clip-path: circle(var(--_c, 55% at 30% 70%));
}
.gallery > img:nth-child(3) {
  clip-path: circle(var(--_c, 55% at 70% 30%));
}
.gallery > img:nth-child(4) {
  clip-path: circle(var(--_c, 55% at 30% 30%));
}

Legg merke til hvordan vi definerer clip-path verdier som en fallback på innsiden var(). På denne måten kan vi lettere oppdatere verdien ved sveving ved å angi verdien til --_c variabel. Når du bruker circle(), er standardposisjonen til midtpunktet 50% 50%, så vi får utelate det for mer konsis kode. Det er derfor du ser at vi bare setter 50% istedenfor 50% at 50% 50%.

Deretter øker vi størrelsen på bildet vårt når vi peker til den totale størrelsen på rutenettet slik at vi kan dekke de andre bildene. Vi sørger også for z-index har en høyere verdi på det pekende bildet, så det er det øverste i vårt stable kontekst.

.gallery {
  --s: 200px; /* controls the image size */
  --g: 8px;   /* controls the gap between images */

  display: grid;
  grid: auto-flow var(--s) / repeat(2, var(--s));
  gap: var(--g);
}

.gallery > img {
  width: 100%; 
  aspect-ratio: 1;
  cursor: pointer;
  z-index: 0;
  transition: .25s, z-index 0s .25s;
}
.gallery > img:hover {
  --_c: 50%; /* change the center point on hover */
  width: calc(200% + var(--g));
  z-index: 1;
  transition: .4s, z-index 0s;
}

.gallery > img:nth-child(1){
  clip-path: circle(var(--_c, 55% at 70% 70%));
  place-self: start;
}
.gallery > img:nth-child(2){
  clip-path: circle(var(--_c, 55% at 30% 70%));
  place-self: start end;
}
.gallery > img:nth-child(3){
  clip-path: circle(var(--_c, 55% at 70% 30%));
  place-self: end start;
}
.gallery > img:nth-child(4){
  clip-path: circle(var(--_c, 55% at 30% 30%));
  place-self: end;
}

Hva skjer med place-self eiendom? Hvorfor trenger vi det og hvorfor har hvert bilde en bestemt verdi?

Husker du problemet vi hadde i forrige artikkel når lage rutenettet av puslespillbrikker? Vi økte størrelsen på bildene for å skape et overløp, men overløpet på noen bilder var feil. Vi fikset dem ved hjelp av place-self eiendom.

Samme problemstilling her. Vi øker størrelsen på bildene slik at hver enkelt flyter over rutenettcellene sine. Men hvis vi ikke gjør noe, vil alle flyte over på høyre og nederste side av rutenettet. Det vi trenger er:

  1. det første bildet som flyter over den nederste høyre kanten (standard oppførsel),
  2. det andre bildet flyter over den nederste venstre kanten,
  3. det tredje bildet for å flyte over den øverste høyre kanten, og
  4. det fjerde bildet for å flyte over den øverste venstre kanten.

For å få det, må vi plassere hvert bilde riktig ved å bruke place-self eiendom.

Diagram som viser plass-selv-egenskapsverdiene for hver kvadrant i rutenettet.
CSS-rutenett og tilpassede former, del 2

I tilfelle du ikke er kjent med place-self, det er en forkortelse for justify-self og align-self å plassere elementet horisontalt og vertikalt. Når det tar én verdi, bruker begge justeringene den samme verdien.

Utvide bildepaneler

I en tidligere artikkel, laget jeg en kul zoom-effekt som gjelder for et rutenett av bilder der vi kan kontrollere alt: antall rader, antall kolonner, størrelser, skaleringsfaktor osv.

Et spesielt tilfelle var de klassiske ekspanderende panelene, hvor vi kun har én rad og en full-bredde beholder.

Vi tar dette eksemplet og kombinerer det med former!

Før vi fortsetter, anbefaler jeg på det sterkeste å lese min annen artikkel for å forstå hvordan triksene vi skal dekke fungerer. Sjekk det ut, så fortsetter vi her med å fokusere på å lage panelformene.

Først, la oss starte med å forenkle koden og fjerne noen variabler

Vi trenger bare én rad og antall kolonner skal justeres basert på antall bilder. Det betyr at vi ikke lenger trenger variabler for antall rader (--n) og kolonner (--m ), men vi må bruke grid-auto-flow: column, slik at rutenettet automatisk kan generere kolonner når vi legger til nye bilder. Vi vil vurdere en fast høyde for vår container; som standard vil den være i full bredde.

La oss klippe bildene til en skrå form:

Et hodebilde av en rolig rød ulv som ser nedover med hjørner overlagt som viser klippbanens egenskapspunkter.
clip-path: polygon(S 0%, 100% 0%, (100% - S) 100%, 0% 100%);

Nok en gang er hvert bilde inneholdt i rutenettcellen, så det er mer plass mellom bildene enn vi ønsker:

Et rutenett med seks paneler med skråstilte bilder av forskjellige ville dyr som viser rutenettets linjer og mellomrom.
CSS-rutenett og tilpassede former, del 2

Vi må øke bredden på bildene for å skape en overlapping. Vi bytter ut min-width: 100% med min-width: calc(100% + var(--s)), Hvor --s er en ny variabel som styrer formen.

Nå må vi fikse de første og siste bildene, slik at de på en måte blør ut av siden uten hull. Med andre ord kan vi fjerne skråningen fra venstre side av det første bildet og skråningen fra høyre side av det siste bildet. Vi trenger en ny clip-path spesielt for de to bildene.

Vi må også rette opp i overløpet. Som standard vil alle bildene flyte over på begge sider, men for det første trenger vi et overløp på høyre side mens vi trenger et venstre overløp for det siste bildet.

.gallery > img:first-child {
  min-width: calc(100% + var(--s)/2);
  place-self: start;
  clip-path: polygon(0 0,100% 0,calc(100% - var(--s)) 100%,0 100%);
}
.gallery > img:last-child {
  min-width: calc(100% + var(--s)/2);
  place-self: end;
  clip-path: polygon(var(--s) 0,100% 0,100% 100%,0 100%);
}

Det endelige resultatet er et fint ekspanderende panel med skråstilte bilder!

Vi kan legge til så mange bilder du vil, og rutenettet justeres automatisk. I tillegg trenger vi bare å kontrollere én verdi for å kontrollere formen!

Vi kunne ha laget det samme oppsettet med flexbox siden vi har å gjøre med en enkelt rad med elementer. Her er implementeringen min.

Visst, skrå bilder er kule, men hva med et sikk-sakk-mønster? Jeg har allerede ertet denne kl slutten av den siste artikkelen.

Alt jeg gjør her er å bytte ut clip-path med mask… og gjett hva? Jeg har allerede en detaljert artikkel om skape den sikk-sakk-formen — for ikke å snakke om en online generator for å få koden. Ser du hvordan alt henger sammen?

Den vanskeligste delen her er å sørge for at sikk-sakkene er perfekt justert, og for dette må vi legge til en forskyvning for hver :nth-child(odd) bildeelement.

.gallery > img {
  mask: 
    conic-gradient(from -135deg at right, #0000, #000 1deg 89deg, #0000 90deg) 
      100% calc(50% + var(--_p, 0%))/51% calc(2*var(--s)) repeat-y,
    conic-gradient(from   45deg at left,  #0000, #000 1deg 89deg, #0000 90deg) 
      0%   calc(50% + var(--_p, 0%))/51% calc(2*var(--s)) repeat-y;
}
/* we add an offset to the odd elements */
.gallery > img:nth-child(odd) {
  --_p: var(--s);
}
.gallery > img:first-child {
  mask: 
    conic-gradient(from -135deg at right, #0000, #000 1deg 89deg, #0000 90deg) 
      0 calc(50% + var(--_p, 0%))/100% calc(2*var(--s));
}
.gallery > img:last-child {
  mask: 
    conic-gradient(from 45deg at left, #0000, #000 1deg 89deg, #0000 90deg) 
      0 calc(50% + var(--_p, 0%)) /100% calc(2*var(--s));
}

Legg merke til bruken av --_p variabel, som vil falle tilbake til 0% men vil være lik --_s for de rare bildene.

Her er en demo som illustrerer problemet. Hold musepekeren for å se hvordan forskyvningen - definert av --_p — fikser justeringen.

Legg også merke til hvordan vi bruker en annen maske for det første og siste bildet som vi gjorde i forrige eksempel. Vi trenger bare en sikk-sakk på høyre side av det første bildet og venstre side av det siste bildet.

Og hvorfor ikke avrundede sider? La oss gjøre det!

Jeg vet at koden kan se skummel og vanskelig ut å forstå, men alt som skjer er en kombinasjon av forskjellige triks vi har dekket i denne og andre artikler jeg allerede har delt. I dette tilfellet bruker jeg samme kodestruktur som sikk-sakk og de skråstilte formene. Sammenlign det med disse eksemplene, og du vil ikke finne noen forskjell! Det er de samme triksene min forrige artikkel om zoomeffekten. Da bruker jeg min annen skriving og min nettgenerator for å få koden for masken som lager de avrundede formene.

Hvis du husker hva vi gjorde for sikk-sakk, hadde vi brukt den samme masken for alle bildene, men så måtte vi legge til en forskyvning til de odde bildene for å skape en perfekt overlapping. I dette tilfellet trenger vi en annen maske for oddetallsbildene.

Den første masken:

mask: 
  linear-gradient(-90deg,#0000 calc(2*var(--s)),#000 0) var(--s),
  radial-gradient(var(--s),#000 98%,#0000) 50% / calc(2*var(--s)) calc(1.8*var(--s)) space repeat;
CSS-rutenett og tilpassede former, del 2 PlatoBlockchain Data Intelligence. Vertikalt søk. Ai.

Den andre:

mask:
  radial-gradient(calc(var(--s) + var(--g)) at calc(var(--s) + var(--g)) 50%,#0000 98% ,#000) 
  calc(50% - var(--s) - var(--g)) / 100% calc(1.8*var(--s))
CSS-rutenett og tilpassede former, del 2 PlatoBlockchain Data Intelligence. Vertikalt søk. Ai.

Den eneste innsatsen jeg gjorde her er å oppdatere den andre masken for å inkludere gap-variabelen (--g) for å skape det rommet mellom bildene.

Siste touch er å fikse det første og siste bildet. Som alle de foregående eksemplene trenger det første bildet en rett venstre kant mens det siste trenger en rett høyre kant.

For det første bildet vet vi alltid hvilken maske den må ha, som er følgende:

.gallery > img:first-child {
  mask: 
    radial-gradient(calc(var(--s) + var(--g)) at right, #0000 98%, #000) 50% / 100% calc(1.8 * var(--s));
}
Et hodeskudd av brunbjørn med bølgemønster for høyre kant.
CSS-rutenett og tilpassede former, del 2

For det siste bildet avhenger det av antall elementer, så det betyr noe om det elementet er det :nth-child(odd) or :nth-child(even).

Det komplette rutenettet med bilder av ville dyr med alle de riktige kantene og avstandene mellom bildene.
CSS-rutenett og tilpassede former, del 2
.gallery > img:last-child:nth-child(even) {
  mask: 
    linear-gradient(to right,#0000 var(--s),#000 0),
    radial-gradient(var(--s),#000 98%,#0000) left / calc(2*var(--s)) calc(1.8*var(--s)) repeat-y
}
Et enkeltrads rutenett med tre bilder av ville dyr med bølgete kanter der det siste bildet er et oddetallselement.
CSS-rutenett og tilpassede former, del 2
.gallery > img:last-child:nth-child(odd) {
  mask: 
    radial-gradient(calc(var(--s) + var(--g)) at left,#0000 98%,#000) 50% / 100% calc(1.8*var(--s))
}

Det er alt! Tre forskjellige oppsett, men de samme CSS-triksene hver gang:

  • kodestrukturen for å lage zoomeffekten
  • en maske eller klippebane for å lage figurene
  • en egen konfigurasjon for de odde elementene i noen tilfeller for å sikre at vi har en perfekt overlapping
  • en spesifikk konfigurasjon for det første og siste bildet for å beholde formen på bare én side.

Og her er en stor demo med alle sammen. Alt du trenger er å legge til en klasse for å aktivere oppsettet du vil se.

Og her er den med Flexbox-implementeringen

Innpakning opp

Uff, vi er ferdige! Jeg vet at det er mange CSS-triks og eksempler mellom denne artikkelen og den siste, for ikke å nevne alle de andre triksene jeg har referert her fra andre artikler jeg har skrevet. Det tok meg tid å sette alt sammen, og du trenger ikke å forstå alt på en gang. En lesing vil gi deg en god oversikt over alle oppsettene, men du må kanskje lese artikkelen mer enn én gang og fokusere på hvert eksempel for å forstå alle triksene.

La du merke til at vi ikke rørte HTML-en i det hele tatt annet enn kanskje antall bilder i markeringen? Alle layoutene vi laget deler den samme HTML-koden, som ikke er annet enn en liste over bilder.

Før jeg avslutter, vil jeg gi deg et siste eksempel. Det er et "mot" mellom to anime-karakterer med en kul sveveeffekt.

Hva med deg? Kan du lage noe basert på det du har lært? Det trenger ikke å være komplisert - forestill deg noe kult eller morsomt som jeg gjorde med den anime-matchupen. Det kan være en god øvelse for deg, og vi kan avslutte med en utmerket samling i kommentarfeltet.

Tidstempel:

Mer fra CSS triks