我正在参加中秋创意投稿大赛,详情请看:中秋创意投稿大赛
大家好,我是寒草🌿,一只草系码猿🐒。间歇性热血🔥,持续性沙雕🌟
如果喜欢我的文章,可以关注➕点赞,为我注入能量,与我一同成长吧~
工程师 · 中秋节🎑
雷猴啊,我是寒草~本来之前的文章说了我最近比较忙,一堆事情要做,而且也在准备我的一个几万字长篇文章,导致最近没有什么时间。但是,我前几天看到了掘金在搞一个活动,就是中秋创意投稿大赛
,我这一看,喔~怪好玩的,于是打算起早贪黑筹备一下。
正好,我在掘金写文半年多了,也趁这个机会给大家送一个中秋节礼物。还是我的老套路嘛,这篇文章你可以看到:
- 我是如何思考并设计一个中秋节礼物滴🥮
- 我和大家一起将这个设计实现出来🌟
以及,我挤出时间来做这个动画,初衷希望大家都可以开心过中秋,主要分享这份礼物🎁的设计和实现,甚至为了搞本文中的gif我还花了30块钱买了个软件,呜呜呜,大家要不心疼寒草🌿一下,给我一个赞,一个评论,一个关注来作为给我的中秋礼物?嘿嘿嘿~
小寒草在这里提前祝各位读者以及作者朋友中秋节快乐啦🎆,biubiubiu~
浪漫又蹩脚的设计之路📖
那么!第一个问题就来了,我该如何设计我给大家的中秋礼物捏,还是像往常一样,我要列出我想要展现的要素:
- 月亮(废话,中秋肯定要有月亮呀,听君一席话,就是一席话)
- 星空:皎洁的月色需要星空点缀
- 诗歌:中秋节是一个中华传统节日,并且无数文人墨客在中秋创作诗词歌赋,我要用诗歌元素让我的作品包含中华文化
这几个要素是必选的,但是感觉形成一个动画的要素要需要更多,而且需要更多细节,比如:
- 星空怎么展现?
- 诗歌与作品怎么结合?
关于更多要素我想到了,不妨在我这个作品里体现日落到月亮升起的过程,来一个“一镜到底”的动画。
而细节如何设计,请容我卖个关子~毕竟,我要留有悬念~
落地设计,逃不开的编码之路💻
现在我已经有了一个初步的构想了,下面就是如何去实现出来,那么这一章就请大家跟随我一步一步把这个动画的内容充实起来吧🌟
请给位读者耐心看完~
诶,终究是逃不开写代码呀,寒草,你跑不掉滴~
日落月升🌛
这里我的动画希望采用的是那种简约派的画风,第一是好做(我好耿直。。。),第二是感觉这个画风类似于之前剪纸之类的风格,简约的日落,圆月升起之中似乎带着一点点的中国风。
这个环节全都是采用css的帧动画实现,主要麻烦的地方是:
调色!调色!调色!还是调色!鬼知道没有ui和产品的情况下,我自己挑颜色花了多长时间,我需要让天空,太阳,月亮,山峦的颜色达成一个一致性:
- 正午:天空蓝色,太阳金黄色,山峦绿油油的~
- 傍晚:天空逐渐变成金色,太阳逐渐变红,山峦也逐渐变暗~
- 日落:天空被落日染成红色,太阳也是变得通红,山峦也被染成深红色~
- 月升:天空变成墨色,月亮是金色的,山峦要变成墨绿色~
所以说,艺术也是需要现实的观察的,哈哈哈,我不是说自己做的东西是艺术,只是简单去做一个效果都要做日常观察,有感而发~
所以下面给大家看一下代码实现:
//css
* {
padding: 0px;
margin: 0px;
}
@keyframes nightfall {
from {
background: #9dc1df;
}
16% {
background: #416cc9;
}
32% {
background: #e58732;
}
50% {
background: #e55327;
}
to {
background: #2a2d38;
}
}
.container {
width: 100vw;
height: 100vh;
transition: all ease;
animation: nightfall 8s;
background: #2a2d38;
overflow: hidden;
}
@keyframes sunfallmoonrise {
from {
background: #ffffff;
top: 10vh;
}
16% {
background: #ffff54;
}
32% {
background: #e63724;
}
50% {
background: #e93324;
top: 80vh;
}
to {
background: #f9dc60;
top: 10vh;
}
}
.sun-and-moon {
width: 200px;
height: 200px;
animation: sunfallmoonrise 8s;
border-radius: 50%;
position: absolute;
left: 20vw;
top: 10vh;
background: #f9dc60;
box-shadow: 0px 0px 20px #f9dc60;
transition: all 3s ease;
z-index: 10;
;
}
@keyframes mountain {
from {
background: rgb(25, 175, 75);
}
16% {
background: rgb(168, 192, 35);
}
32% {
background: rgb(199, 106, 31);
}
50% {
background: rgb(167, 66, 26);
}
to {
background: rgb(56, 56, 27);
}
}
.mountain-common {
position: absolute;
z-index: 999;
border-radius: 50%;
background: rgb(56, 56, 27);
animation: mountain 8s;
}
.mountain-a {
width: 80vw;
height: 400px;
top: 80vh;
left: -20vw;
}
.mountain-b {
width: 100vw;
height: 800px;
top: 65vh;
left: 40vw;
}
// Dom
<div class="container">
<div class="sun-and-moon"></div>
<div class="mountain-common mountain-a"></div>
<div class="mountain-common mountain-b"></div>
</div>
镜头对月色的追随💓
下一步我想的就是,镜头已经记录了太阳落下到月亮升起的过程,下面我们拉近镜头,去更近距离的观察月亮,所以我们要营造一个镜头拉近的效果:
- 月亮放大并到镜头的偏中心的位置
- 山峦也会跟随像右侧移动,并逐渐消失在镜头里
// css
@keyframes moon-bigger {
from {
width: 200px;
height: 200px;
left: 20vw;
top: 10vh;
}
to {
width: 600px;
height: 600px;
top: calc(50vh - 300px);
left: calc(40vw - 300px);
}
}
@keyframes mountain-down-a {
from {
top: 80vh;
left: -20vw;
}
to {
top: 115vh;
left: -300px;
opacity: 0.6;
}
}
@keyframes mountain-down-b {
from {
top: 65vh;
left: 40vw;
}
to {
top: 100vh;
left: calc(60vw - 300px);
opacity: 0.6;
}
}
// Dom,暂时还是之前的Dom
<div class="container">
<div class="sun-and-moon"></div>
<div class="mountain-common mountain-a"></div>
<div class="mountain-common mountain-b"></div>
</div>
但是这次有了js, 因为之前的动画时长是8s,所以我这里设置了9s的定时器去触发月亮变大,山峦消失的效果。
const timerA = setTimeout(() => {
clearTimeout(timerA);
const moon = document.getElementsByClassName('sun-and-moon')[0];
moon.style.animation = 'moon-bigger 5s';
moon.style.width = '600px';
moon.style.height = '600px';
moon.style.top = 'calc( 50vh - 300px )';
moon.style.left = 'calc( 40vw - 300px )';
const mountainList = document.getElementsByClassName('mountain-common');
mountainList[0].style.animation = 'mountain-down-a 5s';
mountainList[0].style.top = '100vh';
mountainList[1].style.animation = 'mountain-down-b 5s';
mountainList[1].style.top = '100vh';
}, 9000);
将银河撒向夜空🌃
接下来我要让星空浮现,因为我想星星也不是一下子全出来的,而是渐渐浮现出来的,所以要随机的时间点来产生星星✨,并让他有闪烁的效果。
// css,星星闪烁的效果
@keyframes star-scale {
from {
transform: scale(1, 1);
}
25% {
transform: scale(0.1, 0.1);
}
50% {
transform: scale(1, 1);
}
25% {
transform: scale(2, 2);
}
to {
transform: scale(1, 1);
}
}
.star {
height: 3px;
width: 3px;
background-color: #f9dc60;
border-radius: 50%;
position: absolute;
animation: star-scale 2s;
animation-iteration-count: infinite;
}
// js 随机时间随机位置,产出星星
const arr = new Array(60);
for (const item of arr) {
const dom = document.createElement('div');
dom.className = 'star';
dom.style.left = `${Math.random() * 100}vw`;
dom.style.top = `${Math.random() * 100}vh`;
setTimeout(() => {
document.body.appendChild(dom);
}, 15000 * Math.random());
}
但愿人长久 · 千里共婵娟🎋
之后就是那一句诗句了:
“但愿人长久,千里共婵娟”
我是如何让他一点一点像是用笔写出来的呢?其实我在我生日文里面也用了这个库用技术创造惊喜|成熟的前端工程师一定要学会亲手制作生日礼物 🎁,只不过:
- 上次是生日礼物,这次是中秋礼物
- 上次是送给我自己,这次是送给你们
嘿嘿嘿,感动不~这个库是 hanzi-writer, 大家可以去看一看这个文档docs,感觉除了可以用来练习书法,也可以做很多效果~
<div class="poetry-top poetry">
<div id="dan"></div>
<div id="yuan"></div>
<div id="ren"></div>
<div id="chang"></div>
<div id="jiu"></div>
</div>
<div class="poetry-down poetry">
<div id="qian"></div>
<div id="li"></div>
<div id="gong"></div>
<div id="chan"></div>
<div id="juan"></div>
</div>
.poetry div {
width: 60px;
height: 60px;
margin-top: 6px;
}
.poetry-top {
position: absolute;
top: 20vh;
right: 48px;
}
.poetry-down {
position: absolute;
top: 30vh;
right: 130px;
}
const BASE_CONFIG = {
width: 60,
height: 60,
padding: 2,
delayBetweenStrokes: 0,
strokeAnimationSpeed: 2,
showCharacter: false,
showOutline: false,
}
const WRITER_CONFIG = {
...BASE_CONFIG,
strokeColor: '#f9dc60'
};
const getWriterList = () => {
let writerList = [];
writerList.push(HanziWriter.create('dan', '但', WRITER_CONFIG));
writerList.push(HanziWriter.create('yuan', '愿', WRITER_CONFIG));
writerList.push(HanziWriter.create('ren', '人', WRITER_CONFIG));
writerList.push(HanziWriter.create('chang', '长', WRITER_CONFIG));
writerList.push(HanziWriter.create('jiu', '久', WRITER_CONFIG));
writerList.push(HanziWriter.create('qian', '千', WRITER_CONFIG));
writerList.push(HanziWriter.create('li', '里', WRITER_CONFIG));
writerList.push(HanziWriter.create('gong', '共', WRITER_CONFIG));
writerList.push(HanziWriter.create('chan', '婵', WRITER_CONFIG));
writerList.push(HanziWriter.create('juan', '娟', WRITER_CONFIG));
return writerList;
}
const generateAnimateWriter = async (writerList) => {
const writerCount = writerList.length;
for (const writer of writerList) {
await writer.animateCharacter();
}
}
generateAnimateWriter(getWriterList());
将诗歌献给皎洁的月🎵
动态gif:
静态细节(注意中间写着寒草呈献):
考虑作品立意时彰显中华传统诗词文化的宗旨,我有个想法,就是去搜寻更多有关中秋的诗歌,并把他们印在月亮上,这里我用了两个手段:
- 透明度渐变
- 词云图
把月亮中心的透明度降低,让藏在后面的诗词显示出来。
// css
#word-cloud__container {
width: 600px;
height: 600px;
top: calc(50vh - 300px);
left: calc(40vw - 300px);
position: absolute;
transition: all 2s;
border-radius: 50%;
overflow: hidden;
opacity: 0.6;
z-index: 1;
}
// dom 词云图
<div id="word-cloud__container"></div>
// 词云图数据处理和展示
const poetryList = [
'明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间。转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。',
'西风来劝凉云去,天东放开金镜。照野霜凝,入河桂湿,一一冰壶相映。殊方路永。更分破秋光,尽成悲境。有客踌躇,古庭空自吊孤影。江南朋旧在许,也能怜天际,诗思谁领。梦断刀头,书开虿尾,别有相思随定。忧心耿耿。对风鹊残枝,露_荒井。斟酌嫦娥,九秋宫殿冷。',
'琼楼玉宇。分明不受人间暑。寻常岂是无三五。惟有今宵,皓彩皆同普。素娥阅尽今和古。何妨小驻听吾语。当年弄影婆娑舞。妙曲虽传,毕竟人何许。',
'快上西楼,怕天放、浮云遮月。但唤取、玉纤横笛,一声吹裂。谁做冰壶浮世界,最怜玉斧修时节。问常娥、孤冷有愁无。应华发。云液满,琼杯滑。长袖起,清歌咽。叹十常八九,欲磨还缺。若得长圆如此夜,人情未必看承别。把从前、离恨总成欢,归时说。',
'碧天如水,一洗秋容净。何处飞来大明镜。谁道斫却桂,应更光辉,无遗照,泻出山河倒影。人犹苦余热,肺腑生尘,移我超然到三境。问姮娥、缘底事,乃有盈亏,烦玉斧、运风重整。教夜夜、人世十分圆,待拚却长年,醉了还醒。',
'海上生明月,天涯共此时。情人怨遥夜,竟夕起相思。灭烛怜光满,披衣觉露滋。不堪盈手赠,还寝梦佳期。',
'一轮飞镜谁磨?照彻乾坤,印透山河。玉露泠泠,洗秋空银汉无波,比常夜清光更多,尽无碍桂影婆娑。老子高歌,为问嫦娥,良夜恹恹,不醉如何?',
'碧海年年,试问取、冰轮为谁圆缺?吹到一片秋香,清辉了如雪。愁中看、好天良夜,知道尽成悲咽。只影而今,那堪重对,旧时明月。花径里、戏捉迷藏,曾惹下萧萧井梧叶。记否轻纨小扇,又几番凉热,。只落得,填膺百感,总茫茫、不关离别。一任紫玉无情,夜寒吹裂。',
'青烟幂处,碧海飞金镜。永夜闲阶卧桂影。露凉时、零乱多少寒螀,神京远,惟有蓝桥路近。水晶帘不下,云母屏开,冷浸佳人淡脂粉。待都将许多明,付与金尊,投晓共、流霞倾尽。更携取、胡床上南楼,看玉做人间,素秋千顷。',
'砧声送风急,蟠蟀思高秋。我来对景,不学宋玉解悲愁。收拾凄凉兴况,分付尊中醽醁,倍觉不胜幽。自有多情处,明月挂南楼。怅襟怀,横玉笛,韵悠悠。清时良夜,借我此地倒金瓯。可爱一天风物,遍倚阑干十二,宇宙若萍浮。醉困不知醒,欹枕卧江流。',
'凭高眺远,见长空万里,云无留迹。桂魄飞来光射处,冷浸一天秋碧。玉宇琼楼,乘鸾来去,人在清凉国。江山如画,望中烟树历历。我醉拍手狂歌,举怀邀月,对影成三客。起舞徘徊风露下,今夕不知何夕。便欲乘风,翻然归去,何用骑鹏翼。水晶宫里,一声吹断横笛。',
'桂花浮玉,正月满天街,夜凉如洗。风泛须眉并骨寒,人在水晶宫里。蛟龙偃蹇,观阙嵯峨,缥缈笙歌沸。霜华满地,欲跨彩云飞起。记得去年今夕,酾酒溪亭,淡月云来去。千里江山昨梦非,转眼秋光如许。青雀西来,嫦娥报我,道佳期近矣。寄言俦侣,莫负广寒沈醉',
'满月飞明镜,归心折大刀。转蓬行地远,攀桂仰天高。水路疑霜雪,林栖见羽毛。此时瞻白兔,直欲数秋毫。稍下巫山峡,犹衔白帝城。气沈全浦暗,轮仄半楼明。刁斗皆催晓,蟾蜍且自倾。张弓倚残魄,不独汉家营。',
'世事一场大梦,人生几度秋凉。夜来风叶已鸣廊。看取眉头鬓上。酒贱常愁客少,月明多被云妨。中秋谁与共孤光。把盏凄然北望。',
'中秋佳月最端圆。老痴顽。见多番。杯酒相延,今夕不应慳。残雨如何妨乐事,声淅淅,点斑斑。天应有意故遮阑。拍人间。等闲看。好处时光,须用著些难。直待黄昏风卷霁,金滟滟,玉团团。',
'丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。明月几时有?把酒问青天。不知天上宫阙,今夕是何年。我欲乘风归去,又恐琼楼玉宇,高处不胜寒。起舞弄清影,何似在人间。转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。',
];
const reg = new RegExp(',|?|。');
let chartList = [];
for(const poetry of poetryList) {
const sentenceList = poetry.split(reg).filter(item => item);
chartList.push(...sentenceList);
}
chartList = chartList.map(item => ({
name: item,
value: Math.random() * 400
}));
chartList.push({
name: '寒草呈献',
value: 1000
})
var chart = echarts.init(document.getElementById('word-cloud__container'));
chart.setOption({
series: [
{
type: "wordCloud",
left: "center",
top: "center",
width: "100%",
height: "100%",
right: null,
bottom: null,
sizeRange: [4, 30],
rotationRange: [0, 0],
rotationStep: 10,
gridSize: 1,
drawOutOfBound: false,
layoutAnimation: true,
textStyle: {
fontFamily: "sans-serif",
fontWeight: "bold",
color: '#f9dc60'
},
emphasis: {
focus: "self",
textStyle: {
shadowBlur: 10,
shadowColor: "#333",
},
},
data: chartList
},
],
});
const timerD = setTimeout(() => {
clearTimeout(timerD);
// moon.style.opacity = 0.9;
moon.style.background = "radial-gradient(rgba(249, 220, 96, 0.9), rgba(249, 220, 96, 1))"
//radial-gradient
}, 1000);
走,与我见家长🌟
设计与编码完成肯定需要拉出来溜溜的,所以经过我上面一通说,也到了给大家看看全貌的时候了,但是由于现在掘金不支持放视频,并且动画过长有36s的长度,转成gif确只有2s,导致速度很快,大家看到的体验可能不是很好,但是相信我,实际运行一下,效果还是很棒的~
仓库地址:mid-autumn-festival-juejin
结束语 · 举杯邀月饮🥤
下面就来到了结束语,寒草就是最喜欢写结束语,因为在这里我喜欢写一些有的没的,可以放松自由的表达~
首先,在这里提前祝大家中秋节快乐,在此中华传统节日,我也在这里为大家赋诗一首:
鹅,鹅,鹅
曲项向天歌
...
呸呸呸,才不是这首,但是我还是需要咏个鹅🦢,大鹅的鹅叫简直是天籁(我看来哈,只是我看来哈),这篇文章的代码也是在大鹅的叫声(歌声)中完成的,我每听到一首都感觉:“这首歌很耳熟”,我现在知道了,不管大鹅唱的是什么,名字就叫:
《曲项向天歌》
诶呀,我感觉我再去皮就可能发生恶性的大鹅打狗事件:
算了,那我不咏鹅了,在中秋前夕祝大鹅这么快乐的人「诶?大鹅这么快乐的。。。人?大鹅是人?」一直做一只快快乐乐,肥美好吃的大鹅。
下面才是本文的正题:
中秋快乐🥮
月圆之后,我们再会🌟
看在中秋礼物份上,点个赞吧👍
看在中秋礼物份上,点个关注吧➕
看在中秋礼物份上,整个评论吧📖
tip:最近关注到500会在交流群里送书哦~
加我微信:hancao97,邀你进群,了解寒草🌿 的github小组现状,一起学习前端,成为更优秀的工程师~(群二维码在这里->前端晚晚睡, 二维码过期了的话看链接沸点中的评论,我会把最新的二维码放在评论区,当然也可以加我微信我拉你进群,毕竟我也是有趣的前端,认识我也不赖🌟~)