CSS3-transform变形

441 阅读5分钟

基操

​ 如果说CSS3的灵魂在于美妙的动画,那在实现炫酷动画过程中,就一定少不了transform变形,在transform中我们可以设置移动、旋转、缩放等效果,同时transform也为我们提供了一些族属性,来应对不同的场景,只要你敢想就能设计出不同的动效。

transform

transform的属性如下:

translate:

translate相关含义
translate(x,y)可同时设置沿(x,y)轴的移动长度
translateX(x)只设置x轴移动长度
translateY(y)只设置y轴移动长度
translateZ(z)只设置z轴移动长度,只有在3D场景下,该属性才能体现
translate3d(x,y,z)可分别设置沿(x,y,z)轴的移动长度

rotate

rotate相关含义
rotate(ndeg)与rotateZ相同。
rotateX(ndeg)只设置x轴旋转角度,在3d场景尤为明显
rotateY(ndeg)只设置y轴旋转角度,在3d场景尤为明显
rotateZ(ndeg)只设置z轴旋转角度
rotate3d(x,y,zndeg)可分别设置沿(x,y,z)轴的旋转角度,前三个参数值为01,意为是否设置某个轴的旋转。

scale

scale相关含义
scale(x,y)分别定义(x,y)轴的缩放比例,值为0~n,若只传入一个值,则(x,y)轴都应用这个值。
scaleX(x)只设置x轴缩放。
scaleY(y)只设置y轴缩放。
scaleZ(z)只设置z轴缩放
scale3d(x,y,z)可分别设置沿(x,y,z)轴的缩放倍数。

skew

scale相关含义
skew(x,y)分别定义(x,y)轴的倾斜角度,单位deg,若只传入一个值,则(x,y)轴都应用这个值。
skewX(x)只设置x轴倾斜角度。
skewY(y)只设置y轴倾斜角度。

perspective

transform: perspective(arg),参数单位为px,规定3D场景的视角距离,该属性可设置在3D盒子本身,也可设置在父级元素,都能成功显示视口距离效果。

​ 还有一个全局属性perspective: arg,用法与transform: perspective(arg)相同,不过值得注意的是:这个全局属性必须设置在想要展示3D效果盒子的父级元素上,才能正常显示视角距离效果。


族属性

属性含义
transform-origin设置transform变换的基点
transform-style规定被嵌套元素如何在 3D 空间中显示。

其它相关

属性含义
perspective设置3D场景的视角距离
perspective-origin设置3D场景的视角基点
backface-visibility设置元素背面是否可见,可设置visiblehidden
  • perspective,要注意其与transform: perspective(arg)的区别,其只能设置在3d盒子的父级元素上

  • backface-visibility 这个属性在做旋转卡片时很重要,因为旋转卡片要展示两面,默认情况下正面卡片在旋转后,其背面也会透视显示,从而影响背面卡片的显示,所以要设置两张卡片背面不可见。

    示例:

    未设置:

    backface-visibility1.gif

    设置后:

    backface-visibility2.gif


示例

了解了变形的基本操作,就可以利用这些属性随意发挥想象力了,下面示例将会运用transform实现。

一、表单效果

translate表单.gif

值得注意的是:input[type="text"]不能添加伪类。

<style>
  main {
    width: 80%;
  }
  form {
    width: inherit;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
    background: #2c3e50;
  }
  span {
    width: 60px;
    display: inline-flex;
    justify-content: space-around;
    align-items: center;
    letter-spacing: 2px;
    color: white;
  }
  label {
    display: block;
    min-height: 50px;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .inputBox {
    display: inline-block;
    position: relative;
    width: 150px;
    min-height: 30px;
    border-radius: 5px;
    margin-left: 8px;
    background: white;
    overflow: hidden;
    transition: 0.8s;
  }
  input {
    display: inline-block;
    min-height: 30px;
  }
  .after {
    position: absolute;
    bottom: 0px;
    left: 0px;
    width: 100%;
    height: 2.1px;
    border-radius: 2px;
    background: linear-gradient(
      to right,
      white,
      #e74c3c,
      #e67e22,
      #f1c40f,
      #bdc3c7,
      #1abc9c,
      #3498db,
      #9b59b6,
      white
    );
    transform: translateX(-100%);
    transition: 0.8s;
  }
  .inputBox:hover {
    transform: scale(1.1);
  }
  .inputBox:hover .after {
    transform: translateX(0);
  }
  button {
    width: 60px;
    height: 40px;
    margin: 10px;
    color: white;
    background: transparent;
    border: 2px solid white;
    border-radius: 5px;
    position: relative;
    overflow: hidden;
    transition: 0.8s;
  }
  button > span {
    position: absolute;
    top: 50%;
    left: 50%;
    z-index: 1;
    background: transparent;
    transform: translate(-50%, -50%);
  }
  button::after {
    content: "";
    width: 98%;
    height: inherit;
    position: absolute;
    top: 50%;
    left: 50%;
    background: transparent;
    transform: translate(-50%, -50%);
    transition: 0.8s;
  }
  button:hover {
    transform: scale(1.1);
  }
  button:hover:after {
    transform: skewX(45deg) translate(-10px, -50%);
    background: #e74c3c;
  }
</style>
<body>
  <main>
    <form action="#">
      <label>
        <span>用户名:</span>
        <div class="inputBox">
          <input type="text" />
          <div class="after"></div>
        </div>
      </label>
      <label>
        <span>密码:</span>
        <div class="inputBox">
          <input type="text" />
          <div class="after"></div>
        </div>
      </label>
      <button><span>Login</span></button>
    </form>
  </main>
</body>

3D

对于3D效果,我们就需要进行一些预设,只有配置了这些预设,才能够有视觉效果。

transform-style

transform-style: 规定被嵌套元素如何在 3D 空间中显示。

属性值含义
flat子元素将不保留其 3D 位置。
preserve-3d子元素将保留其 3D 位置。

当我们设置transform-style: preserve-3d时,后期改变元素位置,才会有视口距离效果。

当然,我们还要配置视口距离👇。

perspective

我们可以使用两种方式定义视口距离,单位都为px

  1. perspective: arg
  2. transform: perspective(arg)

但值得注意的是二者的区别,上文已经说明,这里不再赘述,但在实际使用时,用哪个比较好呢?

个人推荐使用perspective,不使用transform: perspective(arg)的原因如下:

当触发选项很多时,为了保证具有视口效果,在触发时的样式表中还要重复配置transform: perspective(arg)

​ 因为动画被触发时,应用的是触发时的样式表,若此时不配置transform: perspective(arg),则会出现:动画触发前还有视口效果,触发后却没有了。

​ 而我们为了避免这种情况,只需要在其父级盒子上设置perspective即可,因为其不属于transform, 所以在后期触发时,不用考虑transform重新配置的问题。


当我们做好了前期的预设,后面就可以顺利展示3d效果了:

  • z)轴相关特效得以体现

  • 一些(x,y)轴的特效会更加明显

让我们来对比一下:

一、未配置预设时的translateZ效果

​ 没错!没有效果,由于没有保留元素3d位置,所以Z轴效果不能够得到体现。

3D对比-未设置.gif

二、配置预设后

3D对比-设置.gif

什么?效果不明显?让我们简单的旋转一下。

3D效果1.gif

案例展示

下面让我们展示一个案例,更好的熟悉3D动画

3D效果2.gif

<style>
  * {
    margin: 0px;
    padding: 0px;
    box-sizing: border-box;
  }
  body {
    width: 100vw;
    min-height: 100vh;
    background-color: #7f8c8d;
  }
  main {
    width: inherit;
    height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
    align-items: center;
  }
  section {
    width: 400px;
    height: 400px;
  }
  .box3D {
    width: inherit;
    height: inherit;
    border: 2px solid white;
    border-radius: 5px;
    transform-style: preserve-3d;
    transform: perspective(900px) rotate3d(0, 1, 0, 45deg);
    transition-duration: 1s;
    transition-delay: 1s;
    position: relative;
  }
  .box3D > div {
    width: 200px;
    height: 200px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border-radius: 10px;
    transition: 1s;
  }
  .box3D > div:nth-of-type(1) {
    background: #badc58;
  }
  .box3D > div:nth-of-type(2) {
    background: #ff7979;
  }
  .box3D > div:nth-of-type(3) {
    background: #ffbe76;
  }
  .box3D > div:nth-of-type(4) {
    background: #22a6b3;
  }

  .box3D:hover {
    transform: perspective(900px) rotate3d(0, 1, 1, 225deg);
  }
  .box3D:hover > div:nth-of-type(1) {
    transform: translate3d(-50%, -50%, 100px);
  }
  .box3D:hover > div:nth-of-type(2) {
    transform: translate3d(-50%, -50%, -200px);
  }
  .box3D:hover > div:nth-of-type(3) {
    transform: translate3d(-50%, -50%, -100px);
  }
  .box3D:hover > div:nth-of-type(4) {
    transform: translate3d(-50%, -50%, 200px);
  }
</style>
<body>
  <main>
    <section>
      <div class="box3D">
        <div></div>
        <div></div>
        <div></div>
        <div></div>
      </div>
    </section>
  </main>
</body>
  • 当然,我更推荐使用perspective来在3d盒子的父级元素中设置视口。

  • 虽然该案例对于3d盒子(.box3D)来说,只有一个hover进行触发,但如果我希望click、表单提交时,等等场景下都触发该动画,无论在CSS还是在JS中,都需要重复配置transform:perspective(900px)

进行以下更改即可

section {
    width: 400px;
    height: 400px;
    perspective: 900px; //在父级元素配置视口
}
.box3D {
   ……
   transform: rotate3d(0, 1, 0, 45deg);  //去掉transform:perspective(900px)
   ……
 }

之后再出发时,就不用重复配置transform: perspective(900px)选项了。

.box3D:hover {
    transform: rotate3d(0, 1, 1, 225deg);
 }

效果和之前一样,还能减少代码冗余。

最后

原创文章,文笔有限,才疏学浅,文中若有不正之处,速速告知。

本文到此结束,希望对你有所帮助,我是 Ashun ,在校大学生,立志成为资深前端工程师,欢迎大家一起交流、学习。后续更新更多文章,请持续关注哦~