卡片翻转

卡片翻转

我们已经做好了操作一个3D物体的所有准备,让我们开始第一个基础应用,翻转一张卡片。

下面是我们需要的HTML代码片段:

<div class="scene">
  <div class="card">
    <div class="card__face card__face--front">front</div>
    <div class="card__face card__face--back">back</div>
  </div>
</div>

.scene这个元素构建了一个3D的空间容器,.card元素是具体的3D对象,两个独立的.card__face元素分别作为卡片的正反面。我很推荐用这样的结构模型来做3D变换:scene,object,和faces。下面我们用3D空间容器和两个分开的平面来建立一个易于理解、简化样式的范例。

我们准备了一些3D样式。首先,给3D空间的容器元素一个必须的perspective属性,同时添加一些大小、定位的样式。

.scene {
  width: 200px;
  height: 260px;
  perspective: 600px;
}

现在.card元素可以在它父元素创建的3D空间里做transform变换了。我们添加width: 100%;height: 100%;,这样卡片的transform-origin被设置在了容器的中心位置,更多关于transform-origin的内容我们稍后再谈。position: relative是用来绝对定位卡片的正反面的。

我们来添加一些CSS3的过渡效果,这样用户便可以看到变换的效果了。

.card {
  width: 100%;
  height: 100%;
  position: relative;
  transition: transform 1s;
  transform-style: preserve-3d;
}

一个元素的perspective属性只能应用在它的直接子元素上,在这个例子中,就是.card元素。为了使后代所有的子元素都可以继承父元素的perspective,并且处在同一个3D空间下,父元素可以通过transform-style: preserve-3d来传递它的透视关系。如果没有3D的transform-style属性,那么卡片的立面将会被父元素压扁,同时背面旋转也将没有任何效果。

为了定位3D空间中的平面,我们需要在二维上用position: absolute重设他们的位置。为了隐藏远离观察者的背面,我们需要用到backface-visibility: hidden

.card__face {
  position: absolute;
  height: 100%;
  width: 100%;
  backface-visibility: hidden;
}

为了翻转.card__face--back,我们添加了一个基础的3D变换属性rotateY(180deg)

.card__face--front {
  background: red;
}

.card__face--back {
  background: blue;
  transform: rotateY( 180deg );
}

现在各个平面各就其位,当翻转卡片时,每个.card都需要有对应的样式。

.card.is-flipped {
  transform: rotateY(180deg);
}

现在我们有了一个可以使用的3D对象。当翻转卡片,我们切换is-flipped类,当设置.is-flipped时,.card元素将会旋转180度,这样.card__face--back便被翻转到了正面。

平滑翻转

如果你仔细观察1.1中天气App的3D效果,那么你会注意到它的效果和我们前边例子所实现的有些不一样。 请注意它卡片右侧的边缘,你会发现它与容器平齐,边缘并不会超出容器,它是围绕右侧边缘进行转动的,而不是绕着水平中心进行转动。并且这个过渡效果其实并不是旋转,它的边缘是在水平方向上的从右向左的移动。我们可以在前边的卡片翻转例子中,仅仅修改几行CSS来实现这个过渡效果。

转动的中心点要在卡片的右侧。一个元素的transform-origin默认值是在水平和垂直方向的中心(50% 50% 或者 center center)。transform-origin是会影响到元素变换过程的,我们来把它设置为右侧:

.card { transform-origin: center right; }

此时翻转需要用translateX设置水平运动,同时把旋转设置为-180deg,这样就可以向右翻转了。

.card.is-flipped {
  transform: translateX(-100%) rotateY(-180deg);
}

最后更新于