先来看看效果吧
事实上左上角这个位置还有一个图标,它可以用来控制音乐的开关以及点一下音乐图标会变成×
那么眼前这个荡秋千的小帅是如何实现的呢?让我们开动脑筋来想一想。
思路:
- 众所周知,打开这个页面会有音乐,因此需要一个audio标签
- 其次左上角有个控制开关,因此可以放一个div盒子,这里类名我们叫做:music-btn和off(多类名)
<audio src="./assets/bgm.mp3" id="j-bgm"></audio>
<div class="music-btn off"></div>
- 这个小图标永远都在这里,既如此我们不妨直接固定定位把他确定在这个位置
- z-index,设置层级,它需要永远定在这,不能让别人的层级大于他,默认层级为0,因此我们只需要将他设置为大于0的任意值就可以了,这里我们直接设置为999
.music-btn {
position: fixed;
top: 25px;
left: 25px;
width: 40px;
height: 40px;
background: url(./assets/close.png);
background-size: cover;
z-index: 999;
}
- 为什么写成多类名的形式?因为这里点击一下会变成×,需要准备两张照片,一开始我们让他显示音乐图标,点击之后变成×。
.music-btn.off {
background-image: url(./assets/music.png);
}
- 可以看到由于优先级的关系,这里先显示音乐图标,它同时选中两个类名选择器,上面那个只有一个,权重更大。
说到这个地方,先补充一个小知识点
.music-btn.off和.music-btn .off有什么区别?
- 前者是选中同时具备这两个类名的标签,而后者是前后代的关系。
接下来继续思考准备工作
可以看见,中间有一个大太阳,因此我们接着搭框架
-用一个类名为view的div存放类名为sun的div、类名为art的div(秋千)、以及类名为paras的div用于存放文字,那么至此,整个html的框架部分就出来了,当然这里的(art)div中还需要存放秋千部分,并且它包含着腿1(包含脚)、腿2(包含脚)、脖子、头。
<audio src="./assets/bgm.mp3" id="j-bgm"></audio>
<div class="music-btn off"></div>
<div class="view">
<div class="sun"></div>
<!-- 秋千 -->
<div class="art">
<div class="swing">
<div class="leg2">
<div class="jiojio"></div>
</div>
<!-- neck -->
<div class="neck"></div>
<!-- head -->
<div class="head">
<div class="part"></div>
</div>
<div class="leg1">
<div class="jiojio"></div>
</div>
</div>
</div>
<!-- 特殊内容 -->
<div class="paras">
<p class="para f-animLineUp" style="transition-delay: 0.2s;">
<em class="s-fcRed">11月11日</em>
</p>
<p class="para f-animLineUp" style="transition-delay: 0.3s;">
大概是很特别的一天
</p>
<p class="para f-animLineUp" style="transition-delay: 0.4s;">
这一天里
</p>
<p class="para f-animLineUp" style="transition-delay: 0.5s;">
你把郑源的
<em class="s-fcRed">《被伤过的心还可以爱谁》</em>
</p>
<p class="para f-animLineUp" style="transition-delay: 0.6s;">
反复听了
<em class="s-fcRed">10次</em>
</p>
</div>
</div>
搭建完成,渲染框架(CSS)
- html与body标签继承屏幕的宽高100%,view标签便继承body的宽高百分百
- 设置超出则隐藏
overflow: hidden;
- 设置好相对定位,后续要基于view标签做定位
- 可以看见这个背景是一个渐变色
linear-gradient
- 太阳基于view做定位因此太阳做一个绝对定位,当然图片大小要设置为覆盖整个容器,不然图片就不全了
background-size: cover;
那么这种动画效果到底是如何实现的呢?
- 自定义动画:@keyframes name{}
- 调用:animation: name time way xxx
- 具体如下:动画中可以自己设置,在百分之0的时候旋转多少,百分之25的时候旋转多少,数据越细腻,动画就越丝滑。
.swing {
position: absolute;
left: 226px;
top: -180px;
width: 478px;
height: 1038px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/swing.88545d6c8e1ac798465e367f8e5357ab.png);
transform-origin: -16% -30%;
animation: ani_qiuqian 6s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
}
@keyframes ani_qiuqian {
0% {
transform: rotateZ(0deg);
}
50% {
transform: rotateZ(32deg);
}
100% {
transform: rotateZ(0deg);
}
}
- 其他的部分也大致相同,附带代码:
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
.music-btn {
position: fixed;
top: 25px;
left: 25px;
width: 40px;
height: 40px;
background: url(./assets/close.png);
background-size: cover;
z-index: 999;
}
.music-btn.off {
background-image: url(./assets/music.png);
}
.view {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
background-image: linear-gradient(60deg, #f8ddd1, #faece5 73%, #fad2c0);
}
.sun {
position: absolute;
top: 45%;
left: 50%;
width: 283px;
height: 283px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/sun.a3f575ae2fef2cfdae15011e6081a094.png);
background-size: cover;
transform: translate(-50%, -50%);
}
.art {
position: absolute;
top: -140px;
right: 0;
width: 375px;
height: 667px;
transform: scale(0.5);
transform-origin: top right;
}
.swing {
position: absolute;
left: 226px;
top: -180px;
width: 478px;
height: 1038px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/swing.88545d6c8e1ac798465e367f8e5357ab.png);
transform-origin: -16% -30%;
animation: ani_qiuqian 6s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
}
@keyframes ani_qiuqian {
0% {
transform: rotateZ(0deg);
}
50% {
transform: rotateZ(32deg);
}
100% {
transform: rotateZ(0deg);
}
}
.leg2 {
position: absolute;
left: 185.375px;
top: 958px;
width: 130px;
height: 32px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/leg2.d7bc44a91b6974450f2ccc430846c63d.png);
transform-origin: 91.15% 33.59%;
animation: ani_leg2 8s ease infinite;
}
@keyframes ani_leg2 {
0% {
transform: rotateZ(0deg);
}
25% {
transform: rotateZ(-87deg);
}
50% {
transform: rotateZ(0deg);
}
75% {
transform: rotateZ(-87deg);
}
100% {
transform: rotateZ(0deg);
}
}
.leg2 .jiojio {
position: absolute;
width: 57px;
height: 44px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/leg2-part.8f70bb7fc789a70bc78c48aa7718a765.png);
left: -27.75px;
top: -10.5px;
}
.leg1 {
position: absolute;
left: 290.375px;
top: 955.25px;
width: 63px;
height: 130px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/leg1.b1df6a7d1a794d36fbd0e1277733e1cf.png);
transform-origin: 17.857% 13.365%;
animation: ani_leg1 8s ease infinite;
}
@keyframes ani_leg1 {
0% {
transform: rotateZ(0deg);
}
25% {
transform: rotateZ(109deg);
}
50% {
transform: rotateZ(0deg);
}
75% {
transform: rotateZ(109deg);
}
100% {
transform: rotateZ(0deg);
}
}
.leg1 .jiojio {
position: absolute;
width: 39px;
height: 62px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/leg1-part.f2f17703a6af8fd2af5e0f5a9f320623.png);
left: 26.25px;
top: 102.5px;
}
.swing .neck {
position: absolute;
left: 451.125px;
top: 855.5px;
width: 51px;
height: 42px;
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/neck.07a0013beff9796ed79c2cea542e5af2.png) no-repeat;
}
/* 头 */
.swing .neck,
.swing .head {
display: block;
position: absolute;
left: 451.125px;
top: 855.5px;
width: 51px;
height: 42px;
}
/* 脖子 */
.swing .neck {
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/neck.07a0013beff9796ed79c2cea542e5af2.png) no-repeat;
}
/* 头 */
.swing .head {
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/head.90bf892023d7df0522a4b53fc07e38df.png) no-repeat;
animation: ani2_head 8s ease infinite;
}
/* 头发 */
.swing .head .part {
background: url(https://s5.music.126.net/static_public/5c21db8d4684556c72180904/head-part.22d4381c4bd6cb1c3afd2b1bfcfe22f1.png) no-repeat;
left: 20px;
top: 2px;
width: 40px;
height: 47px;
position: absolute;
}
@keyframes ani2_head {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(-55deg);
}
62.5% {
transform: rotate(-55deg);
}
87.92% {
transform: rotate(0deg);
}
100% {
transform: rotate(0deg);
}
}
/* 特殊的内容 */
.paras {
bottom: 110px;
left: 10.67%;
position: absolute;
line-height: 1.6667;
letter-spacing: 1px;
color: #333;
}
.s-fcRed {
color: #df493a;
}
.z-enter .f-animLineUp {
opacity: 1;
transform: translateY(0);
transition: opacity 1.2s, transform 1s;
}
.f-animLineUp {
opacity: 0;
transform: translateY(6px);
}
em,
i {
font-style: normal;
text-align: left;
}
最后js部分,实现点击音乐图标变为×,以及音乐的播放与暂停。思路如下:
- 设置状态变量,默认状态为true,点击以后变为false
- play、pause控制播放与暂停
- 图标的转换:前面我们用了一个单类名和多类名选择器插入背景图的方式,这里我们只需要删除掉那个多类名选择器就可以变换图片了classList.add\classList.remove
<script>
//播放音乐
var viewSpecial = document.querySelector('.view .paras');
var musicBtn = document.querySelector('.music-btn');
var bgMusic = document.getElementById('j-bgm');
var defaultMusicPlay = true;
musicBtn.addEventListener('click', function () {
if (defaultMusicPlay) {
bgMusic.play();
// musicBtn.classList.remove('off');
} else {
bgMusic.pause();
// musicBtn.classList.add('off');
}
musicBtn.classList.toggle('off');//如果有自动移除;如果没有自动添加
defaultMusicPlay = !defaultMusicPlay;
})
setTimeout(() => {
viewSpecial.classList.add('z-enter')
}, 1000)
</script>
- 可以看到,这里我们并没有采用classList.add\classList.remove的方式,而是为了代码更加优雅,直接通过classList.toggle()方法能够取代那两步操作
- 通过 defaultMusicPlay = !defaultMusicPlay;,也取代了小白同学再ifelse中重新复制为false、true的情况,代码更加简洁哦
如有帮助请大力支持~