这原本是GitHub上的一个不错的库,名为Colorful,我觉得不错,顺便用JS复刻了一个,现用于我的个人网站上,效果还算可以
主要是性能方面没法弄什么优化,在某些设备上的性能表现可能比较糟糕
贴个代码:
const colorfulBackground = document.getElementById("colorful-background");
const baseColors = [
"rgb(248, 167, 236)",
"rgb(227, 187, 255)",
"rgb(199, 220, 255)",
]; // 基色
const num = 8; // 生成元素数量
const colorMutationAmount = 80; // 颜色变异水平,提高此值可以获得基色之外的更多颜色
const scaleMean = 0.8;
const scaleStddev = 0.2;
const scaleMin = 0;
const scaleMax = 1.3;
const opacityMean = 0.1;
const opacityStddev = 0.02;
const opacityMin = 0.05;
const opacityMax = 0.15;
const positionMean = 50;
const positionStddev = 30;
const positionMin = 0;
const positionMax = 100;
const blurRadius = 128;
function mutatePrpbability(x) {
return 0.5 * Math.tanh(0.03 * x - 1.5) + 0.5;
}
function mutateColor(color) {
// 根据与变异水平正相关的变异概率计算是否变异
ifMutate = Math.random() > mutatePrpbability();
// 使用HSL而非RGB,会有更好的效果
let [r, g, b] = color.slice(4, -1).split(", ").map(Number);
if (ifMutate) {
let [h, s, l] = rgbToHsl(r, g, b);
h = clamp(h + getRandomMutation() / 360, 0, 1);
s = clamp(s + getRandomMutation(0.1) / 100, 0.6, 1);
l = clamp(l + getRandomMutation(0.1) / 100, 0.7, 1);
[r, g, b] = hslToRgb(h, s, l);
}
return `radial-gradient(rgb(${r}, ${g}, ${b}) 90%, rgba(0,0,0,0)) `;
}
function getRandomMutation(rate=1) {
return (Math.random() - 0.5) * colorMutationAmount * rate;
}
function createColorfulCircle() {
const circle = document.createElement("div");
circle.classList.add("colorful-circle");
circle.style.backgroundImage = mutateColor( baseColors[Math.floor(Math.random() * baseColors.length)] );
circle.style.transform = `translate3d(
calc(-50% + ${getNumberInNormalDistribution(positionMean, positionStddev, positionMin, positionMax)}vw),
calc(-50% + ${getNumberInNormalDistribution(positionMean, positionStddev, positionMin, positionMax)}vh),
0
)`;
circle.style.scale = `${getNumberInNormalDistribution(scaleMean, scaleStddev, scaleMin, scaleMax)}`;
circle.style.opacity = `${getNumberInNormalDistribution(opacityMean, opacityStddev, opacityMin, opacityMax)}`;
circle.style.filter = `blur(${blurRadius}px)`;
return circle;
}
function updateColorfulBackground() {
circle_list = colorfulBackground.children;
for (let i = 0; i < num; i++) {
let circle = circle_list[i];
circle.style.transform = `translate3d(
calc(-50% + ${getNumberInNormalDistribution(positionMean, positionStddev, positionMin, positionMax)}vw),
calc(-50% + ${getNumberInNormalDistribution(positionMean, positionStddev, positionMin, positionMax)}vh),
0
)`;
circle.style.scale = `${getNumberInNormalDistribution(scaleMean, scaleStddev, scaleMin, scaleMax)}`;
circle.style.opacity = `${getNumberInNormalDistribution(opacityMean, opacityStddev, opacityMin, opacityMax)}`;
}
}
function initColorfulBackground() {
for (let i = 0; i < num; i++) {
const circle = createColorfulCircle();
colorfulBackground.appendChild(circle);
}
}
function clamp(number, min, max) {
return Math.min(Math.max(number, min), max);
}
function getNumberInNormalDistribution(mean, std_dev, min, max) {
return clamp(
mean + randomNormalDistribution() * std_dev,
min,
max
);
}
// 网上抄的,别问我,看不懂
function randomNormalDistribution() {
var u = 0.0,
v = 0.0,
w = 0.0,
c = 0.0;
do {
//获得两个(-1,1)的独立随机变量
u = Math.random() * 2 - 1.0;
v = Math.random() * 2 - 1.0;
w = u * u + v * v;
} while (w == 0.0 || w >= 1.0);
//这里就是 Box-Muller转换
c = Math.sqrt((-2 * Math.log(w)) / w);
//返回2个标准正态分布的随机数,封装进一个数组返回
//当然,因为这个函数运行较快,也可以扔掉一个
//return [u*c,v*c];
return u * c;
}
function rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return [h, s, l];
}
function hslToRgb(h, s, l) {
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
let r, g, b;
if (s === 0) {
r = g = b = l; // achromatic
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
initColorfulBackground();
setInterval(updateColorfulBackground, 4000);
CSS:
#colorful-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -5;
}
.colorful-circle {
position: absolute;
border-radius: 50%;
transform-origin: center;
width: 50vw;
height: 50vw;
opacity: 0.1;
transition: 4000ms;
transition-timing-function: linear;
}
HTML:
<div id="colorful-background"></div>