CSS3优雅做动画系列,描边动画

1,524 阅读5分钟

image.png

今天接着CSS3优雅做动画系列,继续学习如何用CSS3实现描边动画,这个笔者之前在工作中也遇到过类似的效果,都是从网上CV大法完事。结果,再做到类似效果,还是脑子里迷糊糊的。

今天,准备系统的从头到尾撸一遍,笔记奉上。

磨刀不误砍柴工,让我们先把刀刀磨磨。

让我们先来了解下scss和css的区别

1,书写方式

CSS 使用分号和大括号等符号进行样式的书写,而 SCSS 类似于编程语言,使用了类似于变量、函数、循环等语法,使其更加灵活。

2,可复用性

在 SCSS 中可以使用变量和 Mixin来定义可复用的样式代码,而 CSS 没有这种功能,需要手动复制粘贴代码。

3,兼容性

CSS 是所有浏览器都可以解析的纯文本样式语言,而 SCSS 需要预处理器将其转换为浏览器可解析的 CSS 代码。

此处衍生3个知识点

3.1 预处理器指的是什么?什么时候转成css的?

SCSS 的预处理器指的是node-sasssass-loader。在 Webpack 的构建过程中, 将 SCSS 文件编译成 CSS 代码了。

3.2 node-sass和sass-loader有啥关系?为什么通常我安装sass-laoder的时候还建议我安装node-sass

node-sass是一个用于解析和编译 Sass 和 SCSS 文件的 Node.js 模块,它可以将 Sass 和 SCSS 文件编译为浏览器可解析的 CSS 代码。node-sass 是一个独立的模块,可以通过 npm 安装来使用。

sass-loader是一个 Webpack 的 loader,将 Sass 文件加载进 webpack 构建流程中,并调用 node-sass 依据 Sass 语法编译成 CSS,最终输出到打包文件中。这也是在使用sass-loader时,需要先安装node-sass的原因。

3.3 使用scss的实际优点有哪些?

可以让开发者编写更加灵活、高效的样式代码,通过使用变量、mixin 等特性来实现样式的复用和管理,从而避免重复代码和提高代码的可维护性,也就是传说中的降本增效~~(哪都有降本增效)

4,嵌套

SCSS 可以通过嵌套来定义样式,使得层次结构更加清晰易读,而 CSS 需要使用类似 BEM 等命名方式来实现相同效果。

css写法
.wrapper:hover {
    background-color: #f0f0f0;
}
.wrapper .item {
    color: #333;
}
  
div + p {
    color: red;
}
scss写法
// & 的作用是用来代表父元素选择器的占位符,可以减少类的数量,让代码更简洁。在编译后的 CSS 中,& 会被替换成实际的父元素选择器

.wrapper {
    &:hover {
      background-color: #f0f0f0;
    }
    & .item {
      color: #333;
    }
}

div {
    + p {
      color: red;
    }
}

image.png

正文

省流,先上效果

11.gif

第一步、引入流弊字体

引入方式

