亚伦影音工作室 发表于 2025-11-6 14:27

CSS mask百叶窗转场动画效果【我还是忘不了你】

本帖最后由 亚伦影音工作室 于 2025-11-7 04:12 编辑 <br /><br /> <style>
#papa{position: relative;
            width: 1286px;
            height: 720px;
            margin-left: -300px;
            margin-top: 10px;
            overflow: hidden;z-index:12345;
            background:url(https://pic1.imgdb.cn/item/68625f9658cb8da5c87f755d.jpg)no-repeat center/cover;
      }
       zxx-slide {display: block;

   width: 100%; height:105%;
    position: absolute;
}
.zxx-slide-a {width: 100%; height: 100%;
    position: absolute;bottom: 0px;
   display: none;
}
.zxx-slide-a.in {
    z-index: 1;
}
.zxx-slide-img { position: absolute;
height:100%;width: 1286px;
   display: block;}

.zxx-slide-index-x {
    position: absolute;
    left: 0px; right: 0; bottom: 0px;
    text-align: center;
    font-size: 0;
    z-index: 1;
}

@keyframes seed {
    0%{--seed:0}1%{--seed:1}2%{--seed:2}3%{--seed:3}4%{--seed:4}5%{--seed:5}6%{--seed:6}7%{--seed:7}8%{--seed:8}9%{--seed:9}10%{--seed:10}11%{--seed:11}12%{--seed:12}13%{--seed:13}14%{--seed:14}15%{--seed:15}16%{--seed:16}17%{--seed:17}18%{--seed:18}19%{--seed:19}20%{--seed:20}21%{--seed:21}22%{--seed:22}23%{--seed:23}24%{--seed:24}25%{--seed:25}26%{--seed:26}27%{--seed:27}28%{--seed:28}29%{--seed:29}30%{--seed:30}31%{--seed:31}32%{--seed:32}33%{--seed:33}34%{--seed:34}35%{--seed:35}36%{--seed:36}37%{--seed:37}38%{--seed:38}39%{--seed:39}40%{--seed:40}41%{--seed:41}42%{--seed:42}43%{--seed:43}44%{--seed:44}45%{--seed:45}46%{--seed:46}47%{--seed:47}48%{--seed:48}49%{--seed:49}50%{--seed:50}51%{--seed:51}52%{--seed:52}53%{--seed:53}54%{--seed:54}55%{--seed:55}56%{--seed:56}57%{--seed:57}58%{--seed:58}59%{--seed:59}60%{--seed:60}61%{--seed:61}62%{--seed:62}63%{--seed:63}64%{--seed:64}65%{--seed:65}66%{--seed:66}67%{--seed:67}68%{--seed:68}69%{--seed:69}70%{--seed:70}71%{--seed:71}72%{--seed:72}73%{--seed:73}74%{--seed:74}75%{--seed:75}76%{--seed:76}77%{--seed:77}78%{--seed:78}79%{--seed:79}80%{--seed:80}81%{--seed:81}82%{--seed:82}83%{--seed:83}84%{--seed:84}85%{--seed:85}86%{--seed:86}87%{--seed:87}88%{--seed:88}89%{--seed:89}90%{--seed:90}91%{--seed:91}92%{--seed:92}93%{--seed:93}94%{--seed:94}95%{--seed:95}96%{--seed:96}97%{--seed:97}98%{--seed:98}99%{--seed:99}100%{--seed:100}
}
zxx-slide .in {
    -webkit-mask: linear-gradient(to right, #000 calc(1% * var(--seed)), transparent calc(1% * var(--seed)));
    -webkit-mask-size: 50px;
    mask: linear-gradient(to right, #000 calc(1% * var(--seed)), transparent calc(1% * var(--seed)));
    mask-size: 50px;
    animation: seed 1s;
}
.lyrics{margin: 0;z-index: 20;
            top: 89%;
            left: 50%;
    transform: translate(-50%, -50%);
            height: 100px; /* 调整高度,只容纳当前歌词 */
                 text-align: center;
             position: absolute;
      }
            .lyric-line{
            width: 100%;
            position: relative;
            height: 60px;
            overflow: visible;
   font: 300 50px '华文隶书', sans-serif;
            line-height: 60px;
         text-align: left;
            white-space: nowrap; /* 禁止换行 */
            
            filter: drop-shadow(#fff 1px 0 0) drop-shadow(#fff 0 1px 0) drop-shadow(#fff -1px 0 0) drop-shadow(#fff 0 -1px 0);
      }

      .lyric-mask {
            position: absolute;
            top: 0;
            left: 0;
            width: 0;
            overflow: hidden;
      color: #8B4513;
            height: 100%;
            white-space: nowrap;
      }

      .lyric-original {
             color: #ag0000;
            white-space: nowrap;
            
      }

#mdiv {top:12%; left:85%;cursor: pointer;width:120px;height: 120px;animation:rot 10s linear infinite ;position: absolute;filter:drop-shadow(#000 0px 0 1px);z-index: 40;}
@keyframes rot { to { transform: rotate(2turn);} }
</style>
<divid="papa">
   <zxx-slide>
    <div class="zxx-slide-x">
      <p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/67453531d0e0a243d4d0ccd4.jpg"></p>
      <p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/689714a158cb8da5c814a178.jpg"></p>
      <p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/686cbd4658cb8da5c8963cfc.webp"></p>
      <p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/68634c9d58cb8da5c8811794.jpg"></p>
      <p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/65db15639f345e8d03a78720.jpg"></p>
      <p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/6713a87cd29ded1a8ccbc781.jpg"></p>
<p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/66936b4cd9c307b7e9613d20.png"></p>
<p class="zxx-slide-a"><img class="zxx-slide-img" src="https://pic1.imgdb.cn/item/66933654d9c307b7e920b911.png"></p>

    </div>
   </zxx-slide>
   <img id="mdiv"src="https://pic1.imgdb.cn/item/690c41ba3203f7be00db7fed.png">
<div class="lyrics" >
            <div class="lyric-line">
                  <div class="lyric-mask"></div>
                  <div class="lyric-original"></div>
                </div>
            </div>

</div>
<audio id="audio" src="https://s2.cldisk.com/sv-w9/audio/77/2a/47/9f2c9c3941d032072bd46d1fdbc67ded/audio.mp3"loopautoplay ></audio>
<script>
mdiv.onclick = () => audio.paused ? audio.play(): audio.pause();
audio.addEventListener('playing', () =>mdiv.style.animationPlayState = 'running');
audio.addEventListener('pause', () =>mdiv.style.animationPlayState = 'paused');

mdiv.style.animationPlayState = audio.paused ? 'paused' : 'running';

</script>

<script>var eleZxxSlides = document.querySelectorAll('zxx-slide');
[].slice.call(eleZxxSlides).forEach(function (container) {
        var timerSlide = null;
        var indexSlide = 0;
        container.addEventListener('mouseover', function () {
                clearTimeout(timerSlide);
        });
        container.addEventListener('mouseout', function () {
                clearTimeout(timerSlide);
                funSlide();
        });
       
        var eleSlides = [].slice.call(container.querySelectorAll('p'));
        var eleButtons = [].slice.call(container.querySelectorAll('button'));
       
       
        eleButtons.forEach(function (button, index) {
                ['mouseover', 'click'].forEach(function (eventType) {
                        button.addEventListener(eventType, function () {
                                clearTimeout(timerSlide);
                                indexSlide = index;
                                funSlide();
                        });
                });
        });

       
        eleSlides.forEach(function (slide, index) {
                slide.addEventListener('animationend', function () {
                        eleSlides.forEach(function (slide2) {
                                if (slide2.classList.contains('in') == false) {
                                        slide2.style.display = '';
                                }
                        });
                });
        });
       
        var funSlide = function() {
                eleSlides.forEach(function (slide, index) {if(!audio.paused){               
                        if (indexSlide == index) {
                                slide.classList.add('in');
                                slide.style.display = 'block';
                        } else if (slide.classList.contains('in')) {
                                slide.classList.remove('in');
                        }
                }});
                eleButtons.forEach(function (button, index) {
                        button.classList.remove('active');
                        if (indexSlide == index) {
                                button.classList.add('active');
                        }
                });
               
                timerSlide = setTimeout(function () {
                        indexSlide++;
                        if (indexSlide == eleSlides.length) {
                                indexSlide = 0;
                        }
                        funSlide();
                }, 2400);
        }
       
        indexSlide++;

        setTimeout(funSlide, 300);
});

</script>

<script>
      // 歌词解析ksc歌词或lrc歌词
      const lrc = `我还是忘不了你
爱的旋律
演唱:燕宝儿
创作:亚伦影音工作室
你不要走你不要走
难道是我爱的不够
我想念你想念着你
想与你一起到白头
你可知道可曾知道
我贪恋着你的温柔
啊负心人负心的人
为什么要如此狠心
啊我还是忘不了你
忘不了你的柔情
你为什么要与我分离
留我一人伤心哭泣
你不该就这样离我而去
你可知道可曾知道
我贪恋着你的温柔
啊负心人负心的人
为什么要如此狠心
啊我还是忘不了你
忘不了你的柔情
你为什么要与我分离
留我一人伤心哭泣
你不该就这样离我而去
啊我还是忘不了你
忘不了你的柔情
你为什么要与我分离
留我一人伤心哭泣
你不该就这样离我而去
你不该就这样离我而去

`;
const audio = document.getElementById('audio');
      const lyrics = parseLyrics(lrc);
      const lyricMask = document.querySelector('.lyric-mask');
      const lyricOriginal = document.querySelector('.lyric-original');
      
      let currentIndex = -1;
      let currentLyric = null;
      
      // 解析歌词(支持两种格式)
      function parseLyrics(lrcText) {
            const lyrics = [];
            if (lrcText.includes('karaoke.add')) {
                const lineRegex = /karaoke\.add\('([^']+)', '([^']+)', '([^']+)', '([^']+)'\);/g;
                let match;
                while ((match = lineRegex.exec(lrcText)) !== null) {
                  const startTime = timeToMs(match);
                  const endTime = timeToMs(match);
                  const text = match.replace(/\[|\]/g, '').trim();
                  const durations = match.split(',').map(Number);
                  if (text) {
                        lyrics.push({startTime, endTime, text, durations});
                  }
                }
            }
            else if (lrcText.includes('[')) {
                const lines = lrcText.split('\n').filter(line => line.trim());
                lines.forEach((line, index) => {
                  const timeMatch = line.match(/\[(\d+:\d+\.\d+)\]/);
                  if (timeMatch) {
                        const timeStr = timeMatch;
                        const text = line.replace(/\[.*?\]/, '').trim();
                        if (text) {
                            const startTime = timeToMs(timeStr);
                            const nextLine = lines;
                            const nextTimeMatch = nextLine ? nextLine.match(/\[(\d+:\d+\.\d+)\]/) : null;
                            const endTime = nextTimeMatch ? timeToMs(nextTimeMatch) : startTime + 5000;
                            lyrics.push({
                              startTime,
                              endTime,
                              text,
                              durations: calculateCharDurations(text, startTime, endTime)
                            });
                        }
                  }
                });
            }
            return lyrics;
      }
      function calculateCharDurations(text, startTime, endTime) {
            const totalDuration = endTime - startTime;
            const charCount = text.length;
            const baseDur = Math.floor(totalDuration / charCount);
            const durations = new Array(charCount).fill(baseDur);
            const remainder = totalDuration % charCount;
            for (let i = 0; i < remainder; i++) {
                durations++;
            }
            return durations;
      }
      function timeToMs(timeStr) {
            const parts = timeStr.split(':');
            const minutes = parseInt(parts, 10);
            const secondsAndMs = parts.split('.');
            const seconds = parseInt(secondsAndMs, 10);
            const ms = parseInt(secondsAndMs || 0, 10);
            return minutes * 60 * 1000 + seconds * 1000 + ms;
      }
      function getCurrentLyricIndex(lyrics, currentTimeMs) {
            for (let i = 0; i < lyrics.length; i++) {
                if (currentTimeMs >= lyrics.startTime && currentTimeMs <= lyrics.endTime) {
                  return i;
                }
            }
            return -1;
      }
      function updateLyricDisplay(index) {
            if (index < 0 || index >= lyrics.length) return;
            currentIndex = index;
            currentLyric = lyrics;
            lyricOriginal.textContent = currentLyric.text;
            lyricMask.textContent = currentLyric.text;
            lyricMask.style.width = '0%';
      }
      function updateLyricMask(currentTimeMs) {
            if (!currentLyric) return;
            const lyricStartTime = currentLyric.startTime;
            const elapsed = currentTimeMs - lyricStartTime;
            const totalDuration = currentLyric.durations.reduce((sum, d) => sum + d, 0);
            let charIndex = 0;
            let accumulatedTime = 0;
            
            for (let i = 0; i < currentLyric.durations.length; i++) {
                accumulatedTime += currentLyric.durations;
                if (elapsed <= accumulatedTime) {
                  charIndex = i + 1;
                  break;
                }
            }
            
            if (elapsed >= totalDuration) {
                charIndex = currentLyric.text.length;
            }
            
            charIndex = Math.min(charIndex, currentLyric.text.length);
            
            const tempSpan = document.createElement('span');
            tempSpan.style.visibility = 'hidden';
            tempSpan.style.position = 'absolute';
            tempSpan.style.fontSize = '50px';
            tempSpan.style.fontWeight = '800';
            document.body.appendChild(tempSpan);
            
            const visibleText = currentLyric.text.substring(0, charIndex);
            tempSpan.textContent = visibleText;
            const width = tempSpan.offsetWidth;
            document.body.removeChild(tempSpan);
            
            lyricMask.style.width = `${width}px`;
      }
      
      // 监听更新歌词
      audio.addEventListener('timeupdate', () => {
            const currentTimeMs = audio.currentTime * 1000;
            const index = getCurrentLyricIndex(lyrics, currentTimeMs);
            
            if (index !== currentIndex) {
                updateLyricDisplay(index);
            }
            
            updateLyricMask(currentTimeMs);
      });
      updateLyricDisplay(0);


</script>

小辣椒 发表于 2025-11-6 17:57

亚纶这个百叶窗转场效果特别棒!{:4_178:}

小辣椒 发表于 2025-11-6 18:07

我曾经做过一个H5播放器的背景图用了百叶窗效果,但没有这么多的图片,感觉找图片太麻烦了

刚才预览了一下一个图百叶窗效果没有了,可能我就是减了图片连接,没有修改代码的原因

亚纶就用二个图片的制作一个,这样做帖速度会快许多。做图太麻烦了

亚伦影音工作室 发表于 2025-11-6 18:32

小辣椒 发表于 2025-11-6 18:07
我曾经做过一个H5播放器的背景图用了百叶窗效果,但没有这么多的图片,感觉找图片太麻烦了

刚才预览了一 ...

后边的数据得改一下就可以了!

樵歌 发表于 2025-11-6 18:42

高手就是高手,用最简单的方法制作出最漂亮的作品!{:4_178:}

樵歌 发表于 2025-11-6 18:43

小辣椒 发表于 2025-11-6 17:57
亚纶这个百叶窗转场效果特别棒!

就知道你喜欢{:4_172:}

老谟深虑 发表于 2025-11-6 19:18

         这个百叶窗转场效果真好,欣赏了!

杨帆 发表于 2025-11-6 21:37

自然、顺畅的百叶窗转场效果,谢谢亚伦老师精彩分享{:4_191:}
页: [1]
查看完整版本: CSS mask百叶窗转场动画效果【我还是忘不了你】