「寒草的中秋献礼🥮,实现30s前端创意动画」陪你看日落和月升|与你赏星空和诗歌

简介: 「寒草的中秋献礼🥮,实现30s前端创意动画」陪你看日落和月升|与你赏星空和诗歌

浪漫又蹩脚的设计之路📖


那么!第一个问题就来了,我该如何设计我给大家的中秋礼物捏,还是像往常一样,我要列出我想要展现的要素:


  • 月亮(废话,中秋肯定要有月亮呀,听君一席话,就是一席话
  • 星空:皎洁的月色需要星空点缀
  • 诗歌:中秋节是一个中华传统节日,并且无数文人墨客在中秋创作诗词歌赋,我要用诗歌元素让我的作品包含中华文化


这几个要素是必选的,但是感觉形成一个动画的要素要需要更多,而且需要更多细节,比如:


  • 星空怎么展现
  • 诗歌与作品怎么结合


关于更多要素我想到了,不妨在我这个作品里体现日落到月亮升起的过程,来一个“一镜到底”的动画。


而细节如何设计,请容我卖个关子~毕竟,我要留有悬念~


落地设计,逃不开的编码之路💻


网络异常,图片无法展示
|


现在我已经有了一个初步的构想了,下面就是如何去实现出来,那么这一章就请大家跟随我一步一步把这个动画的内容充实起来吧🌟


请给位读者耐心看完~


诶,终究是逃不开写代码呀,寒草,你跑不掉滴~


日落月升🌛

网络异常,图片无法展示
|


这里我的动画希望采用的是那种简约派的画风,第一是好做(我好耿直。。。),第二是感觉这个画风类似于之前剪纸之类的风格,简约的日落,圆月升起之中似乎带着一点点的中国风。


这个环节全都是采用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

网络异常,图片无法展示
|


结束语 · 举杯邀月饮🥤


网络异常,图片无法展示
|


下面就来到了结束语,寒草就是最喜欢写结束语,因为在这里我喜欢写一些有的没的,可以放松自由的表达~

相关文章
|
6月前
|
前端开发 JavaScript iOS开发
精选11款炫酷的前端动画特效分享(附在线演示)
分享11款非常不错炫酷的前端特效源码 其中包含css动画特效、js原生特效、svg特效等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源
|
6月前
|
前端开发 JavaScript
前端必看的8个HTML+CSS技巧 (六) 裁剪图像的动画
前端必看的8个HTML+CSS技巧 (六) 裁剪图像的动画
|
4天前
|
前端开发 JavaScript API
前端开发的秘密武器:这些工具让你轻松应对各种复杂动画效果!
【10月更文挑战第30天】前端开发中,动画效果为页面增添了无限生机。CSS3的@keyframes规则和JavaScript动画库如GSAP、Anime.js等,使开发者能轻松实现从简单到复杂的动画效果。掌握动画原理和设计原则,结合工具和库,可以创造出既美观又实用的动画,提升用户体验。
17 4
|
6月前
|
JSON 前端开发 JavaScript
前端使用lottie-web,使用AE导出的JSON动画贴心教程
前端使用lottie-web,使用AE导出的JSON动画贴心教程
589 2
|
3月前
|
iOS开发 Android开发 MacOS
从零到全能开发者:解锁Uno Platform,一键跨越多平台应用开发的神奇之旅,让你的代码飞遍Windows、iOS、Android、macOS及Web,技术小白也能秒变跨平台大神!
【8月更文挑战第31天】从零开始,踏上使用Uno Platform开发跨平台应用的旅程。只需编写一次代码,即可轻松部署到Windows、iOS、macOS、Android及Web(通过WASM)等多个平台。Uno Platform为.NET生态带来前所未有的灵活性和效率,简化跨平台开发。首先确保安装了Visual Studio或VS Code及.NET SDK,然后选择合适的项目模板创建新项目。项目结构类似传统.NET MAUI或WPF项目,包含核心NuGet包。通过简单的按钮示例,你可以快速上手并构建应用。Uno Platform让你的技术探索之旅充满无限可能。
62 0
|
4月前
|
前端开发 JavaScript API
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(下)
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(下)
48 0
|
4月前
|
监控 JavaScript 前端开发
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(上)
只会用插件可不行,这些前端动画技术同样值得收藏-JavaScript篇(上)
50 0
|
4月前
|
前端开发 JavaScript UED
只会用插件可不行,这些前端动画技术同样值得收藏-CSS篇
只会用插件可不行,这些前端动画技术同样值得收藏-CSS篇
93 0
|
4月前
|
前端开发 JavaScript
前端 JS 经典:数字变化动画
前端 JS 经典:数字变化动画
59 0
|
4月前
|
前端开发 API 开发者
前端 CSS 经典:边框转圈动画效果
前端 CSS 经典:边框转圈动画效果
171 0