@import url(https://fonts.googleapis.com/css?family=Six+Caps);

使用

font-family: "Six Caps", sans-serif;

第二步、定义常用变量

引入方式

$color : yellow;

// 或者

--color: #ffffff;

使用

background: $color;

// 或者

background: var(--color);

-- 是css中的自定义属性,用于存储在元素级别上的自定义数据。

第三步、预留动画运行的位置

此处的var(--border-width)在后面动画线条的宽高处也有用到

border: var(--border-width) solid transparent;

第四步、animation中的forwards和ease-in-out

animation 是 CSS3 中用于动画效果实现的属性,其中 forwards 和 ease-in-out 是指定在动画执行结束时的最终状态和动画执行过程中使用的时间函数。

  • forwards 表示在动画完成之后,元素将设置为动画结束时的状态,并保持该状态,即将最终状态应用于元素。如果没有指定 forwards,则动画将回到其原始状态,即回到初始值。
  • ease-in-out 是一种过渡类型的时间函数,表示动画效果开始时慢慢加速,然后达到最大速度,在接近结束时再慢慢减速。这个时间函数会使动画看起来比较流畅。

第五步、通过伪类实现动画线条的绘制

通过伪类&:hover实现鼠标放上去开始动画,通过伪类beforeafter实现动画线条的绘制

线条动画举例

&:before,
&:after {
    content: "";
    position: absolute;
    background: var(--color);
}

初始状态before的宽高,位置

image.png

鼠标放上去后,配合beforeBorders动画

// 鼠标放上去
&:focus:before,
&:hover:before {
  animation: beforeBorders var(--animation-speed) forwards ease-in-out;
}
// 动画
@keyframes beforeBorders {
  0% {
    top: calc(var(--border-width) * -1);
    left: 50%;
    bottom: auto;
    right: auto;
    width: 0;
    height: var(--border-width);
  }
  33% {
    top: calc(var(--border-width) * -1);
    left: calc(var(--border-width) * -1);
    bottom: auto;
    right: auto;
    width: calc(var(--border-width) + 50%);
    height: var(--border-width);
  }
  66% {
    top: calc(var(--border-width) * -1);
    left: calc(var(--border-width) * -1);
    bottom: auto;
    right: auto;
    width: var(--border-width);
    height: calc((var(--border-width) * 2) + 100%);
  }
  100% {
    top: auto;
    left: calc(var(--border-width) * -1);
    bottom: calc(var(--border-width) * -1);
    right: auto;
    width: calc(var(--border-width) + 50%);
    height: calc((var(--border-width) * 2) + 100%);
  }
}

结束状态before的宽高,位置

image.png

动画中,线条跑动的位置变化就是通过动画中0%33%66%100%,不同帧位置+宽高的变化实现。

动画中,线条跑动的效果就是通过上面的位置变化加上borderColors动画中0%33%66%100%不同帧控制线条不同的透明度,一起实现的。

@keyframes borderColors {
  0% {
    border-top-color: transparent;
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-left-color: transparent;
  }
  33% {
    border-top-color: var(--color);
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-left-color: transparent;
  }
  66% {
    border-top-color: var(--color);
    border-right-color: var(--color);
    border-bottom-color: transparent;
    border-left-color: var(--color);
  }
  100% {
    border-top-color: var(--color);
    border-right-color: var(--color);
    border-bottom-color: var(--color);
    border-left-color: var(--color);
  }
}

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

<template>
  <div class="container">
      <a class="border-animation" href="#">
      <div class="border-animation__inner">Border animation</div></a>
    </div>
</template>
<style lang="scss" scoped>
@import url(https://fonts.googleapis.com/css?family=Six+Caps);


.container {
  width: 100%;
  height: 100vh;
  background: #000000;
}

.border-animation {
  --border-width: 0.1em;
  --animation-speed: 0.5s;
  --color: #ffffff;
  color: var(--color);
  position: relative;
  display: inline-block;
  font-size: 4em;
  line-height: 1em;
  transform: scale(1, 0.8);
  border: var(--border-width) solid transparent;
  
  .border-animation__inner {
    position: relative;
    display: inline-block;
    font-family: 'Six Caps', sans-serif;
    font-weight: 300;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    cursor: pointer;
    padding: 0.2em;
    // background: rgba(50, 50, 50, 0.5);
    background: #333;
    z-index: 1;
    border: solid var(--border-width) transparent;
  }
  
  &:before,
  &:after {
    content: '';
    position: absolute;
    background: var(--color);
  }
  
  &:focus:before,
  &:hover:before {
    animation: beforeBorders var(--animation-speed) forwards ease-in-out;
  }

  &:focus:after,
  &:hover:after {
    animation: afterBorders var(--animation-speed) forwards ease-in-out;
  }
  
  &:focus,
  &:hover {
    animation: borderColors var(--animation-speed) steps(1) forwards;
    outline: none;

    .border-animation__inner {
      animation: background calc(var(--animation-speed) / 5 * 3) forwards ease-in-out;
      animation-delay: calc(var(--animation-speed) / 5 * 2);
    }
  }
}

@keyframes beforeBorders {
  0% {
    top: calc(var(--border-width) * -1);
    left: 50%;
    bottom: auto;
    right: auto;
    width: 0;
    height: var(--border-width);
  }
  33% {    
    top: calc(var(--border-width) * -1);
    left: calc(var(--border-width) * -1);
    bottom: auto;
    right: auto;
    width: calc(var(--border-width) + 50%);
    height: var(--border-width);
  }
  66% {
    top: calc(var(--border-width) * -1);
    left: calc(var(--border-width) * -1);
    bottom: auto;
    right: auto;
    width: var(--border-width);
    height: calc((var(--border-width) * 2) + 100%);
  }
  100% {
    top: auto;
    left: calc(var(--border-width) * -1);
    bottom: calc(var(--border-width) * -1);
    right: auto;
    width: calc(var(--border-width) + 50%);
    height: calc((var(--border-width) * 2) + 100%);
  }
}

@keyframes afterBorders {
  0% {
    top: calc(var(--border-width) * -1);
    left: auto;
    bottom: auto;
    right: 50%;
    width: 0;
    height: var(--border-width);
  }
  33% {    
    top: calc(var(--border-width) * -1);
    left: auto;
    bottom: auto;
    right: calc(var(--border-width) * -1);
    width: calc(var(--border-width) + 50%);
    height: var(--border-width);
  }
  66% {
    top: calc(var(--border-width) * -1);
    left: auto;
    bottom: auto;
    right: calc(var(--border-width) * -1);
    width: var(--border-width);
    height: calc((var(--border-width) * 2) + 100%);
  }
  100% {
    top: auto;
    left: auto;
    bottom: calc(var(--border-width) * -1);
    right: calc(var(--border-width) * -1);
    width: calc(var(--border-width) + 50%);
    height: calc((var(--border-width) * 2) + 100%);
  }
}

@keyframes borderColors {
  0% {
    border-top-color: transparent;
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-left-color: transparent;
  }
  33% {
    border-top-color: var(--color);
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-left-color: transparent;

  }
  66% {
    border-top-color: var(--color);
    border-right-color: var(--color);
    border-bottom-color: transparent;
    border-left-color: var(--color);
  }
  100% {
    border-top-color: var(--color);
    border-right-color: var(--color);
    border-bottom-color: var(--color);
    border-left-color: var(--color);
  }
}

@keyframes background {
  to {
    background: #555;
    text-shadow: 0 0.1em 0.1em #111;
  }
}

@media (min-width: 850px) {
  body {
    justify-content: center;
  }
}

@media (min-width: 1200px) {
  .border-animation {
    font-size: 6em;
    line-height: 1em;    
  }
}
</style>

完结

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

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

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

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

image.png