style: 添加预设样式
This commit is contained in:
@@ -1,123 +0,0 @@
|
||||
<style>
|
||||
#matrix-rain-container {
|
||||
width: 100%; height: 100%; background: #000;
|
||||
overflow: hidden; position: relative;
|
||||
}
|
||||
#matrix-canvas { display: block; position: absolute; top: 0; left: 0; }
|
||||
</style>
|
||||
<div id="matrix-rain-container">
|
||||
<canvas id="matrix-canvas"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
const canvas = document.getElementById('matrix-canvas');
|
||||
const layerElement = canvas.closest('.terminal-custom-html-layer'); // Or document.body if not in that specific env
|
||||
if (!canvas || !layerElement) {
|
||||
console.error("Canvas or layerElement not found.");
|
||||
return;
|
||||
}
|
||||
const ctx = canvas.getContext('2d');
|
||||
let animationFrameId;
|
||||
const characters = 'アァカサタナハマヤャラワABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
const fontSize = 14;
|
||||
let columns, drops = [];
|
||||
|
||||
// --- Slowdown Configuration ---
|
||||
const slowdownFactor = 10; // 数字越大,动画越慢 (例如 2 = 半速, 3 = 1/3速度)
|
||||
const originalAlpha = 0.1; // 原始的背景淡出alpha值
|
||||
|
||||
// 计算调整后的alpha值,以保持拖尾视觉效果
|
||||
// 如果 slowdownFactor 为 1, adjustedAlpha 等于 originalAlpha
|
||||
// (1 - newAlpha)^slowdownFactor = (1 - originalAlpha)^1
|
||||
// 1 - newAlpha = (1 - originalAlpha)^(1/slowdownFactor)
|
||||
// newAlpha = 1 - (1 - originalAlpha)^(1/slowdownFactor)
|
||||
const adjustedAlpha = slowdownFactor <= 1 ? originalAlpha : 1 - Math.pow(1 - originalAlpha, 1 / slowdownFactor);
|
||||
|
||||
let frameCounter = 0; // 用于控制逻辑更新频率的计数器
|
||||
// --- End Slowdown Configuration ---
|
||||
|
||||
|
||||
function setupDimensionsAndColumns() {
|
||||
canvas.width = layerElement.offsetWidth;
|
||||
canvas.height = layerElement.offsetHeight;
|
||||
columns = Math.floor(canvas.width / fontSize);
|
||||
drops = [];
|
||||
for (let x = 0; x < columns; x++) {
|
||||
drops[x] = 1 + Math.floor(Math.random() * (canvas.height / fontSize));
|
||||
}
|
||||
frameCounter = 0; // 重置帧计数器
|
||||
}
|
||||
|
||||
function drawMatrix() {
|
||||
if (!ctx || canvas.width === 0 || canvas.height === 0) {
|
||||
animationFrameId = requestAnimationFrame(drawMatrix);
|
||||
return;
|
||||
}
|
||||
|
||||
// 背景淡出效果:每一帧都执行,使用调整后的alpha值
|
||||
ctx.fillStyle = `rgba(0, 0, 0, ${adjustedAlpha})`;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
frameCounter++;
|
||||
|
||||
// 只有当帧计数器达到 slowdownFactor 时,才更新雨滴逻辑和绘制字符
|
||||
if (frameCounter >= slowdownFactor) {
|
||||
frameCounter = 0; // 重置计数器
|
||||
|
||||
ctx.fillStyle = '#0F0'; // 雨滴颜色
|
||||
ctx.font = fontSize + 'px monospace';
|
||||
|
||||
for (let i = 0; i < drops.length; i++) {
|
||||
const text = characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
|
||||
|
||||
// 如果雨滴超出画布底部,并且随机条件满足,则重置雨滴到顶部
|
||||
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
|
||||
drops[i] = 0;
|
||||
}
|
||||
drops[i]++; // 雨滴下落
|
||||
}
|
||||
}
|
||||
animationFrameId = requestAnimationFrame(drawMatrix);
|
||||
}
|
||||
|
||||
const debounce = (func, delay) => {
|
||||
let t;
|
||||
return (...a) => {
|
||||
clearTimeout(t);
|
||||
t = setTimeout(() => func.apply(this, a), delay);
|
||||
};
|
||||
};
|
||||
|
||||
const debouncedReinitialize = debounce(() => {
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
}
|
||||
setupDimensionsAndColumns();
|
||||
if (columns > 0) {
|
||||
drawMatrix();
|
||||
}
|
||||
}, 250);
|
||||
|
||||
// 确保 layerElement 存在才进行监听
|
||||
if (layerElement) {
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.target === layerElement) {
|
||||
debouncedReinitialize();
|
||||
}
|
||||
});
|
||||
});
|
||||
resizeObserver.observe(layerElement);
|
||||
} else {
|
||||
// Fallback if layerElement is not specific, e.g. observe window or body
|
||||
// window.addEventListener('resize', debouncedReinitialize); // Example fallback
|
||||
console.warn("layerElement not found for ResizeObserver, resize handling might be limited.");
|
||||
}
|
||||
|
||||
setupDimensionsAndColumns();
|
||||
if (columns > 0) {
|
||||
drawMatrix();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@@ -1,123 +0,0 @@
|
||||
<style>
|
||||
#matrix-rain-container {
|
||||
width: 100%; height: 100%; background: #000;
|
||||
overflow: hidden; position: relative;
|
||||
}
|
||||
#matrix-canvas { display: block; position: absolute; top: 0; left: 0; }
|
||||
</style>
|
||||
<div id="matrix-rain-container">
|
||||
<canvas id="matrix-canvas"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
const canvas = document.getElementById('matrix-canvas');
|
||||
const layerElement = canvas.closest('.terminal-custom-html-layer'); // Or document.body if not in that specific env
|
||||
if (!canvas || !layerElement) {
|
||||
console.error("Canvas or layerElement not found.");
|
||||
return;
|
||||
}
|
||||
const ctx = canvas.getContext('2d');
|
||||
let animationFrameId;
|
||||
const characters = 'アァカサタナハマヤャラワABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
const fontSize = 14;
|
||||
let columns, drops = [];
|
||||
|
||||
// --- Slowdown Configuration ---
|
||||
const slowdownFactor = 10; // 数字越大,动画越慢 (例如 2 = 半速, 3 = 1/3速度)
|
||||
const originalAlpha = 0.1; // 原始的背景淡出alpha值
|
||||
|
||||
// 计算调整后的alpha值,以保持拖尾视觉效果
|
||||
// 如果 slowdownFactor 为 1, adjustedAlpha 等于 originalAlpha
|
||||
// (1 - newAlpha)^slowdownFactor = (1 - originalAlpha)^1
|
||||
// 1 - newAlpha = (1 - originalAlpha)^(1/slowdownFactor)
|
||||
// newAlpha = 1 - (1 - originalAlpha)^(1/slowdownFactor)
|
||||
const adjustedAlpha = slowdownFactor <= 1 ? originalAlpha : 1 - Math.pow(1 - originalAlpha, 1 / slowdownFactor);
|
||||
|
||||
let frameCounter = 0; // 用于控制逻辑更新频率的计数器
|
||||
// --- End Slowdown Configuration ---
|
||||
|
||||
|
||||
function setupDimensionsAndColumns() {
|
||||
canvas.width = layerElement.offsetWidth;
|
||||
canvas.height = layerElement.offsetHeight;
|
||||
columns = Math.floor(canvas.width / fontSize);
|
||||
drops = [];
|
||||
for (let x = 0; x < columns; x++) {
|
||||
drops[x] = 1 + Math.floor(Math.random() * (canvas.height / fontSize));
|
||||
}
|
||||
frameCounter = 0; // 重置帧计数器
|
||||
}
|
||||
|
||||
function drawMatrix() {
|
||||
if (!ctx || canvas.width === 0 || canvas.height === 0) {
|
||||
animationFrameId = requestAnimationFrame(drawMatrix);
|
||||
return;
|
||||
}
|
||||
|
||||
// 背景淡出效果:每一帧都执行,使用调整后的alpha值
|
||||
ctx.fillStyle = `rgba(0, 0, 0, ${adjustedAlpha})`;
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
frameCounter++;
|
||||
|
||||
// 只有当帧计数器达到 slowdownFactor 时,才更新雨滴逻辑和绘制字符
|
||||
if (frameCounter >= slowdownFactor) {
|
||||
frameCounter = 0; // 重置计数器
|
||||
|
||||
ctx.fillStyle = '#0F0'; // 雨滴颜色
|
||||
ctx.font = fontSize + 'px monospace';
|
||||
|
||||
for (let i = 0; i < drops.length; i++) {
|
||||
const text = characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
ctx.fillText(text, i * fontSize, drops[i] * fontSize);
|
||||
|
||||
// 如果雨滴超出画布底部,并且随机条件满足,则重置雨滴到顶部
|
||||
if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) {
|
||||
drops[i] = 0;
|
||||
}
|
||||
drops[i]++; // 雨滴下落
|
||||
}
|
||||
}
|
||||
animationFrameId = requestAnimationFrame(drawMatrix);
|
||||
}
|
||||
|
||||
const debounce = (func, delay) => {
|
||||
let t;
|
||||
return (...a) => {
|
||||
clearTimeout(t);
|
||||
t = setTimeout(() => func.apply(this, a), delay);
|
||||
};
|
||||
};
|
||||
|
||||
const debouncedReinitialize = debounce(() => {
|
||||
if (animationFrameId) {
|
||||
cancelAnimationFrame(animationFrameId);
|
||||
}
|
||||
setupDimensionsAndColumns();
|
||||
if (columns > 0) {
|
||||
drawMatrix();
|
||||
}
|
||||
}, 250);
|
||||
|
||||
// 确保 layerElement 存在才进行监听
|
||||
if (layerElement) {
|
||||
const resizeObserver = new ResizeObserver(entries => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.target === layerElement) {
|
||||
debouncedReinitialize();
|
||||
}
|
||||
});
|
||||
});
|
||||
resizeObserver.observe(layerElement);
|
||||
} else {
|
||||
// Fallback if layerElement is not specific, e.g. observe window or body
|
||||
// window.addEventListener('resize', debouncedReinitialize); // Example fallback
|
||||
console.warn("layerElement not found for ResizeObserver, resize handling might be limited.");
|
||||
}
|
||||
|
||||
setupDimensionsAndColumns();
|
||||
if (columns > 0) {
|
||||
drawMatrix();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,164 @@
|
||||
<style>
|
||||
#color-ribbons-container {
|
||||
width: 100%; height: 100%;
|
||||
background-color: #222733; /* 柔和的深蓝灰色 */
|
||||
overflow: hidden; position: relative;
|
||||
}
|
||||
#ribbons-canvas { display: block; position: absolute; top: 0; left: 0; }
|
||||
</style>
|
||||
<div id="color-ribbons-container">
|
||||
<canvas id="ribbons-canvas"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
const canvas = document.getElementById('ribbons-canvas');
|
||||
const layerElement = canvas.closest('.terminal-custom-html-layer') || canvas.parentElement;
|
||||
if (!canvas || !layerElement) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
let width, height, animationFrameId;
|
||||
const ribbons = [];
|
||||
const numRibbons = 5; // 彩带数量
|
||||
let time = 0;
|
||||
|
||||
// HSL颜色辅助函数
|
||||
function hslToRgb(h, s, l) {
|
||||
let r, g, b;
|
||||
if (s == 0) {
|
||||
r = g = b = l; // achromatic
|
||||
} else {
|
||||
const 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;
|
||||
};
|
||||
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)];
|
||||
}
|
||||
|
||||
class Ribbon {
|
||||
constructor() {
|
||||
this.numPoints = 50 + Math.floor(Math.random() * 30); // 组成彩带路径的点数
|
||||
this.points = [];
|
||||
this.baseY = height * (0.2 + Math.random() * 0.6);
|
||||
this.amplitude = height * (0.05 + Math.random() * 0.15);
|
||||
this.frequency = 0.002 + Math.random() * 0.003;
|
||||
this.phase = Math.random() * Math.PI * 2;
|
||||
this.thickness = 20 + Math.random() * 30; // 彩带厚度
|
||||
this.speed = 0.5 + Math.random() * 0.5; // 彩带横向移动速度
|
||||
this.hueStart = Math.random(); // 0-1
|
||||
this.hueChangeSpeed = 0.0005 + Math.random() * 0.001;
|
||||
this.opacity = 0.1 + Math.random() * 0.2;
|
||||
this.xOffset = -width * Math.random(); // 初始横向偏移,让彩带从不同位置进入
|
||||
}
|
||||
|
||||
update(deltaTime) {
|
||||
this.xOffset += this.speed * (deltaTime / (1000/60)); // Normalize speed to 60fps
|
||||
if (this.xOffset > width + this.thickness * 5) { // 彩带完全移出右侧
|
||||
this.xOffset = -this.thickness * 5 - Math.random() * width * 0.5; // 从左侧重新进入
|
||||
this.baseY = height * (0.2 + Math.random() * 0.6); // 改变Y基线
|
||||
this.hueStart = Math.random(); // 改变颜色
|
||||
}
|
||||
this.hueStart = (this.hueStart + this.hueChangeSpeed) % 1;
|
||||
|
||||
this.points = [];
|
||||
for (let i = 0; i < this.numPoints; i++) {
|
||||
const progress = i / (this.numPoints - 1); // 0 to 1
|
||||
const x = this.xOffset + progress * (width + this.thickness * 10); // 彩带绘制范围比屏幕宽
|
||||
const y = this.baseY + Math.sin(x * this.frequency + this.phase + time * 0.01) * this.amplitude +
|
||||
Math.cos(x * this.frequency * 0.5 + this.phase * 0.7 + time * 0.005) * this.amplitude * 0.5;
|
||||
this.points.push({ x, y });
|
||||
}
|
||||
}
|
||||
|
||||
draw() {
|
||||
if (this.points.length < 2) return;
|
||||
|
||||
ctx.beginPath();
|
||||
for (let i = 0; i < this.points.length -1; i++) {
|
||||
const p1 = this.points[i];
|
||||
const p2 = this.points[i+1];
|
||||
|
||||
// 计算垂直于路径的偏移点,形成彩带的上下边缘
|
||||
const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
|
||||
const dxTop = Math.sin(angle) * this.thickness / 2;
|
||||
const dyTop = -Math.cos(angle) * this.thickness / 2;
|
||||
const dxBottom = -Math.sin(angle) * this.thickness / 2;
|
||||
const dyBottom = Math.cos(angle) * this.thickness / 2;
|
||||
|
||||
if (i === 0) {
|
||||
ctx.moveTo(p1.x + dxTop, p1.y + dyTop);
|
||||
} else {
|
||||
ctx.lineTo(p1.x + dxTop, p1.y + dyTop);
|
||||
}
|
||||
}
|
||||
// 绘制下边缘 (反向)
|
||||
for (let i = this.points.length - 1; i > 0; i--) {
|
||||
const p1 = this.points[i];
|
||||
// p2 is points[i-1] but we use p1's angle approx or recalculate
|
||||
const p_prev = this.points[i-1];
|
||||
const angle = Math.atan2(p1.y - p_prev.y, p1.x - p_prev.x); // Angle from prev to current
|
||||
const dxBottom = -Math.sin(angle) * this.thickness / 2;
|
||||
const dyBottom = Math.cos(angle) * this.thickness / 2;
|
||||
ctx.lineTo(p1.x + dxBottom, p1.y + dyBottom);
|
||||
}
|
||||
ctx.closePath();
|
||||
|
||||
const [r,g,b] = hslToRgb(this.hueStart, 0.7, 0.6); // (饱和度0.7, 亮度0.6)
|
||||
ctx.fillStyle = `rgba(${r},${g},${b}, ${this.opacity})`;
|
||||
ctx.fill();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
width = layerElement.offsetWidth;
|
||||
height = layerElement.offsetHeight;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
ribbons.length = 0;
|
||||
for (let i = 0; i < numRibbons; i++) {
|
||||
ribbons.push(new Ribbon());
|
||||
}
|
||||
// 使用 'lighter' 或 'screen' 混合模式让彩带叠加时颜色混合更好
|
||||
ctx.globalCompositeOperation = 'screen';
|
||||
}
|
||||
|
||||
let lastTime = 0;
|
||||
function animate(currentTime) {
|
||||
const deltaTime = currentTime - lastTime;
|
||||
lastTime = currentTime;
|
||||
time++;
|
||||
|
||||
ctx.clearRect(0, 0, width, height); // 清晰的背景,或者用低alpha填充制造拖尾
|
||||
|
||||
ribbons.forEach(ribbon => {
|
||||
ribbon.update(deltaTime || (1000/60)); // Provide a fallback for deltaTime on first frame
|
||||
ribbon.draw();
|
||||
});
|
||||
animationFrameId = requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
let resizeTimeout;
|
||||
function onResize() {
|
||||
clearTimeout(resizeTimeout);
|
||||
resizeTimeout = setTimeout(() => {
|
||||
if (animationFrameId) cancelAnimationFrame(animationFrameId);
|
||||
init();
|
||||
// animate(0); // Restart animation loop
|
||||
}, 250);
|
||||
}
|
||||
|
||||
init();
|
||||
animate(0); // Start animation loop
|
||||
window.addEventListener('resize', onResize);
|
||||
canvas.cleanup = function() { if (animationFrameId) cancelAnimationFrame(animationFrameId); };
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,88 @@
|
||||
<style>
|
||||
#svg-lava-lamp-background {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #111827; /* 深灰蓝 */
|
||||
overflow: hidden;
|
||||
}
|
||||
#svg-lava-lamp-background svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.lava-g {
|
||||
filter: url(#gooeyFilter); /* 应用"粘稠"滤镜 */
|
||||
}
|
||||
|
||||
.lava-blob {
|
||||
fill: #ffcc00; /* 岩浆颜色 */
|
||||
/* 动画由JS控制更灵活,但这里用CSS尝试 */
|
||||
animation: moveBlob 15s infinite ease-in-out alternate;
|
||||
}
|
||||
.lava-blob:nth-child(1) { animation-duration: 18s; animation-delay: -2s; fill: #ff9900;}
|
||||
.lava-blob:nth-child(2) { animation-duration: 12s; animation-delay: -5s; fill: #ff6600;}
|
||||
.lava-blob:nth-child(3) { animation-duration: 20s; animation-delay: 0s; fill: #ff3300;}
|
||||
.lava-blob:nth-child(4) { animation-duration: 16s; animation-delay: -8s; fill: #cc3300;}
|
||||
.lava-blob:nth-child(5) { animation-duration: 14s; animation-delay: -12s;fill: #ffcc00;}
|
||||
|
||||
|
||||
@keyframes moveBlob {
|
||||
0% { transform: translate(0px, 0px) scale(1); }
|
||||
25% { transform: translate(30px, -50px) scale(1.2); }
|
||||
50% { transform: translate(-20px, 40px) scale(0.8); }
|
||||
75% { transform: translate(10px, -30px) scale(1.1); }
|
||||
100% { transform: translate(0px, 0px) scale(1); }
|
||||
}
|
||||
</style>
|
||||
<div id="svg-lava-lamp-background">
|
||||
<svg viewBox="0 0 300 400" preserveAspectRatio="xMidYMid slice" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<filter id="gooeyFilter">
|
||||
<!-- 高斯模糊使边缘模糊 -->
|
||||
<feGaussianBlur in="SourceGraphic" stdDeviation="12" result="blur" />
|
||||
<!-- 颜色矩阵增加alpha对比度,使模糊的边缘更"粘稠"地融合 -->
|
||||
<feColorMatrix in="blur" mode="matrix"
|
||||
values="1 0 0 0 0
|
||||
0 1 0 0 0
|
||||
0 0 1 0 0
|
||||
0 0 0 25 -10"
|
||||
result="gooey" />
|
||||
<!-- 可选:将原始图形叠在上面,如果想要更清晰的中心 -->
|
||||
<!-- <feComposite in="SourceGraphic" in2="gooey" operator="atop"/> -->
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- 将所有气泡放在一个应用了滤镜的组中 -->
|
||||
<g class="lava-g">
|
||||
<!-- 定义一些圆形作为气泡 -->
|
||||
<circle class="lava-blob" cx="100" cy="300" r="40" />
|
||||
<circle class="lava-blob" cx="200" cy="350" r="55" />
|
||||
<circle class="lava-blob" cx="150" cy="100" r="30" />
|
||||
<circle class="lava-blob" cx="50" cy="150" r="45" />
|
||||
<circle class="lava-blob" cx="250" cy="200" r="60" />
|
||||
<circle class="lava-blob" cx="120" cy="220" r="35" />
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<script>
|
||||
(function() {
|
||||
// 用JS可以更精细地控制每个blob的动画,例如使用随机目标点
|
||||
const blobs = document.querySelectorAll('#svg-lava-lamp-background .lava-blob');
|
||||
const svg = document.querySelector('#svg-lava-lamp-background svg');
|
||||
if (!blobs.length || !svg) return;
|
||||
|
||||
const viewBoxWidth = svg.viewBox.baseVal.width;
|
||||
const viewBoxHeight = svg.viewBox.baseVal.height;
|
||||
|
||||
blobs.forEach((blob, index) => {
|
||||
// 可以用JS设置更复杂的动画,这里CSS动画已经够用
|
||||
// 为了让CSS动画不完全同步,已经用了nth-child和animation-delay
|
||||
// 如果想完全随机化CSS动画的参数,可以用JS来动态设置style属性
|
||||
// 例如: blob.style.animationDuration = (10 + Math.random() * 10) + 's';
|
||||
// blob.style.animationDelay = (-Math.random() * 5) + 's';
|
||||
|
||||
// 动态改变transform-origin让缩放更有趣
|
||||
blob.style.transformOrigin = `${Math.random()*50+25}% ${Math.random()*50+25}%`;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1,92 @@
|
||||
<style>
|
||||
#css-3d-cubes-background {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #080010; /* 深紫色背景 */
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
perspective: 1000px; /* 为3D效果设置透视 */
|
||||
}
|
||||
|
||||
.scene {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.cube-wrapper {
|
||||
position: absolute;
|
||||
width: 100px; /* 调整立方体大小 */
|
||||
height: 100px;
|
||||
transform-style: preserve-3d;
|
||||
/* 动画由JS控制或预设不同参数 */
|
||||
}
|
||||
|
||||
.cube {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
transform: rotateX(0deg) rotateY(0deg); /* 初始旋转,会被动画覆盖 */
|
||||
animation: spin 15s infinite linear;
|
||||
}
|
||||
|
||||
.cube .face {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border: 1px solid rgba(0, 255, 255, 0.7); /* 青色霓虹边框 */
|
||||
background-color: rgba(0, 50, 80, 0.2); /* 半透明深蓝面 */
|
||||
box-shadow: 0 0 10px rgba(0, 255, 255, 0.5), inset 0 0 8px rgba(0, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/* 定位立方体的六个面 */
|
||||
.cube .front { transform: rotateY( 0deg) translateZ(50px); }
|
||||
.cube .back { transform: rotateY(180deg) translateZ(50px); }
|
||||
.cube .right { transform: rotateY( 90deg) translateZ(50px); }
|
||||
.cube .left { transform: rotateY(-90deg) translateZ(50px); }
|
||||
.cube .top { transform: rotateX( 90deg) translateZ(50px); }
|
||||
.cube .bottom { transform: rotateX(-90deg) translateZ(50px); }
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg); }
|
||||
to { transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg); }
|
||||
}
|
||||
|
||||
/* 示例立方体位置和动画差异化 */
|
||||
.cube-wrapper-1 { top: 20%; left: 30%; transform: scale(0.8) translateZ(-100px); }
|
||||
.cube-wrapper-1 .cube { animation-duration: 18s; animation-delay: -2s; }
|
||||
|
||||
.cube-wrapper-2 { top: 50%; left: 60%; transform: scale(1.2) translateZ(50px); }
|
||||
.cube-wrapper-2 .cube { animation-duration: 12s; }
|
||||
|
||||
.cube-wrapper-3 { top: 70%; left: 15%; transform: scale(0.6) translateZ(-200px); }
|
||||
.cube-wrapper-3 .cube { animation-duration: 22s; animation-delay: -5s; }
|
||||
</style>
|
||||
<div id="css-3d-cubes-background">
|
||||
<div class="scene">
|
||||
<div class="cube-wrapper cube-wrapper-1">
|
||||
<div class="cube">
|
||||
<div class="face front"></div> <div class="face back"></div>
|
||||
<div class="face right"></div> <div class="face left"></div>
|
||||
<div class="face top"></div> <div class="face bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cube-wrapper cube-wrapper-2">
|
||||
<div class="cube">
|
||||
<div class="face front"></div> <div class="face back"></div>
|
||||
<div class="face right"></div> <div class="face left"></div>
|
||||
<div class="face top"></div> <div class="face bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cube-wrapper cube-wrapper-3">
|
||||
<div class="cube">
|
||||
<div class="face front"></div> <div class="face back"></div>
|
||||
<div class="face right"></div> <div class="face left"></div>
|
||||
<div class="face top"></div> <div class="face bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 可以用JS动态添加更多cube-wrapper并随机化参数 -->
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user