中秋节马上就要到了,在这里我提前祝大家生活美满万年长,阖家幸福永平安!
好了进入正题,最近掘金出了一个“中秋创意投稿”活动,我向来对这种可以写一些具有创意性的代码的活动很有兴趣,所以我必须参加,选题我选择做一个 beautiful 的中秋贺卡✊。
最终效果见文章顶部大图
ps:最终实现的效果经过了漫长的调整过程,尤其是调各种参数,一些中秋元素是参考了搜到的中秋相关图片,颜色也是吸的图片的颜色。所以,如果觉的最终效果还不错的,动动小手点个赞,你不会损失什么,我还能得到你的鼓励
本文默认你已经掌握了css的基础知识,这里只是罗列一下用到的知识,具体使用方法可以自行查阅学习。
我要实现的目标分为六部分:
其中的核心难点有以下几个 >>>
蓝色祥云背景的实现,全网目前应该是没有类似的实现,常见的css实现的纹理背景都是每个图案独立占一个区域,但是祥云不同,需要祥云直接互相“叠罗汉”;
黄色月亮上的镂空文字。如果文字镂空漏出的是黄色月亮,那非常容易实现,但是如果要漏出更下面一层的祥云背景,就需要多层图层混合,需要考虑清图层的层级关系以及应该使用的混合模式;
祥云的实现,目前网上也没有参考的案例,考虑了下决定用border-radius实现;
祥云背景参考了网上搜到的上图。观察后可以得出规律,是由“两个扇形的波纹图层错位叠加”
形成的祥云效果。
什么是扇形的波纹?看下图,是实现过程中的截图。
实现原理分为以下几个步骤(当然,实现过程并不是按照这个顺序开发的,这里只是从结果倒推):
先用radial-gradient()
实现半圆波纹图层;
然后用linear-gradient()
画两个三角形通过混合模式遮住半圆的两侧,形成扇形波纹;
最后再复制一层扇形波纹图层,背景位置 x,y 方向都错位移动50%即可达到最终效果。
详细的实现过程我重新整理了一篇文章,感兴趣的自行查阅。这里是文章链接:: 纯css实现祥云纹理背景
文字镂空的发光月亮的实现是最核心也是最难的一个点。因为一般的文字镂空是显示出来下方图像,也就是月亮的黄色,但是我这里要“穿透”两层,显示最底层的蓝色祥云背景。
提到镂空,能联想到的方向有很多:
-webkit-text-stroke
、box-shadow
文字描边实现镂空文字,但是这些方案只是把文字镂空了,但是无法“穿透”两层显示背景,淘汰;mask-image
需要用图片或者渐变函数形成的图像作为遮罩,因为我 主打的就是无图
,所以这个方案pass;-webkit-background-clip: text
背景裁剪。以文字裁剪之后只会留下文字部分,月亮就没了,pass;blend-mode
混合模式了。显然它是最优也是唯一的解决方案,本身它就是解决多个图层层叠后的混合模式场景的最终定下了解决方案:
blend-mode混合模式
实现的大致过程如下:
实际实现过程并不像下面这么顺,只是实现之后重新捋出来一个比较顺的逻辑,提高实现此类效果的逻辑思维。
首先我们要思考最底层的祥云背景是深蓝色,属于深色系。而月亮黄色属于亮色系,在融合后要保留月亮,混合模式就得选用lighten变亮
或者screen滤色
。
那月亮是能保留了,文字怎么镂空呢?很简单,只要文字比背景的深蓝色深不就行了,我直接将文字设置为黑色。这时候得到的效果如下:
可以看到,效果大致实现了,但其实还差的很远。因为现在月亮整体也会有点透明的效果,能看到底部的祥云背景。
那怎么就能完全遮盖住祥云背景呢,根据screen滤色混合模式
叠白得白得特点,可以将月亮设置为白色,就能完全遮盖背景了,如下:
但是这样又不对了,我们的月亮需要是黄色的呀。OK,有了,再在月亮上面叠加一个黄色背景不就行了。诶,不对,那不是又把文字盖住了
再思考思考,上面盖一层黄色的图层,然后还要把下面的文字显示出来,黄色比目前的白色月亮暗,所以可以用darken变暗混合模式
或者multiply正片叠底
,然后再利用变暗叠白无效的原理,再在这一层相同位置覆盖”中秋“文字,并设置白色,既可完美实现效果,如下:
#moon_behind{
background: #fff;
mix-blend-mode: screen;
...
h1{
color: #000;
}
}
#moon_yellow{
background: linear-gradient(#FF0,#FC0);
mix-blend-mode: multiply;
...
h1{
color: #fff;
}
}
<div id="moon_behind"><h1>中秋</h1></div>
<div id="moon_yellow"><h1>中秋</h1></div>
灯笼的实现就简单多了,一个div就可以搞定了。
灯笼的顶部方块用:before
伪元素绘制;
灯笼的“架子”线条用repeating-linear-gradient
绘制,灯笼的光源用radial-gradient
绘制,这里要注意线条和光源的书写顺序,光源在前,架子在后,不然光源就会被架子遮挡;
灯笼底部的穗子在:after
伪元素中用repeating-linear-gradient
绘制。
到这里,一个静态的灯笼就绘制好了,要把它以不同大小显示在不同位置,可以利用css变量很方便的设置每个灯笼的大小和位置。
//灯笼主体
.lantern{
--lanternLine: #d7061f; //灯笼架子颜色
--lanternWidth: 7vw; //灯笼宽
--lanternHeight: 12.5vw; //灯笼高
//架子和光源
background: radial-gradient(circle at center,#febb75 0%, transparent var(--radius)),repeating-linear-gradient(to right, transparent 0%, transparent 15%, var(--lanternLine) 15%, var(--lanternLine) 25% );
...
}
//穗子
.lantern::after{
content: '';
width: 40%;
height: 150px;
background: repeating-linear-gradient(to right, var(--lanternLine) 0%, var(--lanternLine) 5%, transparent 5%, transparent 10% );
...
}
<!-- 灯笼 -->
<div class="lantern" style="--l: 15%;--t: 7%;--scale: .9"></div>
然后就是实现灯笼的闪光效果了,因为光源是用径向渐变实现的,所以只要修改径向渐变的半径即可。
但是浏览器是不支持渐变色的补间动画的,因为浏览器不知道颜色的变化过程。但是我们可以通过@property
自定义属性来定义一个百分比值作为径向渐变的半径,浏览器肯定是可以计算数字的变化过程。这样修改这个自定义属性就能实现动画过程了。
.lantern{
background: radial-gradient(circle at center,#febb75 0%, transparent var(--radius)),repeating-linear-gradient(to right, transparent 0%, transparent 15%, var(--lanternLine) 15%, var(--lanternLine) 25% );
animation: lantern 1s linear infinite alternate;
}
@property --radius {
syntax: '' ;
inherits: false;
initial-value: 35%;
}
@keyframes lantern {
to{
--radius: 50%;
}
}
祥云由很多曲线构成,思考片刻,决定用border实现。只要给border设置弧度,并且border-width
有一定宽度,在boder缺口处就会形成线条逐渐变细的笔触,然后通过定位,将很多有缺口的圆拼接到一起,就形成了祥云。
如下是拆解的一部分:
div{
width: 100px;
height: 100px;
border: 7px solid #fff;
border-radius: 50% 50% 20% 50%;
border-right: 0;
}
然后用多个上面的圈通过定位组合,就构成了祥云。
这里额外说明一下,为了使画面丰富,每个祥云我都设置了不同的颜色(五彩祥云)。但是现在所有的祥云都是在月亮上面飘过的,画面不是很和谐,既然月亮上的文字都镂空了,那如果云彩从月亮后飘过,并且路过文字镂空的区域时,那一定很有趣
怎么让祥云从月亮背后飘过呢?那肯定是改z-index
层级啊,只要让月亮层级比祥云高不就行了,但是你会发现,祥云路过月亮时不会从后面飘过,而是有个变色的效果,如下:
为什么呢?因为月亮设置了混合模式正片叠底
,祥云路过时就会变暗。根据正片叠底
叠白无效的特点,只要祥云是白色,在路过月亮时就会完全保留月亮的黄色,最终效果如下:
兔子的实现就非常简单了。网上找一个卡通的兔子图片,然后将它构图拆解成很多椭圆的拼接,最后通过定位拼图即可。
月亮左下角剩余空间比较小,所以我决定画一个小巧简单可爱的小兔子。既然都追求简单了,用一个div实现它
。
创建一个div作为兔子身体。兔子身体是个不规则椭圆,所以用四个值的 border-radius 效果并不是很好,需要设置8个值,调整参数到合适的形状。
.rabbit{
//兔子身体形状
border-radius: 41% 59% 41% 41% / 54% 60% 40% 41%;
}
实现的时候先写出个大概的参数,然后在浏览器控制台微调参数即可。
兔子眼睛用radial-gradient
实现,需要用at position
语法把眼睛定位要合适的位置。
//眼睛
background-image: radial-gradient(circle at 80% 48%,#000 0%,#000 4%,transparent 4%);
兔子两个耳朵形状一样,所以用before
伪元素实现一个耳朵,另一个耳朵用box-shadow
复制一个即可,注意模糊距离设置为0。
兔子的jue和尾巴都是圆的,同样用after
伪元素实现一个jue,另一个jue和尾巴都用box-shadow
复制。
为了给兔子增加点活力,可以加个奔跑动画。实现起来不复杂,但是也需要不断调整参数使动画流畅。为了节省时间,我在网上搜到了一个兔子奔跑的动画,直接参考它的效果简单实现了下。
jcode
深蓝色祥云背景的实现,我单独写了一篇文章,感兴趣的可以看看传送门
我是归纳总结前端相关知识的前端阿彬,个人创作不易,您的点赞·关注·评论·转发 是我坚持下去的动力
往期文章:
# “钉钉官网首页的炫酷动效” 被我用css新特性轻松破解啦~
# CSS魔术师Houdini,用浏览器引擎实现高级CSS效果
# ⛳前端进阶:SEO 全方位解决方案
# 我给自己搭建的前端导航网站,你们都别用
# 2023 最新最细 vite+vue3+ts 多页面项目架构,建议收藏备用!
# 2023 前端性能优化清单