You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>

这是立方体正常显示的样子:
3D立方体

整体功能运行得还不错,但我遇到了一个问题:当立方体的某个侧面(包括顶面、底面、左面、右面,但不包括正面和背面)完全朝向屏幕时,这个面没法被点击。比如下面这种情况:

顶面朝向屏幕的立方体

这个顶面根本点不了,只能随机点到某个侧面。就算我打开DevTools的元素选择工具(按Ctrl+Shift+C),也选不到这个面。

我试过一个解决方法,能缩小无法点击的角度范围,但当旋转到正好90度的时候,问题还是存在。

而且这个问题只出现在Chromium内核的浏览器里,Firefox是正常的。

备注:内容来源于stack exchange,提问作者Cmo Sekil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 11:19:31