CSS-rutnät och anpassade former, del 2 PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

CSS-rutnät och anpassade former, del 2

Okej, alltså senast vi checkade in, använde vi CSS Grid och kombinerade dem med CSS clip-path och mask tekniker för att skapa rutnät med snygga former.

Här är bara ett av de fantastiska rutnäten vi gjorde tillsammans:

Redo för andra omgången? Vi arbetar fortfarande med CSS Grid, clip-pathoch mask, men i slutet av den här artikeln kommer vi att sluta med olika sätt att ordna bilder på rutnätet, inklusive några rad svävningseffekter som ger en autentisk, interaktiv upplevelse att visa bilder.

Och gissa vad? Vi använder samma uppmärkning som vi använde förra gången. Här är det igen:

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

Liksom föregående artikel behöver vi bara en behållare med bilder inuti. Inget mer!

Kapslad bildrutnät

Förra gången var våra rutnät, ja, typiska bildrutnät. Förutom de snygga formerna vi maskerade dem med, var de ganska vanliga symmetriska rutnät när det gäller hur vi placerade bilderna inuti.

Låt oss försöka kapsla en bild i mitten av rutnätet:

Vi börjar med att ställa in ett 2✕2-rutnät för fyra 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;
}

Inget komplicerat än. Nästa steg är att klippa hörnet av våra bilder för att skapa utrymme för den kapslade bilden. Jag har redan en detaljerad artikel om hur man skär hörn med hjälp av clip-path och mask. Du kan också använda min online generator för att få CSS för att maskera hörn.

Vad vi behöver här är att skära ut hörnen i en vinkel lika med 90deg. Vi kan använda samma sak konisk gradientteknik från den artikeln för att göra 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 skulle kunna använda clip-path metod för att skära hörn från samma artikel, men maskering med gradienter är mer lämplig här eftersom vi har samma konfiguration för alla bilder - allt vi behöver är en rotation (definierad med variabeln --_a) få effekten, så vi maskerar från insidan istället för de yttre kanterna.

CSS-rutnät och anpassade former, del 2

Nu kan vi placera den kapslade bilden i det maskerade utrymmet. Låt oss först se till att vi har ett femte bildelement i HTML:en:

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

Vi kommer att förlita oss på den goda, absoluta positioneringen för att placera den där:

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

Smakämnen inset egenskapen tillåter oss att placera bilden i centrum med en enda deklaration. Vi vet storleken på bilden (definierad med variabeln --s), och vi vet att behållarens storlek är lika med 100 %. Vi gör lite matte, och avståndet från varje kant ska vara lika med (100% - var(--s))/2.

Diagram över de bredder som behövs för att slutföra designen.
CSS-rutnät och anpassade former, del 2

Du kanske undrar varför vi använder clip-path alls här. Vi använder den med den kapslade bilden för att få ett konsekvent gap. Om vi ​​skulle ta bort det skulle du märka att vi inte har samma gap mellan alla bilder. På så sätt skär vi en liten bit från den femte bilden för att få rätt avstånd runt den.

Hela koden 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 kanske många av er också undrar: varför alla de komplexa sakerna när vi kan placera den sista bilden på toppen och lägga till en kant på den? Det skulle dölja bilderna under den kapslade bilden utan en mask, eller hur?

Det är sant, och vi får följande:

Nej mask, Nr clip-path. Ja, koden är lätt att förstå, men det finns en liten nackdel: kantfärgen måste vara densamma som huvudbakgrunden för att göra illusionen perfekt. Denna lilla nackdel räcker för mig för att göra koden mer komplex i utbyte mot verklig transparens oberoende av bakgrunden. Jag säger inte att en gränsstrategi är dålig eller fel. Jag skulle rekommendera det i de flesta fall där bakgrunden är känd. Men vi är här för att utforska nya saker och, viktigast av allt, bygga komponenter som inte är beroende av deras miljö.

Låt oss prova en annan form den här gången:

Den här gången gjorde vi den kapslade bilden till en cirkel istället för en kvadrat. Det är en lätt uppgift border-radius Men vi måste använda en cirkulär utskärning för de andra bilderna. Den här gången kommer vi dock att förlita oss på en radial-gradient() istället för a conic-gradient() för att få den där snygga rundade looken.

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

