秋日恋歌
<style>#papa { left: -214px; width: 1024px; height: 640px; background: gray url('https://638183.freep.cn/638183/t22/webp/qrlg.webp') no-repeat center/cover; box-shadow: 3px 3px 20px #000; display: grid; place-items: center; overflow: hidden; user-select: none; position: relative; z-index: 1; }
.btnplay { position: absolute; top: 0px; left: 100px; width: 80px; height: 80px; border-radius: 50%; box-shadow: 15px 10px 0 0 orange; cursor: pointer; z-index: 10; animation: swing 1s linear infinite alternate; }
.btnplay::before { position: absolute; content: ''; left: 20px; top: 12px; width: 100%; height: 100%; }
.btnplay::after { position: absolute; content: ''; left: 25px; top: 25px; width: 40%; height: 40%; border-radius: 50%; background: tan; box-shadow: 0 0 30px 0px purple, 0 0 100px 0 snow; }
#lrc { --motion: cover1; --tt: 1s; --state: paused; position: absolute; bottom: 15px; font: bold 2.4em sans-serif; color: hsl(60,100%,90%); -webkit-background-clip: text; filter: drop-shadow(1px 1px 2px hsla(0,100%,0%,.85)); }
#lrc::before { position: absolute; content: attr(data-lrc); width: 20%; height: 100%; color: transparent; overflow: hidden; white-space: nowrap; background: linear-gradient(180deg,hsla(0,100%,50%,.75),hsla(60,100%,50%,.65)); filter: inherit; -webkit-background-clip: text; animation: var(--motion) var(--tt) linear forwards; animation-play-state: var(--state); }
#svg { position: absolute; font: bold 10em sans-serif; }
.text { fill: none; stroke-width: 3; stroke-dasharray: 0 300; stroke-dashoffset: 0; }
.text:nth-child(3n + 1) { stroke: orange; animation: stroke1 30s ease-in-out infinite alternate; }
.text:nth-child(3n + 2) { stroke: red; animation: stroke2 30s ease-in-out infinite alternate; }
.text:nth-child(3n + 3) { stroke: snow; animation: stroke3 30s ease-in-out infinite alternate; }
.text:hover { fill: teal; opacity: .45; }
@keyframes cover1 { from { width: 0; } to { width: 100%; } }
@keyframes cover2 { from { width: 0; } to { width: 100%; } }
@keyframes swing { from { transform: rotate(0deg); } to { transform: rotate(30deg); } }
@keyframes stroke1 { to { stroke-dashoffset: 1000; stroke-dasharray: 80 160; } }
@keyframes stroke2 { to { stroke-dashoffset: 1080; stroke-dasharray: 80 160; } }
@keyframes stroke3 { to { stroke-dashoffset: 1160; stroke-dasharray: 80 160; } }
</style>
<div id="papa">
<svg id="svg" width="1024" height="640">
<symbol id="s-text"><text text-anchor="middle" x="50%" y="50%" dy=".35em">秋日恋歌</text></symbol>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
</svg>
<span class="btnplay" title="播放/暂停"></span>
<span style="position: absolute; transform: rotate(270deg); bottom: -120px; left: 80px; ">
<span class="btnplay" style="filter:blur(3px); opacity: .45; cursor: default;"></span>
</span>
<span id="lrc" data-lrc="花潮论坛lrc在线">花潮论坛lrc在线</span>
</div>
<script>
(function() {
let mKey = 0, mFlag = true, aud = new Audio();
let lrcAr = [,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,];
let btnplay = document.querySelector('.btnplay');
aud.src = 'https://music.163.com/song/media/outer/url?id=26147208.mp3';
aud.loop = false;
aud.play();
btnplay.onclick = () => aud.paused ? aud.play() : aud.pause();
aud.addEventListener('pause', () => mState());
aud.addEventListener('play', () => mState());
aud.addEventListener('ended', () => { mKey = 0; aud.play(); });
aud.addEventListener('timeupdate', () => {for (j = 0; j < lrcAr.length; j++) {if (aud.currentTime >= lrcAr) {if (mKey === j) showLrc(lrcAr);else continue;}}});
let mState = () => aud.paused ? (btnplay.style.animationPlayState = 'paused', lrc.style.setProperty('--state', 'paused')) : (btnplay.style.animationPlayState = 'running', lrc.style.setProperty('--state', 'running'));
let showLrc = (time) => {let name = mFlag ? 'cover1' : 'cover2';lrc.innerHTML = lrc.dataset.lrc = lrcAr;lrc.style.setProperty('--motion', name);lrc.style.setProperty('--tt', time + 's');lrc.style.setProperty('--state', 'running');mKey += 1;mFlag = !mFlag;};
})();
</script>
本帖最后由 马黑黑 于 2022-10-12 07:37 编辑
帖子中央的文本特效,用CSS+svg实现,代码如下:
一、CSS
#svg {
position: absolute;
font: bold 10em sans-serif; /* 字体 */
}
.text {
fill: none; /* 无填充色 */
stroke-width: 3; /* 描边宽度 */
stroke-dasharray: 0 300; /* 描边线段样式 */
stroke-dashoffset: 0; /* 描边线段偏移 */
}
/* 1、4、7 ... 单字样式 - 3n + 1 ,n 从 0 开始 */
.text:nth-child(3n + 1) {
stroke: orange; /* 描边色 */
animation: stroke1 30s ease-in-out infinite alternate; /* 运行关键帧动画 */
}
/* 2、5、8 ... 单字样式 */
.text:nth-child(3n + 2) {
stroke: red;
animation: stroke2 30s ease-in-out infinite alternate;
}
/* 3、6、9 ... 单字样式 */
.text:nth-child(3n + 3) {
stroke: snow;
animation: stroke3 30s ease-in-out infinite alternate;
}
/* 鼠标滑过文本时 */
.text:hover {
fill: teal; /* 文本填充色 */
opacity: .45; /* 透明设置 */
}
/**下面三个关键帧动画,依次对应 147、258、369顺序的单字
虚线线段样式 stroke-dasharray 从前面设定的 0 300 变化到下面的 80 160
虚线线段偏移量 stroke-dashoffse 从前面设定的 0 到 1000、1080、1160
关键帧动画其实用一个就好,但需要用到变量,生怕大家看花眼,所以一个一个来
**/
@keyframes stroke1 {
to {
stroke-dashoffset: 1000;
stroke-dasharray: 80 160;
}
}
@keyframes stroke2 {
to {
stroke-dashoffset: 1080;
stroke-dasharray: 80 160;
}
}
@keyframes stroke3 {
to {
stroke-dashoffset: 1160;
stroke-dasharray: 80 160;
}
}
二、HTML
<svg id="svg" width="1024" height="640">
<symbol id="s-text"><text text-anchor="middle" x="50%" y="50%" dy=".35em">秋日恋歌</text></symbol>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
<use xlink:href="#s-text" class="text"></use>
</svg>
svg代码不多做解释,好奇的朋友如果有不解,可取查一下 symbol 和 use,这两货是此处的功臣。
本帖最后由 马黑黑 于 2022-10-12 07:50 编辑
播放控制器使用单标签实现,但CSS代码比较多:
/* 按钮 */
.btnplay {
position: absolute;
top: 0px;
left: 100px;
width: 80px;
height: 80px;
border-radius: 50%;
box-shadow: 15px 10px 0 0 orange;
cursor: pointer;
z-index: 10;
animation: swing 1s linear infinite alternate;
}
/* 伪元素一:用以调整鼠标点击的接收区域 */
.btnplay::before {
position: absolute;
content: '';
left: 20px;
top: 12px;
width: 100%;
height: 100%;
}
/* 伪元素二:模拟伴星 */
.btnplay::after {
position: absolute;
content: '';
left: 25px;
top: 25px;
width: 40%;
height: 40%;
border-radius: 50%;
background: tan;
box-shadow: 0 0 30px 0px purple, 0 0 100px 0 snow;
}
/* 关键帧动画:摇摆 */
@keyframes swing {
from { transform: rotate(0deg); }
to { transform: rotate(30deg); }
}
HTML就一个标签代码:
<span class="btnplay" title="播放/暂停"></span>
JS中,播放器状态控制函数里,设置一下动画的暂停与继续:
let mState = () => aud.paused ? (btnplay.style.animationPlayState = 'paused', lrc.style.setProperty('--state', 'paused')) : (btnplay.style.animationPlayState = 'running', lrc.style.setProperty('--state', 'running'));
这个函数的运行,有诸多触发节点,比如按钮的点击、歌曲能不能自动播放、歌曲是播放中还是暂停中等等,都通过对播放器的监测实现,这里不多做解释。监控代码在这两行:
aud.addEventListener('pause', () => mState());
aud.addEventListener('play', () => mState());
播放器再左下角水中的投影,是对左上角按钮控制器的二次利用,用一个标签将其包裹起来以便易于控制它的位置和动作:
<span style="position: absolute; transform: rotate(270deg); bottom: -120px; left: 80px; ">
<span class="btnplay" style="filter:blur(3px); opacity: .45; cursor: default;"></span>
</span>
包裹的外标签,居中定义了样式(绿色代码),同样,引用按钮控制器的代码,也用了句内的临时样式(红色代码)。
这字幕太精妙了,兼容看是日月相伴,极速打开,山水屏幕出来了,那些像萤火虫慢慢跑动起来,隐隐约约的主题出来了。唱者是水木年华中的一个 这个svg文字漂亮,还能往复进行动画效果,非常惊艳{:4_199:} 马黑黑 发表于 2022-10-12 07:56
播放器再左下角水中的投影,是对左上角按钮控制器的二次利用,用一个标签将其包裹起来以便易于控制它的位置 ...
transform: rotate(270deg); 这个和上次动图的投影不一样呢。 关于月牙怎么出来的,又迷糊了,还得去翻前面的帖子才行{:4_173:} 哇!“秋日恋歌”这几个字设计得太漂亮啦。 醉美水芙蓉 发表于 2022-10-12 11:49
黑黑老师这个播放器真漂亮!
还行吧 红影 发表于 2022-10-12 09:08
transform: rotate(270deg); 这个和上次动图的投影不一样呢。
方法多了去,看爱用什么 上海朝阳 发表于 2022-10-12 08:44
这字幕太精妙了,兼容看是日月相伴,极速打开,山水屏幕出来了,那些像萤火虫慢慢跑动起来,隐隐约约的主题 ...
现在都不考虑兼容IE了,IE早已宣布死亡 梦油 发表于 2022-10-12 11:08
哇!“秋日恋歌”这几个字设计得太漂亮啦。
还行 红影 发表于 2022-10-12 09:33
关于月牙怎么出来的,又迷糊了,还得去翻前面的帖子才行
用影子 红影 发表于 2022-10-12 09:05
这个svg文字漂亮,还能往复进行动画效果,非常惊艳
过得去吧。原理和前面弄过的差别不大。 马黑黑 发表于 2022-10-12 13:32
还行
黑黑朋友真谦逊。 马黑黑 发表于 2022-10-12 13:31
方法多了去,看爱用什么
嗯嗯,在黑黑的帖子里慢慢学习{:4_187:} 马黑黑 发表于 2022-10-12 13:32
用影子
我知道是用投影,一下子又有点反应不过来了。 马黑黑 发表于 2022-10-12 13:32
过得去吧。原理和前面弄过的差别不大。
是的,你在歌词里也弄过的呢。