CSS-gitter og brugerdefinerede former, del 2 PlatoBlockchain Data Intelligence. Lodret søgning. Ai.

CSS-gitter og brugerdefinerede former, del 2

Okay, så sidste gang vi tjekkede ind, vi brugte CSS Grid og kombinerede dem med CSS clip-path , mask teknikker til at skabe gitter med smarte former.

Her er blot et af de fantastiske gitter, vi lavede sammen:

Klar til anden runde? Vi arbejder stadig med CSS Grid, clip-pathog mask, men i slutningen af ​​denne artikel ender vi med forskellige måder at arrangere billeder på gitteret, inklusive nogle rad-hover-effekter, der giver en autentisk, interaktiv oplevelse at se billeder.

Og gæt hvad? Vi bruger samme markup, som vi brugte sidste gang. Her er det igen:

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

Ligesom den forrige artikel har vi kun brug for en beholder med billeder indeni. Intet mere!

Indlejret billedgitter

Sidste gang var vores gitter, ja, typiske billedgitter. Bortset fra de pæne former, vi maskerede dem med, var de ret standard symmetriske gitter, hvad angår hvordan vi placerede billederne inde.

Lad os prøve at indlejre et billede i midten af ​​gitteret:

Vi starter med at indstille et 2✕2-gitter til fire billeder:

.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;
}

Intet komplekst endnu. Det næste trin er at skære hjørnet af vores billeder for at skabe plads til det indlejrede billede. Jeg har allerede en detaljeret artikel om hvordan man skærer hjørner vha clip-path , mask. Du kan også bruge min online generator for at få CSS til at maskere hjørner.

Det, vi har brug for her, er at skære hjørnerne ud i en vinkel svarende til 90deg. Vi kan bruge det samme kegle-gradient teknik fra den artikel for at gø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 bruge clip-path metode til at skære hjørner fra den samme artikel, men maskering med gradienter er mere velegnet her, fordi vi har den samme konfiguration for alle billederne - alt hvad vi behøver er en rotation (defineret med variablen --_a) få effekten, så vi maskerer indefra i stedet for yderkanterne.

CSS-gitter og brugerdefinerede former, del 2

Nu kan vi placere det indlejrede billede inde i det maskerede rum. Lad os først sikre os, at vi har et femte billedelement i HTML:

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

Vi vil stole på den gode gamle absolutte positionering for at placere den der:

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

inset egenskaben giver os mulighed for at placere billedet i centrum ved hjælp af en enkelt erklæring. Vi kender størrelsen på billedet (defineret med variablen --s), og vi ved, at beholderens størrelse svarer til 100 %. Vi laver noget matematik, og afstanden fra hver kant skal være lig med (100% - var(--s))/2.

Diagram over de nødvendige bredder for at færdiggøre designet.
CSS-gitter og brugerdefinerede former, del 2

Du undrer dig måske over, hvorfor vi bruger clip-path overhovedet her. Vi bruger det sammen med det indlejrede billede for at få et ensartet mellemrum. Hvis vi skulle fjerne det, ville du bemærke, at vi ikke har det samme mellemrum mellem alle billederne. På denne måde skærer vi en lille smule fra det femte billede for at få den rigtige afstand omkring det.

Den komplette kode igen:

.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));
}

Nu undrer mange af jer måske også: hvorfor alle de komplekse ting, når vi kan placere det sidste billede på toppen og tilføje en kant til det? Det ville skjule billederne under det indlejrede billede uden en maske, ikke?

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

Ingen mask, nr clip-path. Ja, koden er nem at forstå, men der er en lille ulempe: kantfarven skal være den samme som hovedbaggrunden for at gøre illusionen perfekt. Denne lille ulempe er nok for mig til at gøre koden mere kompleks i bytte for reel gennemsigtighed uafhængig af baggrunden. Jeg siger ikke, at en grænsetilgang er dårlig eller forkert. Jeg vil anbefale det i de fleste tilfælde, hvor baggrunden er kendt. Men vi er her for at udforske nye ting og, vigtigst af alt, bygge komponenter, der ikke er afhængige af deres miljø.

Lad os prøve en anden form denne gang:

Denne gang lavede vi det indlejrede billede til en cirkel i stedet for en firkant. Det er en nem opgave med border-radius Men vi skal bruge en cirkulær udskæring for de andre billeder. Denne gang vil vi dog stole på en radial-gradient() i stedet for a conic-gradient() for at få det flotte afrundede look.

.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 billederne bruger den samme konfiguration som det foregående eksempel, men vi opdaterer midtpunktet hver gang.

Diagram, der viser centerværdierne for hver kvadrant i gitteret.
CSS-gitter og brugerdefinerede former, del 2

Ovenstående figur illustrerer midtpunktet for hver cirkel. Alligevel vil du i den faktiske kode bemærke, at jeg også tager højde for kløften for at sikre, at alle punkter er på samme position (midten af ​​gitteret) for at få en kontinuerlig cirkel, hvis vi kombinerer dem.

Nu hvor vi har vores layout, lad os tale om svæveeffekten. Hvis du ikke lagde mærke til det, øger en cool svæveeffekt størrelsen af ​​det indlejrede billede og justerer alt andet i overensstemmelse hermed. At øge størrelsen er en forholdsvis nem opgave, men opdatering af gradienten er mere kompliceret, da gradienter som standard ikke kan animeres. For at overvinde dette vil jeg bruge en font-size hack for at kunne animere den radiale gradient.

Hvis du tjekker gradientens kode, kan du se, at jeg tilføjer 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 kendt em enheder er i forhold til det overordnede elements font-size, så ændre font-size af .gallery vil også ændre den beregnede em værdi — dette er det trick, vi bruger. Vi animerer font-size fra en værdi på 0 til en given værdi, og som et resultat bliver gradienten animeret, hvilket gør den udskårne del større, efter størrelsen af ​​det indlejrede billede, der bliver større.

Her er koden, der fremhæver de dele, der er involveret i svæveeffekten:

.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);
}

font-size trick er nyttigt, hvis vi ønsker at animere gradienter eller andre egenskaber, der ikke kan animeres. Brugerdefinerede egenskaber defineret med @property kan løse et sådant problem, men støtte til det mangler stadig i skrivende stund.

Jeg opdagede font-size trick fra @SelenIT2 mens du prøver at løse en udfordring på Twitter.

En anden form? Lad os gå!

Denne gang klippede vi det indlejrede billede i form af en rombe. Jeg vil lade dig dissekere koden som en øvelse for at finde ud af, hvordan vi kom hertil. Du vil bemærke, at strukturen er den samme som i vores eksempler. De eneste forskelle er, hvordan vi bruger gradienten til at skabe formen. Grav ind og lær!

Cirkulært billedgitter

Vi kan kombinere det, vi har lært her og i tidligere artikler, for at lave et endnu mere spændende billedgitter. Lad os denne gang gøre alle billederne i vores gitter cirkulære og, når vi svæver, udvide et billede for at afsløre det hele, mens det dækker resten af ​​billederne.

HTML- og CSS-strukturen i gitteret er ikke noget nyt fra før, så lad os springe den del over og i stedet fokusere på den cirkulære form og svæveeffekt, vi ønsker.

Vi skal bruge clip-path og circle() funktion til - du gættede rigtigt! — skær en cirkel ud af billederne.

Viser de to tilstande af et billede, den naturlige tilstand til venstre og den svævende tilstand til højre, inklusive klippestiværdierne for at skabe dem.
CSS-gitter og brugerdefinerede former, del 2

Den figur illustrerer clip-path brugt til det første billede. Den venstre side viser billedets begyndelsestilstand, mens den højre viser den svævende tilstand. Du kan bruge dette online værktøj at spille og visualisere clip-path værdier.

For de andre billeder kan vi opdatere midten af ​​cirklen (70% 70%) for at 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%));
}

Bemærk, hvordan vi definerer clip-path værdier som et fallback indeni var(). På denne måde kan vi nemmere opdatere værdien ved svævning ved at indstille værdien af --_c variabel. Ved brug circle(), er standardpositionen for midtpunktet 50% 50%, så vi kommer til at udelade det for mere kortfattet kode. Derfor ser du, at vi kun sætter 50% i stedet for 50% at 50% 50%.

Derefter øger vi størrelsen af ​​vores billede, når vi svæver til den overordnede størrelse af gitteret, så vi kan dække de andre billeder. Vi sikrer også z-index har en højere værdi på det svævede billede, så det er det øverste i vores 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;
}

Hvad sker der med place-self ejendom? Hvorfor har vi brug for det, og hvorfor har hvert billede en bestemt værdi?

Kan du huske det problem, vi havde i den forrige artikel, hvornår skabe gitteret af puslespilsbrikker? Vi øgede størrelsen af ​​billederne for at skabe et overløb, men overløbet af nogle billeder var forkert. Vi fiksede dem ved hjælp af place-self ejendom.

