Please tell me about everything I could do better, but especially how to calculate notand not hardcorehardcode the randomly shifted second array [...].
If you wish to support older browsers, remove the CSS variables and use
gradient.style.background =
"linear-gradient(90deg, rgb(" + from + "), rgb(" + to + "))";
Please tell me about everything I could do better, but especially how to calculate not not hardcore the randomly shifted second array [...].
Please tell me about everything I could do better, but especially how to calculate and not hardcode the randomly shifted second array [...].
If you wish to support older browsers, remove the CSS variables and use
gradient.style.background =
"linear-gradient(90deg, rgb(" + from + "), rgb(" + to + "))";
Please tell me about everything I could do better, but especially how to calculate not not hardcore the randomly shifted second array [...].
I suggest to get a random permutation of [0, 1, 2]
by introducing a simple but unbiased shuffle function.
A circular shift of that random permutation can then be found by mapping index i
to index (i + shift) % length
:
// Return two shifted colors with min, max and random component:
function randomGradientColors(min, max) {
let permutation = shuffle([0, 1, 2]);
let shift = random(1, 2);
return [
permutation.map(i => [min, max, random(min, max)][i]),
permutation.map(i => [min, max, random(min, max)][(i + shift) % 3])
];
}
Since you asked for everything that you could do better, I would like to suggest using a CSS background gradient instead of a canvas element. If compatibility is not a concern, you can even leverage fancy CSS variables:
.gradient {
background: linear-gradient(90deg, var(--from, black), var(--to, black));
}
Your markup then would provide the min
and max
color components via data attributes:
<div class="gradient" data-min="70" data-max="185"></div>
And your script would simply query all .gradient
elements and compute their CSS from
and to
variables from the provided data attributes:
let gradients = document.querySelectorAll(".gradient");
for (let gradient of gradients) {
let [from, to] = randomGradientColors(
gradient.dataset.min,
gradient.dataset.max
);
gradient.style.setProperty("--start", "rgb(" + from + ")");
gradient.style.setProperty("--to", "rgb(" + to + ")");
}
This approach is pretty flexible and allows you to adapt the styling to your needs without touching the script.
Here is the complete code:
// Return random integer within interval [min, max]:
function random(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// Shuffle array in-place:
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
let j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
// Return two shifted colors with min, max and random component:
function randomGradientColors(min, max) {
let permutation = shuffle([0, 1, 2]);
let shift = random(1, 2);
return [
permutation.map(i => [min, max, random(min, max)][i]),
permutation.map(i => [min, max, random(min, max)][(i + shift) % 3])
];
}
// Compute CSS 'from' and 'to' variables for all gradients:
let gradients = document.querySelectorAll(".gradient");
for (let gradient of gradients) {
let [from, to] = randomGradientColors(
gradient.dataset.min,
gradient.dataset.max
);
gradient.style.setProperty("--from", "rgb(" + from + ")");
gradient.style.setProperty("--to", "rgb(" + to + ")");
}
html {
background-color: #1d1f21;
}
.gradient {
display: inline-block;
width: 500px;
height: 180px;
background: linear-gradient(90deg, var(--from, black), var(--to, black));
}
.container {
text-align: center;
}
.textbox {
text-align: center;
color: white;
font-family: monospace;
}
<div class="container">
<div class="gradient" data-min="70" data-max="185"></div>
</div>
<div class="textbox">Reload to get a different header gradient.</div>