Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

谈谈一些有趣的CSS题目(20)-- 巧妙地制作背景色渐变动画! #10

Open
chokcoco opened this issue Mar 21, 2017 · 13 comments

Comments

@chokcoco
Copy link
Owner

chokcoco commented Mar 21, 2017

通过本文,你能了解到 4 种不一样的,使用纯 CSS 制作的渐变背景的过渡动画的方式。

有的时候,我们可能需要下面这样的动画效果,渐变背景色的过渡动画:

渐变背景的过渡动画

假设我们渐变的写法如下:

div {
    background: linear-gradient(90deg,  #ffc700 0%, #e91e1e 100%);
}

按照常规想法,配合 animation ,我们首先会想到在 animation 的步骤中通过改变颜色实现颜色渐变动画,那么我们的 CSS 代码可能是:

div {
    background: linear-gradient(90deg,  #ffc700 0%, #e91e1e 100%);
    animation: gradientChange 2s infinite;
}

@keyframes gradientChange  {
    100% {
        // 渐变中的颜色发生了变化
        background: linear-gradient(90deg,  #e91e1e 0%, #6f27b0 100%);
    }
}

上面我们用到了三种颜色:

  • #ffc700 黄色
  • #e91e1e 红色
  • #6f27b0 紫色

最后,并没有我们预期的结果,而是这样的:

lineargradient2

CodePen Demo - linear-graident 变换的动画效果

我们预期的过渡动画,变成了逐帧动画。 wtf

也就是说,线性渐变是不支持动画 animation 的。

那单纯的由一个颜色,变化到另外一个颜色呢?像下面这样:

div {
    background: #ffc700;
    animation: gradientChange 3s infinite alternate;
}

@keyframes gradientChange  {
    100% {
        background: #e91e1e;
    }
}

我们发现,单纯的单色值之间的变化是可以发生渐变的:

单色渐变

部分属性是不支持直接整个进行过渡动画的

总结一下,线性渐变(径向渐变、角向渐变)是不支持 animation 的,单色的 background 是支持的。

查找了下文档,在 background 附近区域截图如下:

哪些 CSS 属性可以动画?,上面的截图是不完整的支持 CSS 动画的属性,完整的可以戳左边。

对于 background 相关的,文档里写的是支持 background 但是没有细说不支持 background: linear-gradient()/radial-gradient()

那么是否我们想要的背景色渐变动画就无法实现了呢?下面我们就发散下思维看看有没有其他方式可以达到我们的目标。

通过 background-position 模拟渐变动画

上面哪些 CSS 属性可以动画的截图中,列出了与 background 相关还有 background-position ,也就是 background-position 是支持动画的,通过改变 background-position 的方式,可以实现渐变动画:

div {
    background: linear-gradient(90deg,  #ffc700 0%, #e91e1e 50%, #6f27b0 100%);
    background-size: 200% 100%;
    background-position: 0 0;
    animation: bgposition 2s infinite linear alternate;
}

@keyframes bgposition {
    0% {
        background-position: 0 0;
    }
    100% {
        background-position: 100% 0;
    }
}

这里我们还配合了 background-size。首先了解下:

background-position:指定图片的初始位置。这个初始位置是相对于以 background-origin 定义的背景位置图层来说的。

background-size:设置背景图片大小。当取值为百分比时,表示指定背景图片相对背景区的百分比大小。当设置两个参数时,第一个值指定图片的宽度,第二个值指定图片的高度。

通过 background-size: 200% 100% 将图片的宽度设置为两倍背景区的宽度,再通过改变 background-position 的 x 轴初始位置来移动图片,由于背景图设置的大小是背景区的两倍,所以 background-position 的移动是由 0 0 -> 100% 0

通过 background-size 模拟渐变动画

既然 background-position 可以,那么另一个 background-size 当然也是不遑多让。与上面的方法类似,只是这次 background-position 辅助 background-size ,CSS 代码如下:

div {
    background: linear-gradient(90deg,  #ffc700 0%, #e91e1e 33%, #6f27b0 66%, #00ff88 100%);
    background-position: 100% 0;
    animation: bgSize 5s infinite ease-in-out alternate;

}

@keyframes bgSize {
    0% {
        background-size: 300% 100%;
    }
    100% {
        background-size: 100% 100%;
    }
}

CodePen--Demo--position-size 实现渐变动画

通过改变 background-size 的第一个值,我将背景图的大小由 3 倍背景区大小向 1 倍背景区大小过渡,在背景图变换的过程中,就有了一种动画的效果。

而至于为什么要配合 background-position: 100% 0 。是由于如果不设置 background-position ,默认情况下的值为 0% 0%,会导致动画最左侧的颜色不变,像下面这样,不大自然:

positionsizegradient

通过 transform 模拟渐变动画

上面两种方式虽然都可以实现,但是总感觉不够自由,或者随机性不够大。

不仅如此,上述两种方式,由于使用了 background-positionbackground-size,并且在渐变中改变这两个属性,导致页面不断地进行大量的重绘(repaint),对页面性能消耗非常严重,所以我们还可以试试 transfrom 的方法:

下面这种方式,使用伪元素配合 transform 进行渐变动画,通过元素的伪元素 before 或者 after ,在元素内部画出一个大背景,再通过 transform 对伪元素进行变换:

div {
    position: relative;
    overflow: hidden;
    width: 100px;
    height: 100px;
    margin: 100px auto;
    border: 2px solid #000;
    
    &::before {
        content: "";
        position: absolute;
        top: -100%;
        left: -100%;
        bottom: -100%;
        right: -100%;
        background: linear-gradient(45deg,  #ffc700 0%, #e91e1e 50%, #6f27b0 100%);
        background-size: 100% 100%;
        animation: bgposition 5s infinite linear alternate;
        z-index: -1;
    }
}


@keyframes bgposition {
    0% {
        transform: translate(30%, 30%);
    }
    25% {
        transform: translate(30%, -30%);
    }
    50% {
        transform: translate(-30%, -30%);
    }
    75% {
        transform: translate(-30%, 30%);
    }
    100% {
        transform: translate(30%, 30%);
    }
}

实现原理如下图所示:

CodePen--Demo--伪元素配合transform实现背景渐变

上面列出来的只是部分方法,理论而言,伪元素配合能够产生位移或者形变的属性都可以完成上面的效果。我们甚至可以运用不同的缓动函数或者借鉴蝉原则,制作出随机性十分强的效果。

当然,本文罗列出来的都是纯 CSS 方法,使用 SVG 或者 Canvas 同样可以制作出来,而且性能更佳。感兴趣的读者可以自行往下研究。

通过滤镜 hue-rotate 实现渐变动画(更新于2019/04/06)

下面这个方法,可谓是新时代的利器。

通过滤镜 hue-rotate,可以非常方便的实现背景色渐变动画,过渡效果也非常的自然,代码量也少,可以称得上是黑科技了:

div {
    background: linear-gradient(45deg, #ffc107, deeppink, #9c27b0);
    animation: hueRotate 10s infinite alternate;
}

@keyframes hueRotate {
    0 {
        filter: hue-rotate(0);
    }
    100% {
        filter: hue-rotate(360deg);
    }
}

css-linear-bg

CodePen Demo -- hue-rotate实现渐变背景动画

使用 CSS @Property 实现背景色渐变动画(更新于 2021/04/15)

到今天(2021/04/15),我们还可以使用 CSS @property 实现背景色渐变动画,它的出现,极大的增强的 CSS 的能力!

根据 MDN -- CSS Property@Property CSS at-rule 是 CSS Houdini API 的一部分, 它允许开发者显式地定义他们的 CSS 自定义属性,允许进行属性类型检查、设定默认值以及定义该自定义属性是否可以被继承。

@property --colorA {
  syntax: '<color>';
  inherits: false;
  initial-value: fuchsia;
}
@property --colorC {
  syntax: '<color>';
  inherits: false;
  initial-value: #f79188;
}
@property --colorF {
  syntax: '<color>';
  inherits: false;
  initial-value: red;
}
div {
    background: linear-gradient(45deg,
        var(--colorA),
        var(--colorC),
        var(--colorF));
    animation: change 10s infinite linear;
}

@keyframes change {
    20% {
        --colorA: red;
        --colorC: #a93ee0;
        --colorF: fuchsia;
    }
    40% {
        --colorA: #ff3c41;
        --colorC: #e228a0;
        --colorF: #2e4c96;
    }
    60% {
        --colorA: orange;
        --colorC: green;
        --colorF: teal;
    }
    80% {
        --colorA: #ae63e4;
        --colorC: #0ebeff;
        --colorF: #efc371;
    }
}

简单解读下,CSS @Property 其实就是灵活度更高的,CSS 自定义属性,我们也可以称其为 CSS Houdini 自定义属性。其中:

  • @property --property-name 中的 --property-name 就是自定义属性的名称,定义后可在 CSS 中通过 var(--property-name) 进行引用
  • syntax:该自定义属性的语法规则,也可以理解为表示定义的自定义属性的类型
  • inherits:是否允许继承
  • initial-value:初始值

在上述的 DEMO 中,我们利用了 CSS Houdini 自定义属性,将原本定义在 background 的过渡效果嫁接到了 color 之上,而 CSS 是支持一个颜色变换到另外一个颜色的,这样,我们巧妙的实现了渐变背景色的过渡动画。

关于更多 CSS @property 相关的内容,你可以戳这篇文章详细了解 -- CSS @property,让不可能变可能

完整的代码可以戳这里:

CodePen Demo -- CSS Houdini 自定义属性实现渐变色过渡动画

至此,我们就得到了 4 种不一样的,使用纯 CSS 制作的渐变背景的过渡动画的方式。

运用背景色渐变动画

背景色渐变动画具体可以运用在什么地方呢,稍微举个例子。

背景色渐变过渡实现按钮的明暗变化

gradienthover

CodePen -- Demo -- 背景色渐变过渡实现按钮的明暗变化

除此之外,在背景板凸显文字,让一些静态底图动起来吸引眼球等地方都有用武之地。

最后

好了,本文到此结束,希望对你有帮助 :)

更多精彩 CSS 技术文章汇总在我的 Github -- iCSS ,持续更新,欢迎点个 star 订阅收藏。

如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

@chokcoco chokcoco changed the title 背景色渐变动画!? 谈谈一些有趣的CSS题目(20)-- 背景色渐变动画!? Mar 21, 2017
@chokcoco chokcoco changed the title 谈谈一些有趣的CSS题目(20)-- 背景色渐变动画!? 谈谈一些有趣的CSS题目(20)-- 巧妙地制作背景色渐变动画! Mar 23, 2017
@kosl90
Copy link

kosl90 commented Mar 24, 2017

linear-gradient 严格来说是 background-image 属性的值,MDN 上的 animation type 为 discrete,咋一看有点懵,从 spec 上来看就比较清晰了: Animatable 是 no

@shellphon
Copy link

由于使用了 background-position 和 background-size,并且在渐变中改变这两个属性,导致页面不断地进行大量的重绘(repaint),对页面性能消耗非常严重,所以我们还可以试试 transfrom 的方法:

拜读到这一句有个小疑问,请教一下,transform translate不会引起重绘么?翻了一会没找到相关信息

@chokcoco
Copy link
Owner Author

chokcoco commented Aug 4, 2017

@shellphon
使用 transform/transform3d 可以开启 GPU 加速,避免页面的大面积重绘。
原理可以看看:
http://www.cnblogs.com/coco1s/p/5439619.html
https://www.html5rocks.com/zh/tutorials/speed/layers/#disqus_thread
https://www.html5rocks.com/zh/tutorials/speed/high-performance-animations/

@arronf2e
Copy link

我可以问下 gif 图是怎么录制的嘛 @chokcoco

@chokcoco
Copy link
Owner Author

@arronf2e
我用的是 若水GIF动态截图
录制完成后可以编辑,去掉一些不必要的帧,可以添加水印,工具本身很小只有几MB吧,可以试一下

@arronf2e
Copy link

@chokcoco OK,谢谢

@jawil
Copy link

jawil commented Sep 27, 2017

我也来推荐安利一波:

mac 上,我在用Gifox, snagit。但其实,giphy 也不错
https://giphy.com/apps/giphycapture
App Store 直接下

http://recordit.co/ 这个也不错,简单粗暴,就是没有配置选项

还有这个也是免费的,而且 windows mac 都支持。。收费除了 SnagIt(支持 windows 和 mac),还有 Gifox(只支持 mac)

@arronf2e

@arronf2e
Copy link

@jawil ok,正是mac,我去试用下,多谢

@kuoruan
Copy link

kuoruan commented May 7, 2018

关于最后的按钮渐变,使用 background-position 这种方式和直接改变 linear-gradient 有何区别?哪种性能更好?

@entingzhang
Copy link

我想说为什么我按照上面的逻辑 都是一样的代码 确实先不了效果呢

@chokcoco
Copy link
Owner Author

@entingzhang 嗯,可以提供下代码不,一起看看~

@fanmucc
Copy link

fanmucc commented Mar 27, 2019

基佬就是基佬, 不对大佬就是大佬

@Purek
Copy link

Purek commented Mar 8, 2023

大佬,太厉害了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants