上一篇
HTML、CSS和JavaScript结合,通过解析歌词时间戳与音频播放进度同步,动态控制
歌词显示位置实现滚动效果
HTML中实现歌词的动态效果,通常需要结合CSS和JavaScript来控制歌词的显示、滚动和高亮等行为,以下是实现这一功能的详细步骤和示例代码:
基本结构搭建
- HTML部分:
- 创建一个
<audio>标签用于播放音乐。 - 创建一个容器(如
<div>)来放置歌词,通常使用<ul>和<li>标签来逐行显示歌词。
- 创建一个
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Lyrics Scrolling Effect</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<audio id="musicPlayer" src="song.mp3" controls></audio>
<div class="lyrics-container">
<ul id="lyricsList"></ul>
</div>
<script src="script.js"></script>
</body>
</html>
- CSS部分:
- 设置歌词容器的样式,包括大小、背景、溢出隐藏等。
- 设置歌词列表的样式,如行高、字体、颜色等。
- 定义高亮显示的样式,如改变颜色、放大等。
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
text-align: center;
}
.lyrics-container {
width: 50%;
height: 300px;
margin: 20px auto;
overflow: hidden;
border: 1px solid #ccc;
background-color: #fff;
}
#lyricsList {
list-style: none;
padding: 0;
margin: 0;
transition: top 0.5s ease-in-out;
}
#lyricsList li {
height: 30px;
line-height: 30px;
font-size: 18px;
}
.active {
color: red;
font-weight: bold;
transform: scale(1.1);
}
JavaScript实现逻辑
- 解析歌词文件:
通常歌词文件是LRC格式,包含时间戳和歌词文本,需要编写函数来解析这种格式,将歌词按时间顺序存储到数组中。
function parseLyrics(lyricsText) {
const lines = lyricsText.split('n');
const lyrics = [];
lines.forEach(line => {
const match = line.match(/[(d{2}):(d{2}).(d{2})](.+)/);
if (match) {
const minutes = parseInt(match[1], 10);
const seconds = parseInt(match[2], 10);
const milliseconds = parseInt(match[3], 10);
const time = (minutes 60 + seconds) 1000 + milliseconds 10;
lyrics.push({ time, text: match[4] });
}
});
return lyrics;
}
- 同步歌词与音乐播放:
- 监听
<audio>标签的timeupdate事件,获取当前播放时间。 - 根据当前时间找到应该显示的歌词,并更新歌词列表的显示。
- 监听
const musicPlayer = document.getElementById('musicPlayer');
const lyricsList = document.getElementById('lyricsList');
let lyrics = []; // 假设已经通过AJAX或其他方式加载并解析了歌词
let currentLine = 0;
musicPlayer.addEventListener('timeupdate', () => {
const currentTime = musicPlayer.currentTime 1000; // 转换为毫秒
while (currentLine < lyrics.length && lyrics[currentLine].time <= currentTime) {
lyricsList.children[currentLine].classList.remove('active');
currentLine++;
}
if (currentLine < lyrics.length) {
lyricsList.children[currentLine].classList.add('active');
// 调整歌词列表的位置,使当前行可见
const scrollAmount = currentLine lyricsList.children[0].offsetHeight;
lyricsList.style.top = `-${scrollAmount}px`;
}
});
- 动态加载歌词:
如果歌词是从外部文件加载的,可以使用AJAX或Fetch API来获取歌词文本,然后调用解析函数。

fetch('lyrics.lrc')
.then(response => response.text())
.then(lyricsText => {
lyrics = parseLyrics(lyricsText);
// 将歌词添加到页面中
lyrics.forEach(lyric => {
const li = document.createElement('li');
li.textContent = lyric.text;
lyricsList.appendChild(li);
});
});
优化与扩展
-
平滑滚动:
- 使用CSS的
transition属性或JavaScript的动画库来实现歌词滚动的平滑效果。
- 使用CSS的
-
歌词对齐:

- 确保歌词文本在容器中垂直居中,可以通过调整
line-height或使用Flexbox布局来实现。
- 确保歌词文本在容器中垂直居中,可以通过调整
-
错误处理:
添加错误处理机制,如歌词文件加载失败时的提示信息。

-
用户交互:
- 允许用户点击歌词来跳转到歌曲的特定位置。
- 提供暂停、播放、快进、快退等控制按钮。
完整示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">Lyrics Scrolling Effect</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
text-align: center;
}
.lyrics-container {
width: 50%;
height: 300px;
margin: 20px auto;
overflow: hidden;
border: 1px solid #ccc;
background-color: #fff;
position: relative;
}
#lyricsList {
list-style: none;
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
transition: top 0.5s ease-in-out;
}
#lyricsList li {
height: 30px;
line-height: 30px;
font-size: 18px;
}
.active {
color: red;
font-weight: bold;
transform: scale(1.1);
}
</style>
</head>
<body>
<audio id="musicPlayer" src="song.mp3" controls></audio>
<div class="lyrics-container">
<ul id="lyricsList"></ul>
</div>
<script>
function parseLyrics(lyricsText) {
const lines = lyricsText.split('n');
const lyrics = [];
lines.forEach(line => {
const match = line.match(/[(d{2}):(d{2}).(d{2})](.+)/);
if (match) {
const minutes = parseInt(match[1], 10);
const seconds = parseInt(match[2], 10);
const milliseconds = parseInt(match[3], 10);
const time = (minutes 60 + seconds) 1000 + milliseconds 10;
lyrics.push({ time, text: match[4] });
}
});
return lyrics;
}
const musicPlayer = document.getElementById('musicPlayer');
const lyricsList = document.getElementById('lyricsList');
let lyrics = []; // 假设已经通过AJAX或其他方式加载并解析了歌词
let currentLine = 0;
musicPlayer.addEventListener('timeupdate', () => {
const currentTime = musicPlayer.currentTime 1000; // 转换为毫秒
while (currentLine < lyrics.length && lyrics[currentLine].time <= currentTime) {
lyricsList.children[currentLine].classList.remove('active');
currentLine++;
}
if (currentLine < lyrics.length) {
lyricsList.children[currentLine].classList.add('active');
// 调整歌词列表的位置,使当前行可见
const scrollAmount = currentLine lyricsList.children[0].offsetHeight;
lyricsList.style.top = `-${scrollAmount}px`;
}
});
fetch('lyrics.lrc')
.then(response => response.text())
.then(lyricsText => {
lyrics = parseLyrics(lyricsText);
// 将歌词添加到页面中
lyrics.forEach(lyric => {
const li = document.createElement('li');
li.textContent = lyric.text;
lyricsList.appendChild(li);
});
});
</script>
</body
