「寒草的中秋献礼🥮,实现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

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


结束语 · 举杯邀月饮🥤


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


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

相关文章
|
3月前
|
前端开发 JavaScript
前端必看的8个HTML+CSS技巧 (六) 裁剪图像的动画
前端必看的8个HTML+CSS技巧 (六) 裁剪图像的动画
|
4月前
|
前端开发 JavaScript iOS开发
精选11款炫酷的前端动画特效分享(附在线演示)
分享11款非常不错炫酷的前端特效源码 其中包含css动画特效、js原生特效、svg特效等 下面我会给出特效样式图或演示效果图 但你也可以点击在线预览查看源码的最终展示效果及下载源码资源
|
1月前
|
前端开发 JavaScript UED
前端开发的魔法:CSS动画与JavaScript的完美结合
本文将探讨如何利用CSS动画和JavaScript的结合,为前端页面增添生动的效果。我们将通过实例展示如何使用这两种技术为网页元素创建吸引人的动画效果,并讨论它们的优缺点和适用场景。
29 0
|
2月前
|
前端开发 JavaScript API
前端开发中的动画效果优化技巧
在前端开发中,动画效果是提升用户体验的重要手段之一。本文将介绍一些优化动画效果的技巧,帮助开发者提升网页性能和用户体验。
|
4月前
|
前端开发 容器
【零基础入门前端系列】—动画和弹性盒模型(二十四)
【零基础入门前端系列】—动画和弹性盒模型(二十四)
|
5月前
|
移动开发 前端开发 JavaScript
前端开发中web和移动端动画的常见实现方式
前端动画一般在展示性网站、交互操作或者移动端活动页面使用比较多,可能对于大部分前端平时只会用 css 里的 transition 动画,其实前端动画还有很多实现方式
87 0
|
6月前
|
前端开发 数据可视化 定位技术
GIS前端-地图标绘与动画
GIS前端-地图标绘与动画
77 0
|
6月前
|
JavaScript 前端开发 程序员
|
8月前
|
前端开发 JavaScript
前端动画(动态)图标库收集
前端动画(动态)图标库收集
99 0
|
8月前
|
前端开发 JavaScript
前端(CSS3、JS)动画库收集
前端(CSS3、JS)动画库收集
82 0