「移动设备陀螺仪」与「preserve-3d」碰撞的火花

本文介绍如何使用HTML、CSS与JavaScript结合移动设备陀螺仪数据创建一个互动3D立方体。通过简单的HTML结构配合CSS transform属性,实现3D立方体的基本构造。再利用JavaScript监听deviceorientation事件,动态调整立方体的旋转角度。

原文链接:航洋无声 - github

「移动设备陀螺仪」与「preserve-3d」碰撞的火花

涉及知识「CSS:transform、JS:deviceorientation」

废话不多,先上 DEMO「请使用移动设备查看」

如何搭建一个简单的立方体

只需要寥寥几行 HTML、CSS 代码就能产出一个「立方体」

  • 核心 HTML 如下
<div class="cube">
  <span class="cube-face cube-front"></span>
  <span class="cube-face cube-back"></span>
  <span class="cube-face cube-left"></span>
  <span class="cube-face cube-right"></span>
  <span class="cube-face cube-top"></span>
  <span class="cube-face cube-bottom"></span>
</div>

<!-- 6 个 <span /> 表示立方体的 6 个面 -->
<!--
 这里有个小插曲:
 起初,我使用的 6 个 <i /> 标签,因为大部分表示「图形、图标」的元素都用 <i /> 标签,
 不过,强迫症的我,细细想来,<i /> 是表示的「斜体文字」,语义上完全不匹配啊。
 所以,我在知乎上搜到这样一个描述:[为什么大家都用i标签<i></i>用作小图标?](https://www.zhihu.com/question/26880548)
 有个回答:
 「
   大家都遵循开放的标准来做事,未来可能少走弯路。
   少用 hack 的方法解决问题,有助于你写出向未来兼容的代码。
  」
  我很赞同,所以就把 <i /> 改成了 <span />。
 -->
  • CSS 第一步
.cube {
  width: 160px;
  height: 160px;
  position: relative;
  -webkit-transform-style: preserve-3d; /* 这一句重点 */
  transform-style: preserve-3d;
  -webkit-transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg);
  transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg);
}
.cube-face {
  display: block;
  position: absolute;
  width: 100%;
  height: 100%;
  box-shadow: inset 0 0 4px 1px #fff;
  box-sizing: border-box;
  background: -webkit-linear-gradient(45deg, rgba(156, 144, 144, .6), #000);
  background: -o-linear-gradient(45deg, rgba(156, 144, 144, .6), #000);
  background: linear-gradient(45deg, rgba(156, 144, 144, .6), #000)
}

这个 CSS 过于简单,就不赘述与解释。
主要是要设置父元素 .cubetransform-style: preserve-3d
使子元素位于 3D 空间中,不然子元素都是「平面内、扁平化」,达不到 3D 效果。

给所有子元素 .cube-face 设置了透明的渐变色 rgba(156, 144, 144, .6) 背景,
是为了更好的观察到「被遮住的反面」,视觉上更加 立体

目前效果截图大概是这个样子:

图片描述

看起来就像一个正方形,其实是 6 个面全部重叠在一起。

  • CSS 第二步
.cube-front {
  -webkit-transform: translateZ(80px);
  transform: translateZ(80px);
}

上面 4 行代码使得「正面 .cube-front」向前移动 80px「也就是立方体一半的边长」。
同理我们可以设置「背面 .cube-back」向后移动 80px
效果大概是这样:

图片描述

  • CSS 第三步
.cube-left {
  -webkit-transform: rotateY(90deg);
  transform: rotateY(90deg);
}

上面 4 行代码使得「左面 .cube-left」先顺时针旋转「90 度」
大概是这个样子:

图片描述

然后再向「左边」移动 80px 就 OK 啦,
注意:左边是 Z 轴负方向。

.cube-left {
  -webkit-transform: rotateY(90deg) translateZ(-80px);
  transform: rotateY(90deg) translateZ(-80px);
}

大概是这个样子:

图片描述

同理,我们可以做出右边的效果,唯一区别就是,右边移动方向与左边相反。
道理类似,异曲同工,上边和下边,想必聪明的大家都掌握了正确写法姿势。

成品大概是这个样子:

图片描述

用陀螺仪使立方体动起来

细心的开发者应该发现了,在最开始,我给父元素 .cube 设置了:
transform: rotateX(10deg) rotateY(10deg) rotateZ(10deg)
认让父元素在三维空间上旋转 10 度。
如果我们动态连续修改这三个值,绝对可以达到 3D 旋转动画的效果。

这个时候,JS 的 deviceorientation「检测设备方向」 事件闪现突然闪现在我的脑海。
因为这个事件的回调参数里面恰好有三个参数「beta、gamma、alpha」,分别代表「X、Y、Z」的旋转方向。

beta 表示设备在 x 轴上的旋转角度,范围为 [-180, 180] 度。它描述的是设备由前向后旋转的情况。
gamma 表示设备在 y 轴上的旋转角度,范围为 [-90, 90] 度。它描述的是设备由左向右旋转的情况。
alpha 表示设备沿 z 轴上的旋转角度,范围为 [0, 360] 度。

大概是这个样子:

图片描述

  • 注册 deviceorientation 事件,得到 x、y、z
const handleOrientation = ({beta: x, gamma: y, alpha: z}) => {
  // 1. 得到 x、y、z
  // 2. 处理 x、y、z
  // 3. 使用 x、y、z
}

global.addEventListener('deviceorientation', handleOrientation)
  • 处理 x、y、z

由于我们期望立方体可以在 x、y、z 三个反向的旋转范围是 [-360, 360] 度,
但是 beta、gamma、alpha 的范围并不是我们期望的范围,所以我们要处理一下数据。

{
  x: x * 2,
  y: y * 4,
  z: (z - 180) * 2
}
  • 使用 x、y、z

我们现在得到的 x、y、z 已经在 [-360, 360] 度范围内了,
接下来要做的就是,使用 x、y、z 修改父元素 .cuberotateX(xdeg) rotateY(ydeg) rotateZ(zdeg) 旋转值。

完整的代码大概是这样:

const cube = document.querySelector('.cube')
const setCubePosition = ({x = 0, y = 0, z = 0}) => {
  cube.style = `transform: rotateX(${x}deg) rotateY(${y}deg) rotateZ(${x}deg);-webkit-transform: rotateX(${x}deg) rotateY(${y}deg) rotateZ(${x}deg);`
}
const handleOrientation = ({beta: x, gamma: y, alpha: z}) => {
  setCubePosition({
    x: x * 2,
    y: y * 4,
    z: (z - 180) * 2
  })
}

global.addEventListener('deviceorientation', handleOrientation)

庆祝时刻

现在我们已经完成了,一个利用「移动设备陀螺仪」与「preserve-3d」实现的 3D 交互效果。
让我们为自己鼓掌
???

点我查看完整代码


感谢阅读

### 回答1: transform-style: preserve-3d; 是一个CSS3属性,用于定义一个元素的子元素是如何在三维空间中呈现的。 当应用于一个元素时,它指示该元素的子元素应该在三维空间中进行变换,而不是在二维平面中变换。这意味着子元素可以在三维空间中进行旋转、缩放和移动,而不受到其父元素的影响。 例如,如果一个元素有许多子元素,当应用 transform-style: preserve-3d; 后,这些子元素将会在三维空间中摆放,这样它们可以以更自由的方式进行旋转和变形,而不会受到其父元素的影响。 需要注意的是,使用 transform-style: preserve-3d; 属性时,父元素必须具有透视属性(perspective),否则子元素将无法正确呈现在三维空间中。 ### 回答2: transform-style: preserve-3d; 是一个CSS属性,用于控制3D变换元素内容的呈现方式。 当使用3D变换属性(如rotateX、rotateY等)来转换一个元素时,该元素的子元素也会被影响,它们可能会在3D空间中随着父元素的变换发生改变。但是,默认情况下,子元素的变换发生在二维平面上,即使父元素发生了3D变换。 使用transform-style: preserve-3d; 可以改变子元素的变换方式,使其也在3D空间中进行变换。这意味着子元素可以跟随父元素的旋转和变换,并在3D空间中自由移动。 此属性对于制作3D效果的网页或动画非常有用。例如,在一个3D立方体中,可以通过设置父元素的transform-style为preserve-3d,使得立方体内的内容也在3D空间中进行变换,从而创造出更加生动逼真的效果。 需要注意的是,transform-style: preserve-3d; 只会应用在直接子元素上,对于孙元素或更深层次的元素,需要单独设置transform-style属性。 总之,通过使用transform-style: preserve-3d; 属性,可以在3D变换中更好地控制元素的呈现方式,增强网页或动画的视觉效果。 ### 回答3: transform-style: preserve-3d; 是CSS属性,用于定义一个元素的子元素应如何在3D空间中呈现。 当我们在 CSS 中使用 3D 转换时,通常会在某个容器元素上使用 transform-style: preserve-3d; 属性。这样可以确保容器元素的子元素能够保持其在3D空间中的位置和变换效果。 这个属性的默认值是 flat,即子元素在容器元素的平面内进行变换。而当我们将属性值设置为 preserve-3d 时,容器元素的子元素将以3D空间的形式进行变换,使得子元素可以具有在3D空间中移动、旋转和缩放的效果。 这个属性在进行复杂的3D转换时非常有用。通过将容器元素的子元素设置为 preserve-3d,我们可以在子元素上应用各种3D转换,例如 translate3D、rotate3D 和 scale3D 等。这样能够更加精确地控制子元素在3D空间中的位置和变换效果。 总之,transform-style: preserve-3d; 是一个非常有用的CSS属性,当我们需要在页面中创建3D效果时,可以使用它来确保容器元素的子元素能够正确地在3D空间中进行变换。通过合理运用这个属性,我们可以创造出令人惊叹的3D动画和效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值