CSS3优雅做动画系列,潜水艇动画

712 阅读5分钟

友情提醒,潜水艇动画的效果是真的屌,但知识点也真的多,建议直接CV大法把代码贴到你们的项目中,手写一遍,不要我看了,我收藏,我走了

此处,列一些我吸收的知识点,请尽情采撷。

image.png

正文

省流,先上效果

ezgif.com-video-to-gif.gif

第一步、潜水艇的探照灯

1、先实现一个渐变的背景

.light {
  position: absolute;
  top: 0%;
  left: 0%;
  width: 500px;
  height: 100px;
  background: linear-gradient(to left, $lightColor, $bgColor);
}

image.png

2、把背景定位到探照灯的位置

transform: translate(-18%, -45%);

image.png

3、截取背景图,让它的样子变成探照灯射出去的光芒

-webkit-clip-path: polygon(0% 0%, 50% 45%, 50% 55%, 0% 100%);
clip-path: polygon(0% 0%, 50% 45%, 50% 55%, 0% 100%);

image.png

clip-path是怎么实现这个神仙效果的呢,让我们分解其属性看下:

clip-path 是 CSS 属性,可以用来创造出各种各样的裁剪形状,其中 polygon() 函数是 clip-path 的其中一种用法。polygon() 函数可以创建一个由直线段连接各个点的多边形,每个点坐标通过 x 和 y 坐标的百分比指定。

语法如下:

clip-path: polygon(x1 y1, x2 y2, x3 y3, ..., xn yn);

代码中,clip-path 是通过一个四个顶点的多边形来裁剪元素的内容, 最后形成一个类似三角形的光束。该多边形的四个顶点的坐标如下:

  • 左上角:(0%, 0%)
  • 右上角:(50%, 45%)
  • 右下角:(50%, 55%)
  • 左下角:(0%, 100%)

这四个顶点通过 polygon() 函数的参数传递给 clip-path,最终将元素内容裁剪成这个多边形的形状,只显示多边形所包含的部分,而其他部分则被裁剪掉

第二步、探照灯的管子

定义一个长方形盒子,通过border,对其四个角设置宽度和颜色来实现

  width: 20px;
  height: 50px;
  border-right: 10px solid $lightShadowColor3;
  border-top: 10px solid $lightShadowColor2;
  border-left: 0px solid transparent;
  border-bottom: 0px solid transparent;
  border-top-right-radius: 10px;

image.png

第三步、潜水艇的驾驶舱

核心也是定义一个长方形的盒子,然后通过clip-path进行裁剪, 把长方形盒子的右上裁剪掉

clip-path: polygon(0% 0%, 70% 0%, 100% 100%, 0% 100%);

clip-path: polygon(0% 0%, 70% 0%, 100% 100%, 0% 100%); 的坐标参数进一步说明:

  • (0% 0%):表示多边形的第一条边的左上角
  • (70% 0%):表示多边形的第二条边的右上角,同时这个点也是多边形的右上角
  • (100% 100%):表示多边形的第三条边的右下角,同时这个点还是多边形的右下角
  • (0% 100%):表示多边形的第四条边的左下角,同时这个点还是多边形的左下角

需要注意的是,clip-path属性虽然强大,但是还不是所有浏览器都支持,特别是IE和Edge浏览器。因此,在开发中应该注意兼容性,同时也要注意对于某些较老版本浏览器可能会表现出不同的行为(IE已经退出历史舞台了)

image.png

第四步、潜水艇的身体

此处没啥特殊属性,画一个长方形盒子,使用border-radius:50px; 就可以了

第五步、潜水艇上闪闪的玻璃窗

核心使用的background-image 配合animation 在不同帧画出不同的背景形状

