Anonymous
CSS 3D изометрический куб - лица исчезают при определенных поворотах
Сообщение
Anonymous » 01 сен 2025, 18:09
Я пытаюсь построить простой изометрический куб с чистым HTML и CSS (без WebGL).
При каком -то вращении/кадре некоторые лица куба не показаны. Они в DOM, и у них нет ни одного из этих свойств (
или dislplay: none ).
Я думаю, что это связано с перспективой: нет; . Но мне это нужно изометрическое. Обычно это анимация на прокрутке.
Код: Выделить всё
(() => {
const onReady = (fn) => {
const wait = () => (window.anime && document.readyState !== 'loading') ? fn() : setTimeout(wait, 40);
wait();
};
onReady(() => {
const stage = document.querySelector('.stage');
const cube = stage.querySelector('#cube');
const topFace = stage.querySelector('#top');
const leftFace = stage.querySelector('#left');
const rightFace = stage.querySelector('#right');
const backFace = stage.querySelector('#back');
const range = stage.querySelector('#progress');
const out = stage.querySelector('#progressOut');
if (!cube || !topFace || !leftFace || !rightFace || !backFace || !range) return;
const getS = () => parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--s')) || 280;
const S = getS();
const LIFT_PX = Math.round(S * 0.7);
const FOLD_DEG = 90;
topFace.style.setProperty('--lift-top', '0px');
leftFace.style.setProperty('--fold-left', '0deg');
rightFace.style.setProperty('--fold-right', '0deg');
backFace.style.setProperty('--fold-back', '0deg');
const makeVarTL = (el, name, from, to, unit, duration = 1000, easing = 'linear') => {
const holder = {
v: from
};
return anime.timeline({
autoplay: false,
duration,
easing
})
.add({
targets: holder,
v: to,
update: () => el.style.setProperty(name, holder.v + unit)
});
};
const tlRotate = anime.timeline({
autoplay: false,
duration: 1600,
easing: 'linear'
})
.add({
targets: cube,
rotateX: [0, 360],
rotateY: [0, 360]
});
const tlTopLift = makeVarTL(topFace, '--lift-top', 0, LIFT_PX, 'px', 900);
const tlLeft = makeVarTL(leftFace, '--fold-left', 0, -FOLD_DEG, 'deg', 700);
const tlRight = makeVarTL(rightFace, '--fold-right', 0, FOLD_DEG, 'deg', 700);
const tlBack = makeVarTL(backFace, '--fold-back', 0, FOLD_DEG, 'deg', 700);
const seg = (g, a, b) => {
if (g = b) return 1;
return (g - a) / (b - a);
};
const seekAll = (g) => {
const p1 = seg(g, 0.00, 0.25);
const p2 = seg(g, 0.25, 0.50);
const p3 = seg(g, 0.50, 0.75);
const p4 = seg(g, 0.75, 1.00);
tlRotate.seek(p1 * tlRotate.duration);
tlTopLift.seek(p2 * tlTopLift.duration);
tlLeft.seek(p3 * tlLeft.duration);
tlRight.seek(p3 * tlRight.duration);
tlBack.seek(p4 * tlBack.duration);
};
const onInput = () => {
const g = (parseFloat(range.value) || 0) / 100;
out.value = Math.round(g * 100) + '%';
seekAll(g);
};
range.addEventListener('input', onInput);
onInput();
});
})();< /code>
:root {
--s: min(20vmin, 340px);
--isoX: -35.264deg;
--isoY: 45deg;
--lift-top: 0px;
--fold-left: 0deg;
--fold-right: 0deg;
--fold-back: 0deg;
--glass-rgb: 47 107 255;
--glass-blur: 8px;
--glass-sat: 160%;
--glass-bright: 1.05;
}
.stage {
width: 100%;
height: 70vh;
display: block;
padding: 12px;
box-sizing: border-box;
}
.controls {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 10px;
font: 14px system-ui, sans-serif
}
.controls input[type="range"] {
width: 320px
}
.cube-viewport {
position: relative;
width: 100%;
height: calc(100% - 42px);
overflow: visible;
perspective: none;
}
.cube-camera {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
transform-style: preserve-3d;
transform: rotateX(var(--isoX)) rotateY(var(--isoY));
}
.cube-world {
position: relative;
width: var(--s);
height: var(--s);
transform-style: preserve-3d;
}
.cube {
position: absolute;
inset: 0;
transform-style: preserve-3d;
will-change: transform;
}
.face {
position: absolute;
top: 50%;
left: 50%;
width: var(--s);
height: var(--s);
transform-origin: center;
transform-style: preserve-3d;
backface-visibility: hidden;
border-radius: 12px;
overflow: hidden;
background:
linear-gradient(135deg, rgb(var(--glass-rgb) / 0.22), rgb(var(--glass-rgb) / 0.08)),
radial-gradient(120% 120% at 0% 0%, rgb(255 255 255 / 0.28), transparent 60%);
backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat)) brightness(var(--glass-bright));
box-shadow: 0 8px 24px rgb(0 0 0 / 0.28), inset 0 0 0 1px rgb(255 255 255 / 0.06);
}
.face::after {
content: "";
position: absolute;
inset: 0;
box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06);
pointer-events: none;
}
/* Face-Positionen */
#right {
transform: translate(-50%, -50%) rotateY(-90deg) translateZ(calc(var(--s) * -0.5)) rotateX(var(--fold-right));
transform-origin: 50% 100% 0;
}
#left {
transform: translate(-50%, -50%) rotateY(-90deg) translateZ(calc(var(--s) * 0.5)) rotateX(var(--fold-left));
transform-origin: 50% 100% 0;
}
#top {
transform: translate(-50%, -50%) rotateX(90deg) translateZ(calc(var(--s) * 0.5 + var(--lift-top)));
}
#bottom {
transform: translate(-50%, -50%) rotateX(90deg) translateZ(calc(var(--s) * -0.5));
}
#back {
transform: translate(-50%, -50%) rotateX(0deg) translateZ(calc(var(--s) * -0.5)) rotateX(var(--fold-back));
transform-origin: 50% 100% 0;
}< /code>
Progress
0%
Подробнее здесь:
https://stackoverflow.com/questions/797 ... -rotations
1756739398
Anonymous
Я пытаюсь построить простой изометрический куб с чистым HTML и CSS (без WebGL). При каком -то вращении/кадре некоторые лица куба не показаны. Они в DOM, и у них нет ни одного из этих свойств ([code]visibillity: hidden[/code] или dislplay: none ). Я думаю, что это связано с перспективой: нет; . Но мне это нужно изометрическое. Обычно это анимация на прокрутке.[code](() => { const onReady = (fn) => { const wait = () => (window.anime && document.readyState !== 'loading') ? fn() : setTimeout(wait, 40); wait(); }; onReady(() => { const stage = document.querySelector('.stage'); const cube = stage.querySelector('#cube'); const topFace = stage.querySelector('#top'); const leftFace = stage.querySelector('#left'); const rightFace = stage.querySelector('#right'); const backFace = stage.querySelector('#back'); const range = stage.querySelector('#progress'); const out = stage.querySelector('#progressOut'); if (!cube || !topFace || !leftFace || !rightFace || !backFace || !range) return; const getS = () => parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--s')) || 280; const S = getS(); const LIFT_PX = Math.round(S * 0.7); const FOLD_DEG = 90; topFace.style.setProperty('--lift-top', '0px'); leftFace.style.setProperty('--fold-left', '0deg'); rightFace.style.setProperty('--fold-right', '0deg'); backFace.style.setProperty('--fold-back', '0deg'); const makeVarTL = (el, name, from, to, unit, duration = 1000, easing = 'linear') => { const holder = { v: from }; return anime.timeline({ autoplay: false, duration, easing }) .add({ targets: holder, v: to, update: () => el.style.setProperty(name, holder.v + unit) }); }; const tlRotate = anime.timeline({ autoplay: false, duration: 1600, easing: 'linear' }) .add({ targets: cube, rotateX: [0, 360], rotateY: [0, 360] }); const tlTopLift = makeVarTL(topFace, '--lift-top', 0, LIFT_PX, 'px', 900); const tlLeft = makeVarTL(leftFace, '--fold-left', 0, -FOLD_DEG, 'deg', 700); const tlRight = makeVarTL(rightFace, '--fold-right', 0, FOLD_DEG, 'deg', 700); const tlBack = makeVarTL(backFace, '--fold-back', 0, FOLD_DEG, 'deg', 700); const seg = (g, a, b) => { if (g = b) return 1; return (g - a) / (b - a); }; const seekAll = (g) => { const p1 = seg(g, 0.00, 0.25); const p2 = seg(g, 0.25, 0.50); const p3 = seg(g, 0.50, 0.75); const p4 = seg(g, 0.75, 1.00); tlRotate.seek(p1 * tlRotate.duration); tlTopLift.seek(p2 * tlTopLift.duration); tlLeft.seek(p3 * tlLeft.duration); tlRight.seek(p3 * tlRight.duration); tlBack.seek(p4 * tlBack.duration); }; const onInput = () => { const g = (parseFloat(range.value) || 0) / 100; out.value = Math.round(g * 100) + '%'; seekAll(g); }; range.addEventListener('input', onInput); onInput(); }); })();< /code> :root { --s: min(20vmin, 340px); --isoX: -35.264deg; --isoY: 45deg; --lift-top: 0px; --fold-left: 0deg; --fold-right: 0deg; --fold-back: 0deg; --glass-rgb: 47 107 255; --glass-blur: 8px; --glass-sat: 160%; --glass-bright: 1.05; } .stage { width: 100%; height: 70vh; display: block; padding: 12px; box-sizing: border-box; } .controls { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; font: 14px system-ui, sans-serif } .controls input[type="range"] { width: 320px } .cube-viewport { position: relative; width: 100%; height: calc(100% - 42px); overflow: visible; perspective: none; } .cube-camera { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; transform-style: preserve-3d; transform: rotateX(var(--isoX)) rotateY(var(--isoY)); } .cube-world { position: relative; width: var(--s); height: var(--s); transform-style: preserve-3d; } .cube { position: absolute; inset: 0; transform-style: preserve-3d; will-change: transform; } .face { position: absolute; top: 50%; left: 50%; width: var(--s); height: var(--s); transform-origin: center; transform-style: preserve-3d; backface-visibility: hidden; border-radius: 12px; overflow: hidden; background: linear-gradient(135deg, rgb(var(--glass-rgb) / 0.22), rgb(var(--glass-rgb) / 0.08)), radial-gradient(120% 120% at 0% 0%, rgb(255 255 255 / 0.28), transparent 60%); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat)) brightness(var(--glass-bright)); box-shadow: 0 8px 24px rgb(0 0 0 / 0.28), inset 0 0 0 1px rgb(255 255 255 / 0.06); } .face::after { content: ""; position: absolute; inset: 0; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.06); pointer-events: none; } /* Face-Positionen */ #right { transform: translate(-50%, -50%) rotateY(-90deg) translateZ(calc(var(--s) * -0.5)) rotateX(var(--fold-right)); transform-origin: 50% 100% 0; } #left { transform: translate(-50%, -50%) rotateY(-90deg) translateZ(calc(var(--s) * 0.5)) rotateX(var(--fold-left)); transform-origin: 50% 100% 0; } #top { transform: translate(-50%, -50%) rotateX(90deg) translateZ(calc(var(--s) * 0.5 + var(--lift-top))); } #bottom { transform: translate(-50%, -50%) rotateX(90deg) translateZ(calc(var(--s) * -0.5)); } #back { transform: translate(-50%, -50%) rotateX(0deg) translateZ(calc(var(--s) * -0.5)) rotateX(var(--fold-back)); transform-origin: 50% 100% 0; }< /code> Progress 0% [/code] Подробнее здесь: [url]https://stackoverflow.com/questions/79752649/css-3d-isometric-cube-faces-disappear-at-certain-rotations[/url]