Samme problem her. Vi øger størrelsen af ​​billederne, så hver enkelt flyder over sine gitterceller. Men hvis vi ikke gør noget, vil de alle flyde over på højre og nederste side af gitteret. Det vi har brug for er:

  1. det første billede, der løber over den nederste højre kant (standardadfærden),
  2. det andet billede løber over den nederste venstre kant,
  3. det tredje billede til at flyde over den øverste højre kant, og
  4. det fjerde billede for at flyde over den øverste venstre kant.

For at få det, skal vi placere hvert billede korrekt ved hjælp af place-self ejendom.

Diagram, der viser plads-selv-egenskabsværdierne for hver kvadrant i gitteret.
CSS-gitter og brugerdefinerede former, del 2

Hvis du ikke er bekendt med place-self, det er stenografien for justify-self , align-self at placere elementet vandret og lodret. Når det kræver én værdi, bruger begge justeringer den samme værdi.

Udvidelse af billedpaneler

I en tidligere artikel, lavede jeg en fed zoom-effekt, der gælder for et gitter af billeder, hvor vi kan styre alt: antal rækker, antal kolonner, størrelser, skaleringsfaktor osv.

Et særligt tilfælde var de klassiske ekspanderende paneler, hvor vi kun har én række og en beholder i fuld bredde.

Vi vil tage dette eksempel og kombinere det med former!

Inden vi fortsætter, kan jeg varmt anbefale at læse min anden artikel at forstå, hvordan de tricks, vi er ved at dække, virker. Tjek det ud, og vi fortsætter her med at fokusere på at skabe panelformerne.

Lad os først starte med at forenkle koden og fjerne nogle variabler

Vi har kun brug for én række, og antallet af kolonner skal justeres baseret på antallet af billeder. Det betyder, at vi ikke længere har brug for variabler for antallet af rækker (--n) og kolonner (--m ), men vi skal bruge grid-auto-flow: column, hvilket giver gitteret mulighed for automatisk at generere kolonner, når vi tilføjer nye billeder. Vi vil overveje en fast højde for vores container; som standard vil den være i fuld bredde.

Lad os klippe billederne i en skrå form:

Et hovedbillede af en rolig rød ulv, der kigger nedad med toppunkter overlejret, der viser klippestiegenskabspunkterne.
clip-path: polygon(S 0%, 100% 0%, (100% - S) 100%, 0% 100%);

Endnu en gang er hvert billede indeholdt i sin gittercelle, så der er mere plads mellem billederne, end vi ønsker:

Et gitter med seks paneler af skrå billeder af forskellige vilde dyr, der viser gitterlinjerne og hullerne.
CSS-gitter og brugerdefinerede former, del 2

Vi er nødt til at øge bredden af ​​billederne for at skabe et overlap. Vi erstatter min-width: 100% med min-width: calc(100% + var(--s))Hvor --s er en ny variabel, der styrer formen.

Nu skal vi rette de første og sidste billeder, så de på en måde bløder ud af siden uden huller. Med andre ord kan vi fjerne skråningen fra venstre side af det første billede og skråningen fra højre side af det sidste billede. Vi har brug for en ny clip-path specielt til de to billeder.

Vi skal også rette op på overløbet. Som standard vil alle billeder flyde over på begge sider, men for det første har vi brug for et overløb på højre side, mens vi har brug for et venstre overløb til det sidste billede.

.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 resultat er et flot ekspanderende panel af skrå billeder!

Vi kan tilføje så mange billeder, som du vil, og gitteret justeres automatisk. Plus, vi behøver kun at kontrollere én værdi for at kontrollere formen!

Vi kunne have lavet det samme layout med flexbox, da vi har at gøre med en enkelt række elementer. Her er min implementering.

Selvfølgelig er skrå billeder seje, men hvad med et zig-zag-mønster? Jeg har allerede drillet denne kl slutningen af ​​sidste artikel.

Alt jeg gør her er at udskifte clip-path med mask… og gæt hvad? Jeg har allerede en detaljeret artikel om skabe den zig-zag form — for ikke at nævne en online generator for at hente koden. Se, hvordan alt hænger sammen?

Den sværeste del her er at sikre, at zig-zagerne er perfekt justeret, og til dette skal vi tilføje en offset for hver :nth-child(odd) billedelement.

.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));
}