background-image: linear-gradient(45deg, $windowLightColor, #fff);
animation: shadow-change 1s linear infinite;

// 动画
@keyframes shadow-change {
  0%,
  100% {
    background-image: linear-gradient(
      45deg,
      $windowLightColor 0%,
      $windowLightColor 20%,
      #fff 21%,
      #fff 39%,
      $windowLightColor 40%,
      #fff 41%,
      #fff 59%,
      $windowLightColor 60%
    );
  }
  // ... 具体见下面的全文
}

细节:此处的background-image 并不仅仅用来存放背景图片,也可以被用来自定义的背景效果。

linear-gradient表示线性渐变,指定了渐变的方向角度(45度)。$windowLightColor#fff表示渐变的颜色。数字%表示渐变过程中的位置。让位置不停的动,不就实现了反光的效果了吗。

整个代码的意思是:

  • 页面的背景颜色设置成由$windowLightColor这个颜色开始
  • 在45度方向上从左上角向右下角变成#fff的渐变过程
  • 并在#fff以后从右下角向左上角渐变回$windowLightColor

第六步、潜水艇的尾翼

父盒子通过transitiontransitionanimation实现尾翼整体的转动效果

image.png

transition: transform 1s;
transform-style: preserve-3d;
animation: rotateInfinite 1s linear infinite;

// 动画
@keyframes rotateInfinite {
  0% {
    transform: rotateX(0deg);
  }
  50% {
    transform: rotateX(180deg);
  }
  100% {
    transform: rotateX(360deg);
  }
}

两个子盒子通过transform变形生成尾翼的样子

尾翼一

transform: rotateY(180deg) rotateX(225deg);

尾翼二

transform: rotateX(45deg);

核心点罗列

1、 perspective:600px;意味着该元素的后代元素(使用 3D 变换)将视觉上位于 3D 空间内,并在转换时受到视距值的影响。此处观察者和 3D 元素之间的距离为 600 像素。(实际并没啥效果,删了也不影响,懂行的小伙伴可以评论区留言)

2、transition: transform 1s 表示变换过渡,将应用于在 transform 属性。并且,这个过渡动画会持续一秒钟。

3、transform-style: preserve-3d ,父元素设置为 preserve-3d 属性时,它的子元素将能够在 3D 空间内变换。这里的 preserve-3d 主要表示父元素保留 3D 空间,而非只有单纯的 2D 平面效果。

大功告成,下面贴上全部代码

<template>
  <div class="seaContainer">
  <div class="submarine__container">
    <div class="light"></div>
    <div class="submarine__periscope"></div>
    <div class="submarine__periscope-glass"></div>
    <div class="submarine__sail">
      <div class="submarine__sail-shadow dark1">
      </div>
      <div class="submarine__sail-shadow light1"></div>
      <div class="submarine__sail-shadow dark2"></div>
    </div>
    <div class="submarine__body">
      <div class="submarine__window one">

      </div>
      <div class="submarine__window two">

      </div>
      <div class="submarine__shadow-dark"></div>
      <div class="submarine__shadow-light"></div>
      <div class="submarine__shadow-arcLight"></div>
    </div>
    <div class="submarine__propeller">
      <div class="propeller__perspective">
      <div class="submarine__propeller-parts darkOne"></div>
      <div class="submarine__propeller-parts lightOne"></div>
      </div>        
    </div>
  </div>
  <div class="bubbles__container">
    <span class="bubbles bubble-1"></span>
    <span class="bubbles bubble-2"></span>
    <span class="bubbles bubble-3"></span>
    <span class="bubbles bubble-4"></span>
  </div>
  <div class="ground__container">
    <div class="ground ground1">
      <span class="up-1"></span>
      <span class="up-2"></span>
      <span class="up-3"></span>
      <span class="up-4"></span>
      <span class="up-5"></span>
      <span class="up-6"></span>
      <span class="up-7"></span>
      <span class="up-8"></span>
      <span class="up-9"></span>
      <span class="up-10"></span>
    </div>
    <div class="ground ground2">
      <span class="up-1"></span>
      <span class="up-2"></span>
      <span class="up-3"></span>
      <span class="up-4"></span>
      <span class="up-5"></span>
      <span class="up-6"></span>
      <span class="up-7"></span>
      <span class="up-8"></span>
      <span class="up-9"></span>
      <span class="up-10"></span>
      <span class="up-11"></span>
      <span class="up-12"></span>
      <span class="up-13"></span>
      <span class="up-14"></span>
      <span class="up-15"></span>
      <span class="up-16"></span>
      <span class="up-17"></span>
      <span class="up-18"></span>
      <span class="up-19"></span>
      <span class="up-20"></span>
    </div>
  </div>
</div>
</template>
<style lang="scss" scoped>
//colors
$bgColor: #130560;
$subMarineColor: #e30449;
$lightShadowColor: #ef689e;
$lightShadowColor2: #c6003d;
$lightShadowColor3: #e92d77;
$darkShadowColor: #a10532;
$periscopeColor: #F0F78B;
$propellerColor: #f7e349;
$propellerColor2: #f7ac08;
$windowLightColor: #c9e5d9;
$lightColor: #817E97;
$seaGroundColor1:#0c0051;
$seaGroundColor2:#08003b;
//sizes

html,body {
  background:#130560;
  overflow:hidden;
}
.seaContainer {
  position: absolute;
  top: 0%;
  left: 0%;
  width: 100%;
  height: 100%;
  background: #130560;
  overflow:hidden;
}
.submarine__container {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 400px;
  height: 200px;
  transform: translate(-50%, -50%);
}
.submarine__body {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 250px;
  height: 80px;
  background: $subMarineColor;
  border-radius: 50px;
  transform: translate(-50%, -50%);
}
.submarine__propeller {
  position: absolute;
  left: 80%;
  top: 50%;
  width: 30px;
  height: 50px;
  transform: translate(0%, -50%);
  perspective: 600px;
 
}
.propeller__perspective
{
   width: 100%;
  height: 100%;
  transition: transform 1s;
 
  transform-style: preserve-3d;
  animation:rotateInfinite 1s linear infinite;
  cursor: pointer;
}
.submarine__propeller-parts
{
  position: absolute;
  left: 0%;
  width: 100%;
  height: 100%;
  top: 0%;
  perspective: 1000px;
  transform-style: preserve-3d;
}
.darkOne {
  top:0%;
  background: $propellerColor2;
  transform: rotateY(180deg)rotateX(225deg)
}
.lightOne
{
  top:0%;
   background: $propellerColor;
  transform:rotateX(45deg);
}
.submarine__sail {
  position: absolute;
  top: 40%;
  left: 50%;
  width: 90px;
  height: 50px;
  transform: translate(-50%, -100%);
  background: $lightShadowColor2;
  clip-path: polygon(0% 0%, 70% 0%, 100% 100%, 0% 100%);
}

.submarine__sail-shadow {
  position: absolute;
  width: 160%;
  height: 10%;
  background: $darkShadowColor;
  border-radius: 5px;
}
.dark1 {
  left: 0%;
  top: 0%;
  transform: translate(0%, -33%);
}
.dark2
{
  left:0%;
  top:50%;
}
.light1{
  left:20%;
  top:20%;
  width:50%;
  background:$lightShadowColor;
}
.submarine__window {
  width: 25px;
  height: 25px;
  border-radius: 100%;
  background-image: linear-gradient(45deg,$windowLightColor,#fff);
  border: 8px solid $darkShadowColor;
  z-index:10;
  animation:shadow-change 1s linear infinite;
}
.one,
.two {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
}
.one {
  left: 40%;
}
.two {
  left: 20%;
}

.submarine__shadow-dark {
  position: absolute;
  left: 70%;
  top: 50%;
  width: 70px;
  height: 10px;
  border-radius: 5px;
  transform: translate(-50%, -50%);
  background: $darkShadowColor;
}
.submarine__shadow-light {
  position: absolute;
  left: 35%;
  top: 13%;
  width: 100px;
  height: 6px;
  border-radius: 5px;
  transform: translate(-50%, -50%);
  background: $lightShadowColor;
}
.submarine__shadow-arcLight {
  position: absolute;
  top: 65%;
  left: 80%;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: $lightShadowColor;
}
.submarine__periscope {
  position: absolute;
  top: 0%;
  left: 40%;
  width: 20px;
  height: 50px;
  border-right: 10px solid $lightShadowColor3;
  border-top: 10px solid $lightShadowColor2;
  border-left: 0px solid transparent;
  border-bottom: 0px solid transparent;
  border-top-right-radius: 10px;
}
.submarine__periscope-glass {
  position: absolute;
  left: 40%;
  top: 0%;
  width: 5px;
  height: 15px;
  background: $propellerColor2;
  transform: translate(-50%, -15%);
}
.light {
  position: absolute;
  top: 0%;
  left: 0%;
  width: 500px;
  height: 100px;
  background: linear-gradient(to left, $lightColor, $bgColor);
  /* The points are: centered top, left bottom, right bottom */
  clip-path: polygon(0% 0%, 50% 45%, 50% 55%, 0% 100%);
  
  transform: translate(-18%, -45%);
}
.bubbles__container
{
  position:absolute;
  top:50%;
  left:55%;
  width:100px;
  height:50px;
transform:translate(100%,-50%);
}
.bubbles
{
  position:absolute;
  width:10px;
  height:10px;
  border-radius:100%;
  left:5%;
  top:5%;
  background:#fff;
  opacity:0.8;
}
$bubble-class: bubble;

@for $i from 1 through 4{
  .#{$bubble-class}-#{$i}{
    top:15%*($i+1-1);
    left:1%;
    opacity: 0;
    animation:move-right 1s infinite linear;
    animation-delay: 0.25s*$i;
}
}
.ground__container
{
  position:absolute;
  top:75%;
  left:0%;
  width:100%;
  height:25%;
  background:$seaGroundColor2;
  margin-top:20px;
}
.ground1
{
  top:75%;
  height:100%;
   background:$seaGroundColor1;
}
.ground2
{
  position:absolute;
  top:35%;
  width:100%;
  height:100%;
  background:$seaGroundColor2;
}

.ground span
{
  position:absolute;
  width:60px;
  height:60px;
  border-radius:100%;
  
}
.ground1 span
{
   background:$seaGroundColor1;
}
.ground2 span
{
   background:$seaGroundColor2;
   width:80px;
  height:80px;
  border-radius:100%;
 transform:translateY(30%);
}

$ground-class: up;
@for $i from 1 through 20 
{
  .#{$ground-class}-#{$i}{
    left:-10%*($i+-1);
    top:-20px*($i*0.10);
    animation:moveThegroundRight $i+2s infinite linear;
}
}
//animation

