我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛
前言
之前见过不少节假日“程序员的浪漫”,这不中秋节快到了,我也来蹭一蹭。没有用到Canvas,只是简单的HTML+CSS+JS三件套,好了废话不多说,我们直接看看最终的动画效果。
(好了好了别骂了,土到极致就是潮!PS:动图中火箭尾部留有瑕疵是ScreenToGif渲染的问题)
如图所示,动画中共有月亮、飞机、星星、火箭、对联和海平面6种元素。我们只需要分别实现它们的动画效果,简单地布局一下就好,开干!
元素实现
- 月亮🌕
什么月亮,它就是一个
div。设定好宽高之后,修改border-radius:50%,然后设置一下背景为线性渐变linear-gradient(),这样一个有渐变色背景的圆就画好了。为了让这个圆更像一个发光体(月球本身是不会发光的),我们可以设置一下box-shadow,这样一个看起来像太阳的月亮就做好了。
.moon {
width: 30vw;
height: 30vw;
border-radius: 50%;
background: linear-gradient(#f1c40f,#f39c12);
box-shadow: 0px 0px 50px 5px #f39c12;
position: absolute;
right: 30%;
top: 10%;
animation: moon 5s forwards;
}
- 飞机✈️ 为什么要放一个飞机呢,因为中秋佳节是团圆的日子,这架飞机里搭载的都是回家的人们,承载了浓浓的思乡之情。没错,我不仅仅画了个飞机,您若仔细看了,机内的乘客张三李四也都是我的作品。
这架飞机它不是div拼接出来的,而是用了CSS3的一个属性mask-image。它可以通过特定的素材图将我们想要的形状“刻出来”,并可以自定义背景色或背景图。我在网上找了一张飞机的透明矢量图,通过这个属性我搞了这架飞机。更多关于mask-image的使用场景,可以看看我之前写的一篇文章 探究mask-image的魔力——Win10日历的探照灯效果原来可以这样做!
.airplane {
width: 100px;
height: 100px;
background-color: #000;
-webkit-mask-image: url(./image/airplane.png);
-webkit-mask-size: 100px 100px;
position: absolute;
right: 10%;
top: 20%;
animation: fly 5s ease-in-out forwards;
z-index: 5;
}
- 星星⭐
因为我太菜了,不会用纯CSS绘制五角星,因此我还是用的
mask-image来搞定五角星的形状,至于星星的闪烁,只需要周期性修改opacity就好了。天上的星星参北斗啊!星星太多了,他们的位置、大小、闪烁状态都不会是完全一致的。这里就需要引入随机函数Math.random()来生成随机的位置、大小和闪烁状态。为了避免星星掉进海里,需要设置一个放星星的区域。
关于Math.random()这个方法,我觉得有必要做下笔记加深印象。
Math.random()[0,1)不包含1
Math.floor(Math.random() * (max - min) ) + min[min,max) 不包含max的整数
Math.floor(Math.random() * (max - min + 1) ) + min[min,max] 包含max的整数
(写到这我突然想到我可以搞出流星雨来啊!陪Ta去看流星雨落在这地球上不比打代码有意思?可我都写到这了,算了流星雨说它不来了)
.star {
position: absolute;
background-color: #f1c40f;
width: 20px;
height: 20px;
animation: star 3s linear infinite;
box-shadow: 0px 0px 20px 5px rgb(255 255 255 / 30%);
-webkit-mask-image: url(./image/star.png);
-webkit-mask-size: 20px 20px;
}
window.onload = function(){
let starWrap = document.querySelector('.star-wrap')
for(let i=0;i<50;i++){
let star = document.createElement('div')
let {posX,posY,size,delay} = createRandom()
star.className = "star"
star.style.left = posX
star.style.top = posY
star.style.width = star.style.height = size
star.style.webkitMaskSize = `${size} ${size}`
star.style.animationDelay = delay
star.style.animationDuration = delay
starWrap.appendChild(star)
}
}
function createRandom(){
let posX,posY,size,min = 0,max = 90
// 生成[10,90]的随机数
posX = Math.floor(Math.random()*(max-min+1)+min)+'%';
posY = Math.floor(Math.random()*(max-min+1)+min)+'%';
size = Math.floor(Math.random()*(30-5+1)+5)+'px'
delay = Math.floor(Math.random()*(10-1)+1)+'s'
return {posX,posY,size,delay}
}
-
火箭与海🚀🌊 说到中秋,我就想到了嫦娥,说到嫦娥,我就想到了嫦娥N号探月工程。但是我网上找不到合适的我们的运载火箭素材,就用了一张免费的素材图。“海上生明月” 算是这个动画的主旨吧,于是就又用了一张免费的海平面的素材,置于页面底部。这部分无非就是火箭起飞,加速,变小的过程,代码拉到最后看。
-
对联🧧 最初是没有这个元素的,但事后我觉得两边好像太空了,就加上了这个。气球素材网上找的,主要靠气球把对联给飞起来,至于底部的月饼,是我强行添加的【中秋元素】。对联主体
.content设置好宽高背景色之后,通过.content::before伪元素来设置对联内部的黄色边框。这里我是把文本内容写进伪元素的content里了,其实也是也可以写在外面的。关于文字竖排显示,我用了一种很笨的方法,就是当文字大小超过对联宽度的时候,它就会自动往下排,形成竖排列的效果,网上也有看到用writing-mode这个属性的。
结语
至此,所有的元素都写好了,只需要添加动画animation就好了。
小陈预祝看到这的和没看到这的各位,中秋节快乐,阖家幸福!🤞
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>中秋</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: rgb(37, 37, 37);
overflow: hidden;
}
.moon {
width: 30vw;
height: 30vw;
border-radius: 50%;
background: linear-gradient(#f1c40f,#f39c12);
box-shadow: 0px 0px 50px 5px #f39c12;
position: absolute;
right: 30%;
top: 10%;
animation: moon 5s forwards;
}
@keyframes moon {
from {
transform: translate3d(0,100%,0);
}
}
.airplane {
width: 100px;
height: 100px;
background-color: #000;
-webkit-mask-image: url(./image/airplane.png);
-webkit-mask-size: 100px 100px;
position: absolute;
right: 10%;
top: 20%;
animation: fly 5s ease-in-out forwards;
z-index: 5;
}
@keyframes fly {
to {
transform: translate3d(-30vw,0,0);
}
}
.star-wrap {
width: 100%;
height: 60%;
position: absolute;
top: 0;
z-index: -1;
}
.star {
position: absolute;
background-color: #f1c40f;
width: 20px;
height: 20px;
animation: star 3s linear infinite;
box-shadow: 0px 0px 20px 5px rgb(255 255 255 / 30%);
-webkit-mask-image: url(./image/star.png);
-webkit-mask-size: 20px 20px;
}
@keyframes star {
from {
opacity: 0;
}
50% {
opacity: 1;
}
to {
opacity: 0;
}
}
.rocket {
width: 100px;
height: 200px;
background: url(/image/rocket.png);
background-size: 100%;
position: absolute;
bottom: 0;
right: 30%;
animation: rocket 5s ease-in forwards;
z-index: 9;
}
@keyframes rocket {
to {
transform: translate3d(0,-80vh,0) scale(.2);
}
}
.sea {
width: 100%;
height: 50%;
position: absolute;
bottom: 0;
background: url(/image/sea.png) no-repeat;
background-size: 100%;
z-index: 0;
}
.couplet-wrap {
width: 90%;
height: 90vh;
background-color: transparent;
z-index: 10;
display: flex;
justify-content: space-between;
animation: couplet 2s ease 5s backwards;
}
@keyframes couplet {
from {
transform: translate3d(0,120%,0);
}
to {
transform: translate3d(0,0,0);
}
}
.couplet {
width: 150px;
display: flex;
flex-direction: column;
align-items: center;
}
.balloon {
width: 100%;
height: 120px;
background: url(/image/balloon.png) no-repeat center;
background-size: contain;
}
.content {
background-color: #c0392b;
flex: 1;
width: 100%;
position: relative;
}
.content::before {
content: "海上生明月";
position: absolute;
width: 80%;
height: 90%;
border: 5px solid #f1c40f;
left: 50%;
top: 50%;
transform: translate3d(-50%,-50%,0);
text-align: center;
font: 70px '宋体';
line-height: 90px;
color: rgb(44, 44, 44);
}
#content2::before {
content: "天涯共此时";
}
.content::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
width: 5px;
height: 50px;
background-color: #c0392b;
border-left: 2px dashed #f1c40f;
border-right: 2px dashed #f1c40f;
box-sizing: border-box;
}
.mooncake {
width: 100%;
height: 80px;
margin-top: 30px;
background: url(/image/mooncake.png) no-repeat center;
background-size: contain;
z-index: 10;
}
</style>
</head>
<body>
<!-- 图片资源就自己找吧~ -->
<div class="moon"></div>
<div class="airplane"></div>
<div class="star-wrap"></div>
<div class="rocket"></div>
<div class="sea"></div>
<div class="couplet-wrap">
<div class="couplet">
<div class="balloon"></div>
<div class="content"></div>
<div class="mooncake"></div>
</div>
<div class="couplet">
<div class="balloon"></div>
<div class="content" id="content2"></div>
<div class="mooncake"></div>
</div>
</div>
<script>
window.onload = function(){
let starWrap = document.querySelector('.star-wrap')
for(let i=0;i<50;i++){
let star = document.createElement('div')
let {posX,posY,size,delay} = createRandom()
star.className = "star"
star.style.left = posX
star.style.top = posY
star.style.width = star.style.height = size
star.style.webkitMaskSize = `${size} ${size}`
star.style.animationDelay = delay
star.style.animationDuration = delay
starWrap.appendChild(star)
}
}
function createRandom(){
let posX,posY,size,min = 0,max = 90
// 生成[10,90]的随机数
posX = Math.floor(Math.random()*(max-min+1)+min)+'%';
posY = Math.floor(Math.random()*(max-min+1)+min)+'%';
size = Math.floor(Math.random()*(30-5+1)+5)+'px'
delay = Math.floor(Math.random()*(10-1)+1)+'s'
return {posX,posY,size,delay}
}
</script>
</body>
</html>