Alla bilder använder samma konfiguration som föregående exempel, men vi uppdaterar mittpunkten varje gång.

Diagram som visar mittvärdena för varje kvadrant i rutnätet.
CSS-rutnät och anpassade former, del 2

Ovanstående figur illustrerar mittpunkten för varje cirkel. Ändå, i själva koden kommer du att märka att jag också tar hänsyn till gapet för att säkerställa att alla punkter är i samma position (mitten av rutnätet) för att få en kontinuerlig cirkel om vi kombinerar dem.

Nu när vi har vår layout, låt oss prata om hovringseffekten. Om du inte märkte det, ökar en cool hovringseffekt storleken på den kapslade bilden och justerar allt annat därefter. Att öka storleken är en relativt enkel uppgift, men att uppdatera övertoningen är mer komplicerad eftersom övertoningar som standard inte kan animeras. För att övervinna detta kommer jag att använda en font-size hacka för att kunna animera den radiella gradienten.

Om du kollar koden för gradienten kan du se att jag lägger till 1em:

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

Det är känt att em enheter är relativa till det överordnade elementets font-size, så att ändra font-size av .gallery kommer också att ändra den beräknade em värde — det här är tricket vi använder. Vi animerar font-size från ett värde på 0 till ett givet värde och som ett resultat animeras övertoningen, vilket gör den utskurna delen större, efter storleken på den kapslade bilden som blir större.

Här är koden som framhäver delarna som är involverade i hovringseffekten:

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

Smakämnen font-size trick är användbart om vi vill animera gradienter eller andra egenskaper som inte kan animeras. Anpassade egenskaper definierade med @property kan lösa ett sådant problem, men stöd för det saknas fortfarande i skrivande stund.

Jag upptäckte font-size trick från @SelenIT2 samtidigt som man försöker lösa en utmaning på Twitter.

En annan form? Nu går vi!

Den här gången klippte vi den kapslade bilden till formen av en romb. Jag låter dig dissekera koden som en övning för att ta reda på hur vi kom hit. Du kommer att märka att strukturen är densamma som i våra exempel. De enda skillnaderna är hur vi använder gradienten för att skapa formen. Gräv in och lär dig!

Cirkulär bildrutnät

Vi kan kombinera det vi har lärt oss här och i tidigare artiklar för att göra ett ännu mer spännande bildrutnät. Den här gången, låt oss göra alla bilderna i vårt rutnät cirkulära och expandera en bild när du håller muspekaren för att avslöja allt eftersom det täcker resten av fotona.

HTML- och CSS-strukturen i rutnätet är inget nytt sedan tidigare, så låt oss hoppa över den delen och fokusera istället på den cirkulära formen och svävningseffekten vi vill ha.

Vi ska använda clip-path och dess circle() funktion till - du gissade rätt! — skär ut en cirkel ur bilderna.

Visar de två tillstånden för en bild, det naturliga tillståndet till vänster och det svävade tillståndet till höger, inklusive klippvägsvärdena för att skapa dem.
CSS-rutnät och anpassade former, del 2

Den figuren illustrerar clip-path används för den första bilden. Den vänstra sidan visar bildens initiala tillstånd, medan den högra visar det svävade tillståndet. Du kan använda detta onlineverktyg att spela och visualisera clip-path värden.

För de andra bilderna kan vi uppdatera mitten av cirkeln (70% 70%) för att få följande kod:

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

Notera hur vi definierar clip-path värden som ett fallback inuti var(). På detta sätt kan vi enklare uppdatera värdet vid hovring genom att ställa in värdet på --_c variabel. När man använder circle(), är standardpositionen för mittpunkten 50% 50%, så vi får utelämna det för mer koncis kod. Det är därför du ser att vi bara ställer 50% istället för 50% at 50% 50%.

Sedan ökar vi storleken på vår bild när vi svävar till den totala storleken på rutnätet så att vi kan täcka de andra bilderna. Vi säkerställer också z-index har ett högre värde på den svävade bilden, så det är den översta i vår staplingssammanhang.

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

Vad händer med place-self fast egendom? Varför behöver vi det och varför har varje bild ett specifikt värde?

Kommer du ihåg problemet vi hade i förra artikeln när skapa rutnätet av pusselbitar? Vi ökade storleken på bilderna för att skapa ett överflöde, men överflödet av vissa bilder var felaktigt. Vi fixade dem med hjälp av place-self fast egendom.