@keyframes shadow-change
{
  0%,100%
  {
    background-image: linear-gradient(45deg,$windowLightColor 0%,$windowLightColor 20% ,#fff 21%, #fff 39%, $windowLightColor 40%,#fff 41%,#fff 59%,$windowLightColor 60%);
  }
  20%
  {
    background-image: linear-gradient(45deg,$windowLightColor 20%,$windowLightColor 40% ,#fff 41%, #fff 59%, $windowLightColor 60%,#fff 61%,#fff 79%,$windowLightColor 80%);
  }
  40%
  {
    
    background-image: linear-gradient(45deg,$windowLightColor 40%,$windowLightColor 60% ,#fff 61%, #fff 79%, $windowLightColor 80%,#fff 81%,#fff 99%,$windowLightColor 0%);
  }
  60%
  {
    background-image: linear-gradient(45deg,$windowLightColor 60%,$windowLightColor 80% ,#fff 81%, #fff 99%, $windowLightColor 0%,#fff 1%,#fff 19%,$windowLightColor 20%);
  }
  80%
  {
    background-image: linear-gradient(45deg,$windowLightColor 80%,$windowLightColor 0% ,#fff 1%, #fff 19%, $windowLightColor 20%,#fff 21%,#fff 39%,$windowLightColor 40%);
  }
  
}

@keyframes move-right {
  0%
  {
    opacity:0;
  }
  10%
  {
    opacity:0.4;
    transform:translate(10%,10%);
  }
  50%
  {
    opacity:0.2;
    transform:translate(450%,25%);
  }
  80%
  {
    opacity:0;
     transform:translateX(555%);
  }
  100%
  {
    opacity:0;
    left:0%;
    top:0%;
  }
}
@keyframes rotateInfinite{
  0%
  {
    transform: rotateX(0deg);
  }
  50%
  {
    transform: rotateX(180deg);
  }
  100%
  {
    transform: rotateX(360deg);
  }
}
@keyframes moveThegroundRight
{
 90%
  {
    opacity:1;
   left:100%;
  }
  95%,100%
  {
    left:1050%;
    opacity:0;
  }
}
</style>

完结

这篇文章是我在网上冲浪的时候发现的效果,其实我一直蛮感兴趣CSS3动画,只是一直没时间搞,都用来刷某音和某站了。这里把动画效果和实现方式整理了一下,希望对小伙伴有帮助。

后续,我可能还会更新其他CSS3动画方面的,因为的确很感兴趣。

欢迎转载,但请注明来源。

最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

image.png