CSS实现的3D立方体在特定旋转角度下部分面无法点击的问题求助
CSS实现的3D立方体在特定旋转角度下部分面无法点击的问题求助
我正在尝试用CSS做一个支持拖拽旋转、点击选中每个面的简单3D立方体,下面是我的实现代码:
JavaScript代码
const DEFAULT_ROTATION = [-27, -36]; let position = [0, 0]; let rotation = DEFAULT_ROTATION; let isMoved = false; const container = document.querySelector(".container"); const rotate = () => { container.style.setProperty("--rotate-x", rotation[0] + "deg"); container.style.setProperty("--rotate-y", rotation[1] + "deg"); }; const reset = () => { position = [0, 0]; rotation = DEFAULT_ROTATION; rotate(); }; const cube = document.querySelector(".cube"); cube.addEventListener("pointerdown", e => { position = [e.clientX, e.clientY]; cube.setPointerCapture(e.pointerId); }); cube.addEventListener("pointermove", e => { if (!cube.hasPointerCapture(e.pointerId)) return; const rx = floorMod(rotation[0], 360), ryDir = rx > 90 && rx < 270 ? 1 : -1; rotation = [ rotation[0] - (Math.round(e.clientY) - position[1]), rotation[1] - ryDir * (Math.round(e.clientX) - position[0]) % 360, ]; rotate(); const newPosition = [Math.round(e.clientX), Math.round(e.clientY)]; if (!isMoved && Math.hypot(position[0] - newPosition[0], position[1] - newPosition[1]) >= 1) isMoved = true; position = newPosition; }); cube.addEventListener("pointerup", e => { position = [0, 0]; cube.releasePointerCapture(e.pointerId); const target = document.elementFromPoint(e.pageX, e.pageY); const face = target?.closest(".face"); if (e.button === 1 || e.button === 2) { if (!isMoved) reset(); } else if (!isMoved && face instanceof HTMLElement) face.click(); isMoved = false; }); const faces = document.querySelectorAll(".face"); faces.forEach(face => face.addEventListener("click", e => { faces.forEach(face => face.classList.remove("selected")); face.classList.add("selected"); })); function floorMod(x, y) { let result = x % y; if (result !== 0 && x < 0 !== y < 0) result += y; return result; }
CSS代码
.container { --side-length: 200px; width: var(--side-length); height: var(--side-length); position: relative; transform: rotateX(var(--rotate-x, -27deg)) rotateY(var(--rotate-y, -36deg)); transform-style: preserve-3d; user-select: none; transition: all cubic-bezier(0, 0, 0, 1) 250ms; } .face { width: var(--side-length); height: var(--side-length); position: absolute; align-content: center; overflow: clip; text-align: center; color: black; background-color: #ffffffb3; border: 2px solid #0000000f; border-radius: calc(8 / 200 * var(--side-length)); pointer-events: auto; transition: none; &.front { transform: translateZ(calc(var(--side-length) / 2)); } &.back { transform: translateZ(calc(var(--side-length) / -2)) rotateY(180deg); } &.left { transform: translateX(calc(var(--side-length) / -2)) rotateY(-90deg); } &.right { transform: translateX(calc(var(--side-length) / 2)) rotateY(90deg); } &.top { transform: translateY(calc(var(--side-length) / -2)) rotateX(90deg); } &.bottom { transform: translateY(calc(var(--side-length) / 2)) rotateX(-90deg); } &.selected { color: white; background-color: #005fb8; &:hover { background-color: #005fb8e0; } &:active { background-color: #005fb8c0; } } &:not(.selected) { &:hover { color: #005fb8; } &:active { color: #005fb880; } } } .cube { display: grid; place-items: center; width: 350px; height: 350px; perspective: 750px; cursor: grab; &:active { cursor: grabbing; } } body { display: grid; place-items: center; height: 100vh; margin: 0; } * { box-sizing: border-box; }
HTML代码
<div class="cube"> <div class="container"> <div class="front face">Front</div> <div class="back face">Back</div> <div class="left face">Left</div> <div class="right face">Right</div> <div class="top face">Top</div> <div class="bottom face">Bottom</div> </div> </div>
这是立方体正常显示的样子:
整体功能运行得还不错,但我遇到了一个问题:当立方体的某个侧面(包括顶面、底面、左面、右面,但不包括正面和背面)完全朝向屏幕时,这个面没法被点击。比如下面这种情况:

这个顶面根本点不了,只能随机点到某个侧面。就算我打开DevTools的元素选择工具(按Ctrl+Shift+C),也选不到这个面。
我试过一个解决方法,能缩小无法点击的角度范围,但当旋转到正好90度的时候,问题还是存在。
而且这个问题只出现在Chromium内核的浏览器里,Firefox是正常的。
备注:内容来源于stack exchange,提问作者Cmo Sekil
相关产品推荐
相关产品推荐