Samma fråga här. Vi ökar storleken på bilderna så att var och en svämmar över sina rutnätsceller. Men om vi inte gör något kommer alla att svämma över på höger och undersida av nätet. Det vi behöver är:

  1. den första bilden som svämmar över den nedre högra kanten (standardbeteendet),
  2. den andra bilden svämmar över den nedre vänstra kanten,
  3. den tredje bilden för att svämma över den övre högra kanten, och
  4. den fjärde bilden för att svämma över den övre vänstra kanten.

För att få det måste vi placera varje bild korrekt med hjälp av place-self fast egendom.

Diagram som visar platssjälvegenskapsvärdena för varje kvadrant i rutnätet.
CSS-rutnät och anpassade former, del 2

Om du inte är bekant med place-self, det är förkortningen för justify-self och align-self för att placera elementet horisontellt och vertikalt. När det krävs ett värde använder båda justeringarna samma värde.

Expandera bildpaneler

I en tidigare artikel, skapade jag en cool zoomeffekt som gäller ett rutnät av bilder där vi kan styra allt: antal rader, antal kolumner, storlekar, skalfaktor osv.

Ett speciellt fall var de klassiska expanderande panelerna, där vi bara har en rad och en fullbreddsbehållare.

Vi tar det här exemplet och kombinerar det med former!

Innan vi fortsätter rekommenderar jag starkt att läsa min annan artikel för att förstå hur de knep vi ska täcka fungerar. Kolla in det, så fortsätter vi här med att fokusera på att skapa panelformerna.

Låt oss först börja med att förenkla koden och ta bort några variabler

Vi behöver bara en rad och antalet kolumner bör justeras utifrån antalet bilder. Det betyder att vi inte längre behöver variabler för antalet rader (--n) och kolumner (--m ) men vi måste använda grid-auto-flow: column, vilket låter rutnätet automatiskt generera kolumner när vi lägger till nya bilder. Vi kommer att överväga en fast höjd för vår container; som standard kommer den att vara i full bredd.

Låt oss klippa bilderna i en lutande form:

Ett huvudbild av en lugn röd varg som tittar nedåt med hörn överlagrade och visar egenskaperna för klippbanan.
clip-path: polygon(S 0%, 100% 0%, (100% - S) 100%, 0% 100%);

Återigen finns varje bild i sin rutnätscell, så det finns mer utrymme mellan bilderna än vi skulle vilja:

Ett rutnät med sex paneler med lutande bilder av olika vilda djur som visar rutnätets linjer och luckor.
CSS-rutnät och anpassade former, del 2

Vi måste öka bredden på bilderna för att skapa en överlappning. Vi byter ut min-width: 100% med min-width: calc(100% + var(--s))Där --s är en ny variabel som styr formen.

Nu måste vi fixa de första och sista bilderna, så att de liksom blöder från sidan utan luckor. Med andra ord kan vi ta bort lutningen från den vänstra sidan av den första bilden och lutningen från den högra sidan av den sista bilden. Vi behöver en ny clip-path speciellt för dessa två bilder.

Vi måste också åtgärda brädden. Som standard kommer alla bilder att svämma över på båda sidor, men för den första behöver vi ett spill på höger sida medan vi behöver ett överflöd till vänster för den sista bilden.

.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 slutliga resultatet är en snygg expanderande panel med lutande bilder!

Vi kan lägga till så många bilder du vill, och rutnätet justeras automatiskt. Dessutom behöver vi bara kontrollera ett värde för att kontrollera formen!

Vi kunde ha gjort samma layout med flexbox eftersom vi har att göra med en enda rad med element. Här är min implementering.

Visst, lutande bilder är coola, men hur är det med ett sicksackmönster? Jag har redan retat den här kl slutet av den sista artikeln.

Allt jag gör här är att byta ut clip-path med mask… och gissa vad? Jag har redan en detaljerad artikel om skapa den där sicksackformen — för att inte tala om en online generator för att få koden. Ser du hur allt går ihop?

Det svåraste här är att se till att sicksackarna är perfekt anpassade, och för detta måste vi lägga till en offset för varje :nth-child(odd) bildelement.

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