Bemærk brugen af --_p variabel, som vil falde tilbage til 0% men vil være lig med --_s for de mærkelige billeder.

Her er en demo, der illustrerer problemet. Hold musen over for at se, hvordan forskydningen - defineret af --_p — fikser justeringen.

Læg også mærke til, hvordan vi bruger en anden maske til det første og sidste billede, som vi gjorde i det foregående eksempel. Vi skal kun bruge en zig-zag på højre side af det første billede og venstre side af det sidste billede.

Og hvorfor ikke afrundede sider? Lad os gøre det!

Jeg ved godt, at koden kan se skræmmende og svær at forstå, men det eneste, der foregår, er en kombination af forskellige tricks, vi har dækket i denne og andre artikler, jeg allerede har delt. I dette tilfælde bruger jeg den samme kodestruktur som zig-zag og de skrå former. Sammenlign det med disse eksempler, og du vil ikke finde nogen forskel! Det er de samme tricks i min tidligere artikel om zoom-effekten. Så bruger jeg min anden skrift , min online generator for at få koden til masken, der skaber de afrundede former.

Hvis du husker, hvad vi gjorde for zig-zaggen, havde vi brugt den samme maske til alle billederne, men så var vi nødt til at tilføje en forskydning til de ulige billeder for at skabe et perfekt overlap. I dette tilfælde har vi brug for en anden maske til de ulige billeder.

Den første maske:

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-gitter og brugerdefinerede former, del 2 PlatoBlockchain Data Intelligence. Lodret søgning. Ai.

Den anden:

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-gitter og brugerdefinerede former, del 2 PlatoBlockchain Data Intelligence. Lodret søgning. Ai.

Den eneste indsats, jeg gjorde her, var at opdatere den anden maske for at inkludere gap-variablen (--g) for at skabe det mellemrum mellem billederne.

Den sidste touch er at rette det første og sidste billede. Som alle de foregående eksempler skal det første billede have en lige venstre kant, mens det sidste skal have en lige højre kant.

For det første billede ved vi altid, hvilken maske det skal have, hvilket 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 brunt bjørnehovedskud med et bølgemønster til højre kant.
CSS-gitter og brugerdefinerede former, del 2

For det sidste billede afhænger det af antallet af elementer, så det betyder noget, om det element er det :nth-child(odd) or :nth-child(even).

Det komplette gitter af fotos af vilde dyr med alle de korrekte kanter og mellemrum mellem billeder.
CSS-gitter og brugerdefinerede 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 enkelt-rækket gitter af tre vilde dyrefotos med bølgede kanter, hvor det sidste billede er et ulige nummereret element.
CSS-gitter og brugerdefinerede 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 forskellige layouts men de samme CSS-tricks hver gang:

  • kodestrukturen for at skabe zoom-effekten
  • en maske eller clip-bane for at skabe formerne
  • en separat konfiguration for de ulige elementer i nogle tilfælde for at sikre, at vi har et perfekt overlap
  • en specifik konfiguration for det første og sidste billede for at bevare formen på kun den ene side.

Og her er en stor demo med dem alle sammen. Alt du behøver er at tilføje en klasse for at aktivere det layout, du vil se.

Og her er den med Flexbox-implementeringen

Indpakning op

Øv, vi er færdige! Jeg ved, at der er mange CSS-tricks og eksempler mellem denne artikel og den sidste, for ikke at nævne alle de andre tricks, jeg har henvist til her fra andre artikler, jeg har skrevet. Det tog mig tid at sætte alt sammen, og man behøver ikke forstå alt på én gang. Én læsning vil give dig et godt overblik over alle layouts, men du skal muligvis læse artiklen mere end én gang og fokusere på hvert eksempel for at forstå alle tricks.

Har du bemærket, at vi slet ikke rørte ved HTML-koden udover måske antallet af billeder i markeringen? Alle de layouts, vi lavede, deler den samme HTML-kode, som ikke er andet end en liste over billeder.

Inden jeg slutter, vil jeg efterlade dig med et sidste eksempel. Det er et "versus" mellem to anime-karakterer med en cool svæveeffekt.

Hvad med dig? Kan du skabe noget ud fra det, du har lært? Det behøver ikke at være komplekst – forestil dig noget sejt eller sjovt, som jeg gjorde med den anime-matchup. Det kan være en god øvelse for dig, og vi kan afslutte med en fremragende samling i kommentarfeltet.

Tidsstempel:

Mere fra CSS-tricks