Fancy bilddekorationer: Single Element Magic PlatoBlockchain Data Intelligence. Vertikal sökning. Ai.

Fancy bilddekorationer: Single Element Magic

Som rubriken säger, vi ska dekorera bilder! Det finns ett gäng andra artiklar där ute som talar om detta, men det vi tar upp här är ganska annorlunda eftersom det är mer av en utmaning. Utmaningen? Dekorera en bild med endast tagg och inget mer.

Just det, ingen extra markering, inga divs och inga pseudo-element. Bara en tagg.

Låter svårt, eller hur? Men i slutet av den här artikeln – och de andra som utgör den här lilla serien – ska jag bevisa att CSS är tillräckligt kraftfull för att ge oss fantastiska och fantastiska resultat trots begränsningen av att arbeta med ett enda element.

Fancy bilddekorationsserie

  • Single Element Magic — du är här
  • Masker och avancerade svävningseffekter (kommer den 21 oktober )
  • Konturer och komplexa animationer (kommer den 28 oktober )

Låt oss börja med vårt första exempel

Innan vi gräver i koden, låt oss räkna upp möjligheterna för att styla en utan några extra element eller pseudoelement. Vi kan använda border, box-shadow, outline, och naturligtvis, background. Det kan se konstigt ut att lägga till en bakgrund till en bild eftersom vi inte kan se den eftersom den kommer att vara bakom bilden - men tricket är att skapa utrymme runt bilden med hjälp av padding och / eller border och rita sedan vår bakgrund i det utrymmet.

Jag tror att du vet vad som kommer härnäst sedan jag pratade om background, höger? Ja, gradienter! Alla dekorationer vi ska göra förlitar sig på många gradienter. Om du har följde mig ett tag tror jag att detta förmodligen inte kommer som någon överraskning för dig alls. 😁

Låt oss gå tillbaka till vårt första exempel:

img {
  --s: 10px; /* control the size */
  padding: var(--s);
  border: calc(2 * var(--s)) solid #0000;
  outline: 1px solid #000;
  outline-offset: calc(-1 * var(--s));
  background: conic-gradient(from 90deg at 1px 1px, #0000 25%, #000 0);
}

Vi definierar padding och en transparent border med hjälp av variabeln --s att skapa ett utrymme runt vår bild lika med tre gånger så stor variabel.

Varför använder vi båda padding och border istället för det ena eller det andra? Vi kan få genom att bara använda en av dem men jag behöver den här kombinationen för min gradient eftersom, som standard, startvärdet för background-clip is border-box och background-origin är lika med padding-box.

Här är en steg-för-steg-illustration för att förstå logiken:

Inledningsvis har vi inga kanter på bilden, så vår gradient kommer att skapa två segment med 1px av tjocklek. (Jag använder 3px i denna specifika demo så att det är lättare att se.) Vi lägger till en färgad kant och gradienten ger oss fortfarande samma resultat inne i utfyllnadsområdet (pga. background-origin) men det upprepas bakom gränsen. Om vi ​​gör färgen på bården transparent kan vi använda upprepningen och vi får den ram vi vill ha.

Smakämnen outline i demon har en negativ offset. Det skapar en fyrkantig form överst i gradienten. Det är allt! Vi lade till en snygg dekoration till vår bild med en gradient och en outline. Vi kunde ha använt fler gradienter! Men jag försöker alltid hålla min kod så enkel som möjligt och jag upptäckte att lägga till en outline är bättre så.

Här är en lösning med enbart gradient där jag bara använder padding att definiera utrymmet. Fortfarande samma resultat men med en mer komplex syntax.

Låt oss prova en annan idé:

För den här tog jag det tidigare exemplet bort outline, och tillämpade en clip-path för att skära lutningen på varje sida. De clip-path värdet är lite mångsidigt och förvirrande men här är en illustration för att bättre se dess poäng:

Fancy bilddekorationer: Single Element Magic

Jag tror att du förstår huvudtanken. Vi kommer att kombinera bakgrunder, konturer, klippning och lite maskering för att åstadkomma olika sorters dekorationer. Vi kommer också att överväga några coola svävningsanimationer som en extra bonus! Det vi har tittat på hittills är bara en liten översikt över vad som kommer!

Ramen endast för hörn

Den här tar fyra gradienter. Varje gradient täcker ett hörn och när vi håller muspekaren expanderar vi dem för att skapa en hel ram runt bilden. Låt oss dissekera koden för en av gradienterna:

--b: 5px; /* border thickness */
background: conic-gradient(from 90deg at top var(--b) left var(--b), #0000 90deg, darkblue 0) 0 0;
background-size: 50px 50px; 
background-repeat: no-repeat;

Vi ska rita en gradient med en storlek lika med 50px 50px och placera den i det övre vänstra hörnet (0 0). För gradientens konfiguration, här är en steg-för-steg-illustration som visar hur jag nådde det resultatet.

Vi tenderar att tro att gradienter bara är bra för att växla mellan två färger. Men i verkligheten kan vi göra så mycket mer med dem! De är särskilt användbara när det gäller att skapa olika former. Tricket är att se till att vi har hårda stopp mellan färgerna - som i exemplet ovan - snarare än mjuka övergångar:

#0000 25%, darkblue 0

Detta är i princip att säga: "fyll gradienten med en transparent färg tills 25% av området, fyll sedan det återstående området med darkblue.

Du kanske kliar dig i huvudet över 0 värde. Det är ett litet hack för att förenkla syntaxen. I verkligheten borde vi använda detta för att göra ett hårt stopp mellan färgerna:

#0000 25%, darkblue 25%

Det är mer logiskt! Den genomskinliga färgen slutar kl 25% och darkblue börjar precis där transparensen slutar, vilket gör ett hårt stopp. Om vi ​​ersätter den andra med 0, kommer webbläsaren att göra jobbet åt oss, så det är ett lite mer effektivt sätt att gå tillväga.

Någonstans i specifikationen, det står:

Om en färgstopp or övergångstips har en position som är mindre än den angivna positionen för något färgstopp eller övergångstips före sig i listan, ställ in dess position till att vara lika med den största angivna positionen för något färgstopp eller övergångstips före den.

0 är alltid mindre än något annat värde, så webbläsaren kommer alltid att konvertera det till det största värdet som kommer före det i deklarationen. I vårt fall är den siffran 25%.

Nu tillämpar vi samma logik på alla hörn och vi avslutar med följande kod:

img {
  --b: 5px; /* border thickness */
  --c: #0000 90deg, darkblue 0; /* define the color here */
  padding: 10px;
  background:
    conic-gradient(from 90deg  at top    var(--b) left  var(--b), var(--c)) 0 0,
    conic-gradient(from 180deg at top    var(--b) right var(--b), var(--c)) 100% 0,
    conic-gradient(from 0deg   at bottom var(--b) left  var(--b), var(--c)) 0 100%,
    conic-gradient(from -90deg at bottom var(--b) right var(--b), var(--c)) 100% 100%;
  background-size: 50px 50px; /* adjust border length here */
  background-repeat: no-repeat;
}

Jag har introducerat CSS-variabler för att undvika viss redundans eftersom alla gradienter använder samma färgkonfiguration.

För svävningseffekten är allt jag gör att öka storleken på gradienterna för att skapa hela bilden:

img:hover {
  background-size: 51% 51%;
}

Ja det är det 51% istället för 50% — som skapar en liten överlappning och undviker eventuella luckor.

Låt oss prova en annan idé med samma teknik:

Den här gången använder vi bara två gradienter, men med en mer komplex animering. Först uppdaterar vi positionen för varje gradient och ökar sedan deras storlekar för att skapa hela bilden. Jag introducerade också fler variabler för bättre kontroll över färg, storlek, tjocklek och till och med gapet mellan bilden och ramen.

img {
  --b: 8px;  /* border thickness*/
  --s: 60px; /* size of the corner*/
  --g: 14px; /* the gap*/
  --c: #EDC951; 

  padding: calc(var(--b) + var(--g));
  background-image:
    conic-gradient(from  90deg at top    var(--b) left  var(--b), #0000 25%, var(--c) 0),
    conic-gradient(from -90deg at bottom var(--b) right var(--b), #0000 25%, var(--c) 0);
  background-position:
    var(--_p, 0%) var(--_p, 0%),
    calc(100% - var(--_p, 0%)) calc(100% - var(--_p, 0%));
  background-size: var(--s) var(--s);
  background-repeat: no-repeat;
  transition: 
    background-position .3s var(--_i,.3s), 
    background-size .3s calc(.3s - var(--_i, .3s));
}
img:hover {
  background-size: calc(100% - var(--g)) calc(100% - var(--g));
  --_p: calc(var(--g) / 2);
  --_i: 0s;
}

Varför gör --_i och --_p Variabler har ett understreck i sitt namn? Understrecket är en del av en namnkonvention jag använder för att överväga "interna" variabler som används för att optimera koden. De är inget speciellt men jag vill göra skillnad mellan de variabler vi justerar för att styra ramen (som --b, --c, etc.) och de jag använder för att göra koden kortare.

Koden kan se förvirrande ut och inte lätt att förstå men jag skrev en serie i tre delar där jag beskriver sådan teknik. Jag rekommenderar starkt att du läser åtminstone den första artikeln för att förstå hur jag nådde ovanstående kod.

Här är en illustration för att bättre förstå de olika värdena:

Visar samma bild av två klassiska bilar tre gånger för att illustrera CSS-variablerna som används i koden.
Fancy bilddekorationer: Single Element Magic

The Frame Reveal

Låt oss prova en annan typ av animering där vi avslöjar hela bilden när vi svävar:

Coolt, eller hur? Och du om du tittar noga kommer du att märka att linjerna försvinner i motsatt riktning på musen ut vilket gör effekten ännu mer fancy! Jag använde en liknande effekt i en tidigare artikel.

Men den här gången, istället för att täcka hela elementet, täcker jag bara en liten del genom att definiera en height för att få något sånt här:

Detta är den övre kanten på vår ram. Vi upprepar samma process på varje sida av bilden och vi har vår svävningseffekt:

img {
  --b: 10px; /* the border thickness*/
  --g: 5px; /* the gap on hover */
  --c: #8A9B0F; 

  padding: calc(var(--g) + var(--b));
  --_g: no-repeat linear-gradient(var(--c) 0 0);
  background: 
    var(--_g) var(--_i, 0%) 0,
    var(--_g) 100% var(--_i, 0%),
    var(--_g) calc(100% - var(--_i, 0%)) 100%,
    var(--_g) 0 calc(100% - var(--_i, 0%));
  background-size: var(--_i, 0%) var(--b),var(--b) var(--_i, 0%);
  transition: .4s, background-position 0s;
  cursor: pointer;
}
img:hover {
  --_i: 100%;
}

Som du kan se applicerar jag samma gradient fyra gånger och var och en har en annan position för att täcka endast en sida åt gången.

En till? Nu går vi!

Den här ser lite knepig ut och den kräver verkligen lite fantasi för att förstå hur två koniska gradienter åstadkommer denna typ av magi. Här är en demo för att illustrera en av gradienterna:

Pseudoelementet simulerar gradienten. Det är till en början utom synhåll och när vi svävar, ändrar vi först dess position för att få fram den övre kanten av ramen. Sedan ökar vi höjden för att få rätt kant. Gradientformen liknar de vi använde i förra avsnittet: två segment för att täcka två sidor.

Men varför gjorde jag gradientens bredd 200%? Skulle man tro 100% skulle räcka, eller hur?

100% borde räcka men jag kommer inte att kunna flytta gradienten som jag vill om jag håller dess bredd lika med 100%. Det är en annan liten egenhet relaterat till hur background-position Arbetar. Jag täcker in detta en tidigare artikel. jag med postade ett svar på Stack Overflow hantera detta. Jag vet att det är mycket läsning, men det är verkligen värt din tid.

Nu när vi har förklarat logiken för en gradient är den andra lätt eftersom den gör exakt samma sak, men täcker den vänstra och nedre kanten istället. Allt vi behöver göra är att byta några värden och vi är klara:

img {
  --c: #8A9B0F; /* the border color */
  --b: 10px; /* the border thickness*/
  --g: 5px;  /* the gap */

  padding: calc(var(--g) + var(--b));
  --_g: #0000 25%, var(--c) 0;
  background: 
    conic-gradient(from 180deg at top    var(--b) right var(--b), var(--_g))
     var(--_i, 200%) 0 / 200% var(--_i, var(--b))  no-repeat,
    conic-gradient(            at bottom var(--b) left  var(--b), var(--_g))
     0 var(--_i, 200%) / var(--_i, var(--b)) 200%  no-repeat;
  transition: .3s, background-position .3s .3s;
  cursor: pointer;
}
img:hover {
  --_i: 100%;
  transition: .3s, background-size .3s .3s;
}

Som du kan se är båda gradienterna nästan identiska. Jag byter helt enkelt ut värdena för storlek och position.

Ramrotationen

Den här gången ska vi inte rita en ram runt vår bild, utan snarare anpassa utseendet på en befintlig.

Du frågar förmodligen hur fan jag kan förvandla en rak linje till en vinklad linje. Nej, magin är annorlunda än så. Det är bara illusionen vi får efter att ha kombinerat enkla animationer för fyra gradienter.

Låt oss se hur animeringen för toppgradienten görs:

Jag uppdaterar helt enkelt positionen för en upprepad gradient. Inget snyggt än! Låt oss göra samma sak för höger sida:

Börjar du se tricket? Båda gradienterna skär varandra i hörnet för att skapa en illusion där den räta linjen ändras till en vinklad. Låt oss ta bort konturen och dölja överflödet för att bättre se det:

Nu lägger vi till ytterligare två gradienter för att täcka de återstående kanterna och vi är klara:

img {
  --g: 4px; /* the gap */
  --b: 12px; /* border thickness*/
  --c: #669706; /* the color */

  padding: calc(var(--g) + var(--b));
  --_c: #0000 0 25%, var(--c) 0 50%;
  --_g1: repeating-linear-gradient(90deg ,var(--_c)) repeat-x;
  --_g2: repeating-linear-gradient(180deg,var(--_c)) repeat-y;
  background:
    var(--_g1) var(--_p, 25%) 0, 
    var(--_g2) 0 var(--_p, 125%),
    var(--_g1) var(--_p, 125%) 100%, 
    var(--_g2) 100% var(--_p, 25%);
  background-size: 200% var(--b), var(--b) 200%;
  transition: .3s;
}
img:hover {
  --_p: 75%;
}

Om vi ​​tar den här koden och justerar den lite kan vi få en annan cool animation:

Kan du lista ut logiken i detta exempel? Det är din läxa! Koden kan se skrämmande ut men den använder samma logik som de tidigare exemplen vi tittade på. Försök att isolera varje gradient och föreställ dig hur den animerar.

Inslagning upp

Det är många gradienter i en artikel!

Det är det säkert och jag varnade dig! Men om utmaningen är att dekorera en bild utan extra element och pseudoelement, har vi bara några få möjligheter och gradienter är det mest kraftfulla alternativet.

Oroa dig inte om du är lite vilse i några av förklaringarna. Jag rekommenderar alltid några av mina gamla artiklar där jag går in mer i detalj med några av de koncept vi återvunnit för den här utmaningen.

Jag kommer att lämna med en sista demo för att hålla dig kvar tills nästa artikel i den här serien. Den här gången använder jag radial-gradient() för att skapa ytterligare en rolig svävningseffekt. Jag låter dig dissekera koden för att se hur det fungerar. Ställ frågor till mig i kommentarerna om du fastnar!

Fancy bilddekorationsserie

  • Single Element Magic — du är här
  • Masker och avancerade svävningseffekter (kommer den 21 oktober )
  • Konturer och komplexa animationer (kommer den 28 oktober )

Tidsstämpel:

Mer från CSS-tricks