Notera användningen av --_p variabel, som kommer att falla tillbaka till 0% men kommer att vara lika med --_s för de udda bilderna.

Här är en demo som illustrerar problemet. Håll muspekaren för att se hur förskjutningen - definieras av --_p — fixar inriktningen.

Lägg också märke till hur vi använder en annan mask för den första och sista bilden som vi gjorde i föregående exempel. Vi behöver bara en sicksack på höger sida av den första bilden och vänster sida av den sista bilden.

Och varför inte rundade sidor? Vi gör det!

Jag vet att koden kan se skrämmande och svår att förstå, men allt som händer är en kombination av olika knep som vi har tagit upp i den här och andra artiklar som jag redan har delat. I det här fallet använder jag samma kodstruktur som zig-zaggen och de lutande formerna. Jämför det med dessa exempel, så kommer du inte att se någon skillnad! Det är samma knep i min tidigare artikel om zoomeffekten. Sedan använder jag min annat skrivande och min online-generator för att få koden för masken som skapar de rundade formerna.

Om du kommer ihåg vad vi gjorde för zig-zaggen, hade vi använt samma mask för alla bilder men sedan var tvungna att lägga till en förskjutning till de udda bilderna för att skapa en perfekt överlappning. I det här fallet behöver vi en annan mask för de udda numrerade bilderna.

Den första 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-rutnät och anpassade former, del 2 PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Den andra:

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-rutnät och anpassade former, del 2 PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Det enda jag gjorde här är att uppdatera den andra masken för att inkludera gapvariabeln (--g) för att skapa det utrymmet mellan bilderna.

Sista handen är att fixa den första och sista bilden. Liksom alla tidigare exempel behöver den första bilden en rak vänsterkant medan den sista behöver en rak högerkant.

För den första bilden vet vi alltid vilken mask den behöver ha, vilket är följande:

.gallery > img:first-child {
  mask: 
    radial-gradient(calc(var(--s) + var(--g)) at right, #0000 98%, #000) 50% / 100% calc(1.8 * var(--s));
}
En brun björn med ett vågmönster för den högra bården.
CSS-rutnät och anpassade former, del 2

För den sista bilden beror det på antalet element, så det spelar roll om det elementet är det :nth-child(odd) or :nth-child(even).

Det kompletta rutnätet med foton av vilda djur med alla de korrekta gränserna och luckorna mellan bilderna.
CSS-rutnät och anpassade 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
}
Ett rutnät på en rad med tre foton av vilda djur med vågiga kanter där den sista bilden är ett udda nummer.
CSS-rutnät och anpassade 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 är allt! Tre olika layouter men samma CSS-trick varje gång:

  • kodstrukturen för att skapa zoomeffekten
  • en mask eller klippbana för att skapa formerna
  • en separat konfiguration för de udda elementen i vissa fall för att se till att vi har en perfekt överlappning
  • en specifik konfiguration för den första och sista bilden för att behålla formen på endast en sida.

Och här är en stor demo med dem alla tillsammans. Allt du behöver är att lägga till en klass för att aktivera layouten du vill se.

Och här är den med Flexbox-implementeringen

Inslagning upp

Oj, vi är klara! Jag vet att det finns många CSS-trick och exempel mellan den här artikeln och den förra, för att inte tala om alla andra knep som jag har refererat till här från andra artiklar jag har skrivit. Det tog mig tid att sätta ihop allt, och du behöver inte förstå allt på en gång. En läsning ger dig en bra överblick över alla layouter, men du kan behöva läsa artikeln mer än en gång och fokusera på varje exempel för att förstå alla knep.

Har du märkt att vi inte rörde HTML alls förutom kanske antalet bilder i markeringen? Alla layouter vi gjorde delar samma HTML-kod, vilket är inget annat än en lista med bilder.

Innan jag avslutar ska jag lämna er med ett sista exempel. Det är ett "mot" mellan två animekaraktärer med en cool svävningseffekt.

Hur är det med dig? Kan du skapa något utifrån det du har lärt dig? Det behöver inte vara komplicerat – föreställ dig något coolt eller roligt som jag gjorde med den där anime-matchen. Det kan vara en bra övning för dig, och vi kanske avslutar med en utmärkt samling i kommentarsfältet.

Tidsstämpel:

Mer från CSS-tricks