- 顶部导航栏:包含Logo、搜索框、用户信息。
- 侧边栏菜单:包含我的音乐、推荐歌单、排行榜等。
- 区:
- 轮播图:展示推荐内容。
- 推荐歌单:以网格形式展示。
- 新歌速递:列表形式展示最新歌曲。
- 排行榜:展示多个榜单。
- 底部播放器:包含播放/暂停、上一首/下一首、进度条、音量控制等。
第一步:项目文件结构
创建一个项目文件夹,并在其中创建以下文件:

(图片来源网络,侵删)
netease-music/
├── index.html # HTML主文件
├── css/
│ └── style.css # CSS样式文件
├── js/
│ └── main.js # JavaScript交互逻辑
└── images/ # 存放图片资源
├── logo.png
├── banner1.jpg
├── banner2.jpg
└── ... (其他歌曲封面等)
第二步:HTML 结构 (index.html)
这是整个页面的骨架,我们使用语义化的HTML5标签,并引入我们将要编写的CSS和JS文件。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">网易云音乐</title>
<link rel="stylesheet" href="css/style.css">
<!-- 引入字体图标库,这里使用Font Awesome作为示例 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
</head>
<body>
<!-- 顶部导航栏 -->
<header class="header">
<div class="header-left">
<h1 class="logo">网易云音乐</h1>
</div>
<div class="header-center">
<div class="search-box">
<input type="text" placeholder="音乐、歌词、歌手">
<button><i class="fas fa-search"></i></button>
</div>
</div>
<div class="header-right">
<a href="#" class="login-btn">登录</a>
<a href="#" class="user-avatar"><img src="https://picsum.photos/seed/user1/40/40.jpg" alt="用户头像"></a>
</div>
</header>
<div class="main-container">
<!-- 侧边栏 -->
<aside class="sidebar">
<ul class="menu-list">
<li class="menu-item active"><a href="#"><i class="fas fa-home"></i> 发现音乐</a></li>
<li class="menu-item"><a href="#"><i class="fas fa-music"></i> 我的音乐</a></li>
<li class="menu-item"><a href="#"><i class="fas fa-list"></i> 创建的歌单</a></li>
<li class="menu-item"><a href="#"><i class="fas fa-star"></i> 我喜欢的音乐</a></li>
</ul>
<div class="playlists">
<h3>创建的歌单</h3>
<ul>
<li><a href="#">我喜欢的音乐</a></li>
<li><a href="#">搜索“周杰伦”</a></li>
<li><a href="#">搜索“林俊杰”</a></li>
</ul>
</div>
</aside>
<!-- 主内容区 -->
<main class="content">
<!-- 轮播图 -->
<section class="banner">
<div class="banner-slides">
<div class="slide active"><img src="https://picsum.photos/seed/banner1/800/300.jpg" alt="轮播图1"></div>
<div class="slide"><img src="https://picsum.photos/seed/banner2/800/300.jpg" alt="轮播图2"></div>
<div class="slide"><img src="https://picsum.photos/seed/banner3/800/300.jpg" alt="轮播图3"></div>
</div>
<div class="banner-dots">
<span class="dot active"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</section>
<!-- 推荐歌单 -->
<section class="recommend-playlists">
<h2 class="section-title">推荐歌单</h2>
<div class="playlist-grid">
<!-- 歌单项将通过JS动态生成 -->
</div>
</section>
<!-- 新歌速递 -->
<section class="new-songs">
<h2 class="section-title">新歌速递</h2>
<div class="song-list">
<!-- 歌曲列表将通过JS动态生成 -->
</div>
</section>
<!-- 排行榜 -->
<section class="charts">
<h2 class="section-title">排行榜</h2>
<div class="charts-container">
<!-- 榜单将通过JS动态生成 -->
</div>
</section>
</main>
</div>
<!-- 底部播放器 -->
<footer class="player">
<div class="player-left">
<div class="now-playing">
<img src="https://picsum.photos/seed/nowplaying/50/50.jpg" alt="正在播放" class="song-cover">
<div class="song-info">
<div class="song-name">起风了</div>
<div class="artist-name">买辣椒也用券</div>
</div>
</div>
</div>
<div class="player-center">
<div class="player-controls">
<button class="control-btn prev-btn"><i class="fas fa-step-backward"></i></button>
<button class="control-btn play-btn"><i class="fas fa-play"></i></button>
<button class="control-btn next-btn"><i class="fas fa-step-forward"></i></button>
</div>
<div class="progress-bar">
<span class="current-time">0:00</span>
<div class="progress-track">
<div class="progress-filled"></div>
</div>
<span class="total-time">3:50</span>
</div>
</div>
<div class="player-right">
<button class="control-btn volume-btn"><i class="fas fa-volume-up"></i></button>
<div class="volume-bar">
<div class="volume-track">
<div class="volume-filled"></div>
</div>
</div>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>
第三步:CSS 样式 (css/style.css)
这是页面的“皮肤”,负责布局、颜色、字体和动画,为了保持代码整洁,我们使用了一些CSS变量。
/* 全局样式和变量 */
:root {
--primary-color: #C20C0C;
--background-color: #222;
--sidebar-bg: #000;
--text-color: #fff;
--text-secondary: #999;
--border-color: #282828;
--hover-bg: #333;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background-color: var(--background-color);
color: var(--text-color);
height: 100vh;
display: flex;
flex-direction: column;
}
/* 顶部导航栏 */
.header {
height: 70px;
background-color: var(--sidebar-bg);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
}
.logo {
font-size: 24px;
font-weight: bold;
color: var(--primary-color);
}
.search-box {
width: 300px;
position: relative;
}
.search-box input {
width: 100%;
padding: 8px 35px 8px 15px;
border: none;
border-radius: 20px;
background-color: var(--hover-bg);
color: var(--text-color);
outline: none;
}
.search-box button {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: var(--text-secondary);
cursor: pointer;
}
.header-right a {
color: var(--text-color);
text-decoration: none;
margin-left: 20px;
}
.user-avatar img {
width: 40px;
height: 40px;
border-radius: 50%;
}
/* 主容器 */
.main-container {
display: flex;
margin-top: 70px; /* 为固定header留出空间 */
height: calc(100vh - 70px - 70px); /* 减去header和footer的高度 */
}
/* 侧边栏 */
.sidebar {
width: 200px;
background-color: var(--sidebar-bg);
padding: 20px 0;
overflow-y: auto;
}
.menu-list {
list-style: none;
}
.menu-item a {
display: block;
padding: 15px 20px;
color: var(--text-secondary);
text-decoration: none;
transition: all 0.3s;
}
.menu-item a:hover, .menu-item.active a {
color: var(--text-color);
background-color: var(--hover-bg);
}
区 */
.content {
flex: 1;
padding: 20px;
overflow-y: auto;
background-color: #121212;
}
.section-title {
font-size: 20px;
margin-bottom: 20px;
font-weight: 500;
}
/* 轮播图 */
.banner {
position: relative;
height: 300px;
margin-bottom: 30px;
border-radius: 8px;
overflow: hidden;
}
.banner-slides .slide {
position: absolute;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 1s ease-in-out;
}
.banner-slides .slide.active {
opacity: 1;
}
.banner-slides img {
width: 100%;
height: 100%;
object-fit: cover;
}
.banner-dots {
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
}
.dot {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: rgba(255, 255, 255, 0.5);
cursor: pointer;
}
.dot.active {
background-color: #fff;
}
/* 推荐歌单 */
.playlist-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.playlist-item {
cursor: pointer;
}
.playlist-item img {
width: 100%;
border-radius: 8px;
margin-bottom: 10px;
}
.playlist-item .play-count {
font-size: 12px;
color: var(--text-secondary);
}
/* 新歌速递 */
.song-list {
display: flex;
flex-direction: column;
gap: 15px;
margin-bottom: 40px;
}
.song-item {
display: flex;
align-items: center;
padding: 10px;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s;
}
.song-item:hover {
background-color: var(--hover-bg);
}
.song-item img {
width: 60px;
height: 60px;
border-radius: 4px;
margin-right: 15px;
}
.song-item .song-info {
flex: 1;
}
.song-item .song-name {
font-size: 16px;
margin-bottom: 5px;
}
.song-item .artist-name {
font-size: 13px;
color: var(--text-secondary);
}
/* 排行榜 */
.charts-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.chart-card {
background-color: var(--hover-bg);
border-radius: 8px;
padding: 15px;
}
.chart-card h3 {
font-size: 16px;
margin-bottom: 15px;
}
.chart-list {
list-style: none;
}
.chart-item {
display: flex;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid var(--border-color);
}
.chart-item .rank {
width: 25px;
text-align: center;
color: var(--text-secondary);
}
.chart-item .rank.top {
color: var(--primary-color);
font-weight: bold;
}
.chart-item .song-details {
flex: 1;
margin-left: 10px;
}
.chart-item .song-name {
font-size: 14px;
margin-bottom: 3px;
}
.chart-item .artist {
font-size: 12px;
color: var(--text-secondary);
}
/* 底部播放器 */
.player {
height: 70px;
background-color: var(--sidebar-bg);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
position: fixed;
bottom: 0;
left: 0;
right: 0;
}
.player-left .now-playing {
display: flex;
align-items: center;
}
.song-cover {
width: 50px;
height: 50px;
border-radius: 4px;
margin-right: 15px;
}
.song-info .song-name {
font-size: 14px;
margin-bottom: 3px;
}
.song-info .artist-name {
font-size: 12px;
color: var(--text-secondary);
}
.player-center {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
padding: 0 40px;
}
.player-controls {
display: flex;
align-items: center;
gap: 20px;
margin-bottom: 10px;
}
.control-btn {
background: none;
border: none;
color: var(--text-color);
cursor: pointer;
font-size: 16px;
}
.control-btn.play-btn {
font-size: 24px;
color: var(--primary-color);
}
.progress-bar {
width: 100%;
display: flex;
align-items: center;
gap: 10px;
}
.progress-track {
flex: 1;
height: 4px;
background-color: var(--border-color);
border-radius: 2px;
position: relative;
cursor: pointer;
}
.progress-filled {
height: 100%;
background-color: var(--primary-color);
border-radius: 2px;
width: 30%; /* 初始进度 */
}
.player-right {
display: flex;
align-items: center;
gap: 10px;
}
.volume-bar {
width: 100px;
height: 4px;
background-color: var(--border-color);
border-radius: 2px;
position: relative;
cursor: pointer;
display: none; /* 默认隐藏,点击音量图标时显示 */
}
.volume-bar.show {
display: block;
}
.volume-filled {
height: 100%;
background-color: var(--text-color);
border-radius: 2px;
width: 70%; /* 初始音量 */
}
第四步:JavaScript 交互 (js/main.js)
这是页面的“大脑”,负责处理用户的点击、播放音乐、切换内容等动态行为。
document.addEventListener('DOMContentLoaded', () => {
// --- 模拟数据 ---
const playlists = [
{ id: 1, name: '欧美经典', cover: 'https://picsum.photos/seed/pl1/200/200.jpg', playCount: '120万' },
{ id: 2, name: '华语新歌榜', cover: 'https://picsum.photos/seed/pl2/200/200.jpg', playCount: '98万' },
{ id: 3, name: '轻音乐', cover: 'https://picsum.photos/seed/pl3/200/200.jpg', playCount: '56万' },
{ id: 4, name: '摇滚在路上', cover: 'https://picsum.photos/seed/pl4/200/200.jpg', playCount: '42万' },
{ id: 5, name: '电音派对', cover: 'https://picsum.photos/seed/pl5/200/200.jpg', playCount: '35万' },
{ id: 6, name: '深夜emo', cover: 'https://picsum.photos/seed/pl6/200/200.jpg', playCount: '88万' },
];
const newSongs = [
{ id: 1, name: '起风了', artist: '买辣椒也用券', cover: 'https://picsum.photos/seed/song1/60/60.jpg' },
{ id: 2, name: '漠河舞厅', artist: '柳爽', cover: 'https://picsum.photos/seed/song2/60/60.jpg' },
{ id: 3, name: '错位时空', artist: '艾辰', cover: 'https://picsum.photos/seed/song3/60/60.jpg' },
{ id: 4, name: '星辰大海', artist: '黄霄雲', cover: 'https://picsum.photos/seed/song4/60/60.jpg' },
{ id: 5, name: '孤勇者', artist: '陈奕迅', cover: 'https://picsum.photos/seed/song5/60/60.jpg' },
];
const charts = [
{ id: 1, name: '飙升榜', songs: [
{ rank: 1, name: '错位时空', artist: '艾辰' },
{ rank: 2, name: '星辰大海', artist: '黄霄雲' },
{ rank: 3, name: '孤勇者', artist: '陈奕迅' },
]},
{ id: 2, name: '新歌榜', songs: [
{ rank: 1, name: '起风了', artist: '买辣椒也用券' },
{ rank: 2, name: '漠河舞厅', artist: '柳爽' },
{ rank: 3, name: '错位时空', artist: '艾辰' },
]},
{ id: 3, name: '原创榜', songs: [
{ rank: 1, name: '起风了', artist: '买辣椒也用券' },
{ rank: 2, name: '漠河舞厅', artist: '柳爽' },
{ rank: 3, name: '星辰大海', artist: '黄霄雲' },
]},
];
// --- DOM 元素 ---
const playlistGrid = document.querySelector('.playlist-grid');
const songList = document.querySelector('.song-list');
const chartsContainer = document.querySelector('.charts-container');
const playBtn = document.querySelector('.play-btn i');
const prevBtn = document.querySelector('.prev-btn');
const nextBtn = document.querySelector('.next-btn');
const progressFilled = document.querySelector('.progress-filled');
const volumeFilled = document.querySelector('.volume-filled');
const volumeBar = document.querySelector('.volume-bar');
const volumeBtn = document.querySelector('.volume-btn');
// --- 渲染函数 ---
function renderPlaylists() {
playlistGrid.innerHTML = playlists.map(p => `
<div class="playlist-item">
<img src="${p.cover}" alt="${p.name}">
<p class="play-count"><i class="fas fa-play"></i> ${p.playCount}</p>
<p>${p.name}</p>
</div>
`).join('');
}
function renderNewSongs() {
songList.innerHTML = newSongs.map(s => `
<div class="song-item">
<img src="${s.cover}" alt="${s.name}">
<div class="song-info">
<div class="song-name">${s.name}</div>
<div class="artist-name">${s.artist}</div>
</div>
</div>
`).join('');
}
function renderCharts() {
chartsContainer.innerHTML = charts.map(chart => `
<div class="chart-card">
<h3>${chart.name}</h3>
<ul class="chart-list">
${chart.songs.map(s => `
<li class="chart-item">
<span class="rank ${s.rank <= 3 ? 'top' : ''}">${s.rank}</span>
<div class="song-details">
<div class="song-name">${s.name}</div>
<div class="artist">${s.artist}</div>
</div>
</li>
`).join('')}
</ul>
</div>
`).join('');
}
// --- 事件监听器 ---
// 播放/暂停
let isPlaying = false;
playBtn.addEventListener('click', () => {
isPlaying = !isPlaying;
playBtn.classList.toggle('fa-play');
playBtn.classList.toggle('fa-pause');
});
// 上一首/下一首
prevBtn.addEventListener('click', () => {
console.log('上一首');
// 这里可以切换歌曲逻辑
});
nextBtn.addEventListener('click', () => {
console.log('下一首');
// 这里可以切换歌曲逻辑
});
// 进度条拖动(简化版)
let isDragging = false;
const progressTrack = document.querySelector('.progress-track');
progressTrack.addEventListener('click', (e) => {
const rect = progressTrack.getBoundingClientRect();
const offsetX = e.clientX - rect.left;
const percentage = (offsetX / rect.width) * 100;
progressFilled.style.width = `${percentage}%`;
});
// 音量控制
volumeBtn.addEventListener('click', () => {
volumeBar.classList.toggle('show');
});
document.addEventListener('click', (e) => {
if (!volumeBar.contains(e.target) && !volumeBtn.contains(e.target)) {
volumeBar.classList.remove('show');
}
});
const volumeTrack = document.querySelector('.volume-track');
volumeTrack.addEventListener('click', (e) => {
const rect = volumeTrack.getBoundingClientRect();
const offsetY = e.clientY - rect.top; // 音量条通常垂直,这里用Y轴
const percentage = 100 - (offsetY / rect.height) * 100; // 上大下小
volumeFilled.style.height = `${percentage}%`;
});
// --- 初始化页面 ---
renderPlaylists();
renderNewSongs();
renderCharts();
});
最终效果与如何运行
- 保存所有文件:确保
index.html,style.css, 和main.js文件都保存在正确的目录结构中。 - 打开
index.html:直接用浏览器(如 Chrome, Firefox, Edge)打开netease-music/index.html文件。
你将看到一个功能齐全的网易云音乐风格网页,包括静态布局和基础的交互功能。

(图片来源网络,侵删)
如何进一步改进?
这个版本是一个很好的起点,你可以继续扩展它:
- 真实API数据:使用网易云音乐的真实API(需要申请开发者密钥)来获取歌曲、歌单、排行榜等数据,替换掉模拟数据。
- 播放功能:使用HTML5的
<audio>标签来实现真正的音乐播放,当用户点击播放按钮或歌曲列表时,加载并播放对应的音频文件。 - 更复杂的交互:实现歌曲列表点击播放、切换歌曲时更新底部播放器信息、歌词滚动显示等。
- 响应式设计:使用媒体查询(
@media)让网页在手机和平板上也能有良好的显示效果。 - 动画效果:使用CSS
transition和animation或 JavaScript 库(如 GSAP)让页面动起来,比如菜单滑入、卡片悬浮效果等。 - 后端技术:如果需要用户登录、创建歌单、保存播放记录等功能,就需要引入 Node.js, Python (Django/Flask), PHP 等后端技术。
希望这个详细的教程能帮助你成功制作出自己的网易云音乐网页!
