Per questo blog ho usato il framework Hugo con il tema Risotto; mi piace il minimalismo e questa combinazione mi ha particolarmente convinto, essendo semplice e senza troppi fronzoli. Ho apportato qualche modifica al tema per adattarlo alle mie esigenze, e quella di cui vorrei parlare in questo post riguarda l’animazione dello sfondo del logo.
Per ottenere l’effetto di gradiente rotante che si vede attualmente, ho inizialmente sperimentato con un po’ di JavaScript, in questo modo:
document.addEventListener("DOMContentLoaded", () => {
const DEG_STEP = 2.8125 // equivale a 360 / 128;
const INTERVAL = 62.5 // equivale a 8000 / 128
let deg = 42;
let logo = document.querySelector(".page__logo-inner");
setInterval(() => {
deg += DEG_STEP;
deg %= 360;
logo.style["background-image"] = `linear-gradient(${deg}deg, rgb(247, 115, 241), rgb(16, 180, 215))`;
}, INTERVAL)
});
All’apertura della pagina, quindi, parte il setInterval, che a cadenza di 62.5 millisecondi modifica lo stile background-image, ruotando di fatto il linear-gradient.
Il loop dura 8 secondi. In 8 secondi vengono disegnati 128 fotogrammi, e ad ogni fotogramma la rotazione avanza di 2.8125 gradi.
Funzionava tutto perfettamente, ma avevo notato un problema: quando aprivo gli strumenti di sviluppo, l’utilizzo della CPU si impennava.
Questo succedeva perché nel tab Elements degli strumenti di sviluppo è visibile il DOM della pagina, con gli stili inline visibili in chiaro.
Lo stile del tag con classe .page__logo-inner, infatti, viene costantemente aggiornato, e il browser consuma CPU per visualizzare le modifiche, che, come detto prima, avvengono ogni 62.5 millisecondi. Probabilmente per il 99,99% degli utenti questo non rappresenta un vero problema, ma ho voluto comunque provare a risolverlo.
Ho deciso, quindi, di implementare lo stesso loop usando opportunamente il CSS al posto di JavaScript.
Ho provato inizialmente a impostare 3 keyframes, in questo modo:
.page__logo-inner {
background-image: linear-gradient(42deg, rgb(247, 115, 241), rgb(16, 180, 215));
animation: logo_anim 8s linear infinite;
}
@keyframes logo_anim {
0% {
background-image: linear-gradient(42deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
50% {
background-image: linear-gradient(222deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
100% {
background-image: linear-gradient(42deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
}
Mi aspettavo che il browser calcolasse tutti i fotogrammi mancanti e rendesse quindi l’animazione fluida, ma non ha funzionato. L’animazione, infatti, si componeva di soli 3 frame, senza alcuna interpolazione, come si può vedere nella gif qui sotto.
Occorreva quindi scrivere esplicitamente tutti e 128 i keyframe per ottenere lo stesso effetto avuto con JavaScript. In questo modo il browser non avrebbe dovuto eseguire alcun calcolo, ma soltanto leggere i valori pre-calcolati.
Ma non avevo alcuna intenzione di farlo a mano, così ho scritto un piccolo programma JS da far girare direttamente sulla console del browser, che mi producesse la regola CSS con tutti i keyframe in formato testuale, da copiare e incollare direttamente nel file CSS.
const STEPS = 128;
const START_DEG = 42;
const DEG_STEP = 2.8125;
let percent_step = 100 / STEPS;
let output = "@keyframes logo_anim {\n";
for (let i=0; i<STEPS; i++) {
let percent = i * percent_step;
let deg = (START_DEG + (i * DEG_STEP)) % 360;
output += `\t${percent.toFixed(2)}% {\n\t\tbackground-image: linear-gradient(${deg}deg, rgb(247, 115, 241), rgb(16, 180, 215));\n\t}\n`;
}
output += "}";
console.log(output);
A questo punto, dopo averlo fatto girare in console, è bastato copiare l’output stampato a video e incollarlo nel file CSS.
.page__logo-inner {
background-image: linear-gradient(42deg, rgb(247, 115, 241), rgb(16, 180, 215));
animation: logo_anim 8s linear infinite;
}
@keyframes logo_anim {
0.00% {
background-image: linear-gradient(42deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
0.78% {
background-image: linear-gradient(44.8125deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
1.56% {
background-image: linear-gradient(47.625deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
/* ... */
97.66% {
background-image: linear-gradient(33.5625deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
98.44% {
background-image: linear-gradient(36.375deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
99.22% {
background-image: linear-gradient(39.1875deg, rgb(247, 115, 241), rgb(16, 180, 215));
}
}
Problema risolto! Adesso l’utilizzo della CPU resta basso anche aprendo gli strumenti di sviluppo.