Single Element Loaders: Går i 3D! PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Single Element Loaders: Går i 3D!

För denna fjärde och sista artikel i vår liten serie om enelementslastare, vi ska utforska 3D-mönster. När du skapar ett 3D-element är det svårt att föreställa sig att bara ett HTML-element räcker för att simulera något som liknar alla sex ytor i en kub. Men vi kanske kan komma undan med något mer kub-tycka om istället genom att bara visa de tre främre sidorna av formen — det är fullt möjligt och det är vad vi ska göra tillsammans.

Artikelserie

Den delade kubladdaren

Här är en 3D-lastare där en kub är uppdelad i två delar, men är bara gjord med bara ett enda element:

CodePen Bädda in reserv

Varje halva av kuben är gjord med hjälp av ett pseudoelement:

Single Element Loaders: Går i 3D! PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
Single Element Loaders: Går i 3D!

Coolt va?! Vi kan använda en konisk gradient med CSS clip-path på elementets ::before och ::after pseudos för att simulera de tre synliga ytorna i en 3D-kub. Negativ marginal är det som drar ihop de två pseudos för att överlappa och simulera en hel kub. Resten av vårt arbete är mest att animera dessa två halvor för att få snygga lastare!

Låt oss kolla in en bild som förklarar matematiken bakom klippvägspunkterna som används för att skapa detta kubliknande element:

Single Element Loaders: Går i 3D! PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
Single Element Loaders: Går i 3D!

Vi har våra variabler och en ekvation, så låt oss få dem att fungera. Först kommer vi att fastställa våra variabler och ställa in storleken för huvudet .loader element:

.loader { --s: 150px; /* control the size */ --_d: calc(0.353 * var(--s)); /* 0.353 = sin(45deg)/2 */ width: calc(var(--s) + var(--_d)); aspect-ratio: 1; display: flex;
}

Inget för galet än så länge. Vi har en 150px kvadrat som är inrättad som en flexibel behållare. Nu etablerar vi våra pseudos:

.loader::before,
.loader::after { content: ""; flex: 1;
}

Det är två halvor i .loader behållare. Vi måste måla in dem, så det är där vårt konisk gradient sparkar in:

.loader::before,
.loader::after { content: ""; flex: 1; background: conic-gradient(from -90deg at calc(100% - var(--_d)) var(--_d), #fff 135deg, #666 0 270deg, #aaa 0);
}

Gradienten finns där, men det ser konstigt ut. Vi måste fäst den vid elementet:

.loader::before,
.loader::after { content: ""; flex: 1; background: conic-gradient(from -90deg at calc(100% - var(--_d)) var(--_d), #fff 135deg, #666 0 270deg, #aaa 0); clip-path: polygon(var(--_d) 0, 100% 0, 100% calc(100% - var(--_d)), calc(100% - var(--_d)) 100%, 0 100%, 0 var(--_d));
}

Låt oss se till att de två halvorna överlappar med a negativ marginal:

.loader::before { margin-right: calc(var(--_d) / -2);
} .loader::after { margin-left: calc(var(--_d) / -2);
}

Låt oss nu få dem att flytta!

.loader::before,
.loader::after { /* same as before */ animation: load 1.5s infinite cubic-bezier(0, .5, .5, 1.8) alternate;
} .loader::after { /* same as before */ animation-delay: -.75s
} @keyframes load{ 0%, 40% { transform: translateY(calc(var(--s) / -4)) } 60%, 100% { transform: translateY(calc(var(--s) / 4)) }
}

Här är den sista demon igen:

CodePen Bädda in reserv

Förloppskubladdaren

Låt oss använda samma teknik för att skapa en 3D progress loader. Ja, fortfarande bara ett element!

CodePen Bädda in reserv

Vi ändrar inte en sak när det gäller att simulera kuben på samma sätt som vi gjorde tidigare, annat än att ändra lastarens höjd och bildförhållande. Animationen vi gör bygger på en förvånansvärt enkel teknik där vi uppdaterar bredden på vänster sida medan höger sida fyller det återstående utrymmet, tack vare flex-grow: 1.

Det första steget är att lägga till lite transparens på höger sida med hjälp av opacity:

CodePen Bädda in reserv

Detta simulerar effekten att ena sidan av kuben fylls i medan den andra är tom. Sedan uppdaterar vi färgen på vänster sida. För att göra det uppdaterar vi antingen de tre färgerna inuti den koniska gradienten eller så gör vi det genom att lägga till en bakgrundsfärg med en background-blend-mode:

.loader::before { background-color: #CC333F; /* control the color here */ background-blend-mode: multiply;
}

Detta trick låter oss bara uppdatera färgen en gång. Den högra sidan av lastaren smälter in med de tre nyanserna av vitt från den koniska gradienten för att skapa tre nya nyanser av vår färg, även om vi bara använder ett färgvärde. Färglurar!

CodePen Bädda in reserv

Låt oss animera bredden på lastarens vänstra sida:

CodePen Bädda in reserv

Oj, animationen är lite konstig i början! Lägg märke till hur det liksom börjar utanför kuben? Detta beror på att vi startar animeringen vid 0% bredd. Men på grund av clip-path och negativ marginal vi använder, vad vi behöver göra istället är att utgå från vår --_d variabel, som vi använde för att definiera clip-path poäng och den negativa marginalen:

@keyframes load { 0%, 5% {width: var(--_d); } 95%, 100% {width: 100%; }
}

Det är lite bättre:

CodePen Bädda in reserv

Men vi kan göra den här animationen ännu smidigare. Har du märkt att vi saknar något? Låt mig visa dig en skärmdump för att jämföra hur den slutliga demot ska se ut med den sista demon:

Single Element Loaders: Går i 3D! PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Det är undersidan av kuben! Eftersom det andra elementet är genomskinligt måste vi se undersidan av den rektangeln som du kan se i det vänstra exemplet. Det är subtilt, men borde finnas där!

Vi kan lägga till en gradient till huvudelementet och klippa det som vi gjorde med pseudos:

background: linear-gradient(#fff1 0 0) bottom / 100% var(--_d) no-repeat;

Här är hela koden när allt har dragits ihop:

.loader { --s: 100px; /* control the size */ --_d: calc(0.353*var(--s)); /* 0.353 = sin(45deg) / 2 */ height: var(--s); aspect-ratio: 3; display: flex; background: linear-gradient(#fff1 0 0) bottom / 100% var(--_d) no-repeat; clip-path: polygon(var(--_d) 0, 100% 0, 100% calc(100% - var(--_d)), calc(100% - var(--_d)) 100%, 0 100%, 0 var(--_d));
}
.loader::before,
.loader::after { content: ""; clip-path: inherit; background: conic-gradient(from -90deg at calc(100% - var(--_d)) var(--_d), #fff 135deg, #666 0 270deg, #aaa 0);
}
.loader::before { background-color: #CC333F; /* control the color here */ background-blend-mode: multiply; margin-right: calc(var(--_d) / -2); animation: load 2.5s infinite linear;
}
.loader:after { flex: 1; margin-left: calc(var(--_d) / -2); opacity: 0.4;
} @keyframes load { 0%, 5% { width: var(--_d); } 95%, 100% { width: 100%; }
}
CodePen Bädda in reserv

Det är allt! Vi använde precis en smart teknik som använder pseudoelement, koniska gradienter, klippning, bakgrundsblandning och negativa marginaler för att få, inte en, men två söta 3D-lastare med inget mer än ett enda element i markeringen.

Mer 3D

Vi kan fortfarande gå längre och simulera ett oändligt antal 3D-kuber med ett element — ja, det är möjligt! Här är ett rutnät med kuber:

CodePen Bädda in reserv

Denna demon och följande demos stöds inte i Safari i skrivande stund.

Galet, eller hur? Nu skapar vi ett upprepat mönster av kuber gjorda med ett enda element ... och inga pseudos heller! Jag kommer inte att gå in på detaljer om matematiken vi använder (det finns mycket specifika siffror där) men här är en figur för att visualisera hur vi kom hit:

Single Element Loaders: Går i 3D! PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.
Single Element Loaders: Går i 3D!

Vi använder först a conic-gradient för att skapa det upprepade kubmönstret. Upprepningen av mönstret styrs av tre variabler:

  • --size: Trogen namnet styr detta storleken på varje kub.
  • --m: Detta representerar antalet kolumner.
  • --n: Detta är antalet rader.
  • --gap: detta gapet eller avståndet mellan kuberna
.cube { --size: 40px; --m: 4; --n: 5; --gap :10px; aspect-ratio: var(--m) / var(--n); width: calc(var(--m) * (1.353 * var(--size) + var(--gap))); background: conic-gradient(from -90deg at var(--size) calc(0.353 * var(--size)), #249FAB 135deg, #81C5A3 0 270deg, #26609D 0) /* update the colors here */ 0 0 / calc(100% / var(--m)) calc(100% / var(--n));
}

Sedan applicerar vi ett masklager med ett annat mönster med samma storlek. Det här är den svåraste delen av denna idé. Att använda en kombination av en linear-gradient och en conic-gradient vi kommer att skära ut några delar av vårt element för att endast kubformerna ska vara synliga.

.cube { /* etc. */ mask: linear-gradient(to bottom right, #0000 calc(0.25 * var(--size)), #000 0 calc(100% - calc(0.25 * var(--size)) - 1.414 * var(--gap)), #0000 0), conic-gradient(from -90deg at right var(--gap) bottom var(--gap), #000 90deg, #0000 0); mask-size: calc(100% / var(--m)) calc(100% / var(--n)); mask-composite: intersect;
}

Koden kan se lite komplex ut men tack vare CSS-variabler behöver vi bara uppdatera några värden för att kontrollera vår matris av kuber. Behöver du ett 10⨉10 rutnät? Uppdatera --m och --n variabler till 10. Behöver du ett större mellanrum mellan kuberna? Uppdatera --gap värde. Färgvärdena används bara en gång, så uppdatera dem för en ny färgpalett!

Nu när vi har en annan 3D-teknik, låt oss använda den för att bygga varianter av laddaren genom att leka med olika animationer. Vad sägs till exempel om ett upprepat mönster av kuber som glider oändligt från vänster till höger?

CodePen Bädda in reserv

Den här laddaren definierar fyra kuber i en enda rad. Det betyder vår --n värdet är 4 och --m är lika med 1 . Dessa behöver vi med andra ord inte längre!

Istället kan vi arbeta med --size och --gap variabler i en rutnätsbehållare:

.loader { --size: 70px; --gap: 15px; width: calc(3 * (1.353 * var(--size) + var(--gap))); display: grid; aspect-ratio: 3;
}

Det här är vår container. Vi har fyra kuber, men vill bara visa tre i behållaren åt gången så att vi alltid har en som glider in när en glider ut. Det är därför vi tar hänsyn till bredden 3 och ha bildförhållandet inställt på 3 också.

Låt oss se till att vårt kubmönster är inställt för bredden av fyra kuber. Vi ska göra detta på containerns ::before pseudoelement:

.loader::before { content: ""; width: calc(4 * 100% / 3); /* Code to create four cubes */
}

Nu när vi har fyra kuber i en trekubsbehållare kan vi motivera kubmönstret till slutet av rutnätsbehållaren för att svämma över det, och visa de tre sista kuberna:

.loader { /* same as before */ justify-content: end;
}

Här är vad vi har hittills, med en röd kontur för att visa gränserna för rutnätsbehållaren:

CodePen Bädda in reserv

Nu behöver vi bara flytta pseudoelementet till höger genom att lägga till vår animation:

@keyframes load { to { transform: translate(calc(100% / 4)); }
}
CodePen Bädda in reserv

Förstod du tricket med animationen? Låt oss avsluta detta genom att dölja det överfulla kubmönstret och genom att lägga till en touch av maskering för att skapa den blekningseffekt som börjar och slutet:

.loader { --size: 70px; --gap: 15px; width: calc(3*(1.353*var(--s) + var(--g))); display: grid; justify-items: end; aspect-ratio: 3; overflow: hidden; mask: linear-gradient(90deg, #0000, #000 30px calc(100% - 30px), #0000);
}
CodePen Bädda in reserv

Vi kan göra detta mycket mer flexibelt genom att införa en variabel, --n, för att ställa in hur många kuber som ska visas i behållaren samtidigt. Och eftersom det totala antalet kuber i mönstret bör vara en mer än --n, vi kan uttrycka det som calc(var(--n) + 1).

Här är hela grejen:

CodePen Bädda in reserv

OK, ytterligare en 3D-laddare som är liknande men där kuberna ändrar färg i följd istället för att glida:

CodePen Bädda in reserv

Vi kommer att förlita oss på en animerad bakgrund med background-blend-mode för den här:

.loader { /* ... */ background: linear-gradient(#ff1818 0 0) 0% / calc(100% / 3) 100% no-repeat, /* ... */; background-blend-mode: multiply; /* ... */ animation: load steps(3) 1.5s infinite;
}
@keyframes load { to { background-position: 150%; }
}

Jag har tagit bort den överflödiga koden som användes för att skapa samma layout som förra exemplet, men med tre kuber istället för fyra. Det jag lägger till här är en gradient definierad med en specifik färg som smälter samman med den koniska gradienten, precis som vi gjorde tidigare för 3D-lastaren för förloppsindikatorn.

Därifrån animerar den bakgrundsgradienten background-position som en trestegsanimering för att få kuberna att blinka färger en i taget.

Om du inte är bekant med de värden jag använder för background-position och bakgrundssyntaxen rekommenderar jag starkt en av mina tidigare artiklar och en av mina Stack Overflow svar. Du hittar en mycket detaljerad förklaring där.

Kan vi uppdatera antalet kuber för att göra det till variabler?

Ja, jag har en lösning för det, men jag skulle vilja att du tar ett öga på det istället för att bädda in det här. Ta det vi har lärt oss från det tidigare exemplet och försök att göra detsamma med det här - dela sedan ditt arbete i kommentarerna!

Variationer i massor!

Precis som de andra tre artiklarna i den här serien skulle jag vilja ge dig lite inspiration för att gå vidare och skapa dina egna lastare. Här är en samling som inkluderar de 3D-lastare vi gjorde tillsammans, plus några andra för att få fart på din fantasi:

CodePen Bädda in reserv

Vi är klara

Jag hoppas verkligen att du njöt av att tillbringa tid med att göra enelementslastare med mig de senaste veckorna. Det är galet att vi började med en till synes enkel spinner och sedan gradvis lade till nya bitar för att arbeta oss hela vägen upp till 3D-tekniker som fortfarande bara använder ett enda element i markeringen. Det är precis så här CSS ser ut när vi utnyttjar dess krafter: skalbar, flexibel och återanvändbar.

Tack igen för att du läser denna lilla serie! Jag skriver under genom att påminna dig om att jag har en samling av mer än 500 lastare om du letar efter fler idéer och inspiration.

Artikelserie


Single Element Loaders: Går i 3D! ursprungligen publicerad på CSS-tricks. Du borde få nyhetsbrevet.

Tidsstämpel:

Mer från CSS-tricks