news 2026/9/8 4:24:02

用纯HTML+CSS复刻网易云音乐首页:从零掌握flex与grid实战布局

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用纯HTML+CSS复刻网易云音乐首页:从零掌握flex与grid实战布局

简介:HTML+CSS实现网易云网站是一份适合前端初学者与网页设计练习者的静态站点案例,围绕用HTML搭建内容结构、用CSS完成视觉表现与响应式布局展开。压缩包为ZIP格式,共76个文件,约1.48MB,主要包含2个HTML入口页面(index.html与product.html)、21个CSS样式文件、多张PNG/JPG界面素材,以及woff2/ttf字体文件和Font Awesome图标库,目录将样式、图片、字体分开放置,便于对照学习。目前已有1308人学习下载。通过该项目可以看到导航栏、焦点图、商品展示区、页脚等典型模块的写法,还能练习语义化标签、CSS选择器、自定义字体引入、雪碧图与媒体查询等知识点。同时,页面中还引入了Font Awesome字体图标与多套自定义字体,帮助理解如何用字体文件增强界面视觉。由于是纯HTML+CSS实现,它既适合课程设计、期末作业,也适合作为前端入门后的综合演练,读者还可以从中提取出可复用的页面布局框架,用于自己的小型网站练习。 学完HTML和CSS基础,最尴尬的状态就是:会写标签,会用选择器,但一打开真实网站,还是不知道它那些界面到底是怎么搭出来的。今天这个项目就是来解决这个问题的——用纯HTML加上CSS复刻一个网易云音乐网站的静态首页。全程不写一行JavaScript,不引框架,不依赖任何现成UI库,就靠语义化标签、flex、grid、伪类、渐变这些最基础的东西,把页面从顶部导航一路还原到底部播放条。做完之后你会发现,那些看起来"很高端"的界面,底层逻辑其实没那么玄乎。

这个项目很适合两类人:一是刚把HTML、CSS语法过完一遍,急需一个完整实战来串知识点的初学者;二是想练"视觉还原能力"的人——拿到一个真实网站,知道怎么下手拆结构、怎么用布局属性去逼近设计稿。文章里涉及的所有代码都是静态演示性质,我会把每个模块的设计意图和踩坑点都摊开讲,你可以完全照着敲一遍,再换成自己的内容做改造。

1. 动手前先看页面再拆布局:网易云首页到底有哪几块

1.1 先看真实产品,别急着打开控制台

做仿站项目,最常见的错误就是一上来打开浏览器控制台,对着Elements面板里的DOM开始复制。这么干通常会立刻陷入泥潭——真实网站的HTML节点里混杂着大量框架注入、广告脚本、动态生成的class,那些类名既没有语义也没有规律,抄下来没有任何学习价值,还可能抄到一堆根本不该出现的结构。

我的建议是:把真实页面先当一张设计稿看。拿起笔在纸上或者脑海里做一次"区域划分"。网易云音乐首页从上到下、从左到右扫过去,信息层级其实很清晰:

  • 顶部红色区域,放着产品logo、搜索框、登录入口
  • 红色条下面的白色导航行,是"发现音乐、我的音乐、朋友、商城"这些菜单
  • 主内容区是个典型的两栏结构,左边宽、右边窄,左边主要放banner和推荐歌单,右边放热门歌手和用户相关信息
  • 再往下是页脚版权区
  • 还有一个永远固定在视口底部的黑色播放条

这一步做完,你已经完成了这个项目最重要的工作——把复杂界面拆成了4个可独立实现的模块。后面写代码就不是"面对一张网页发呆",而是逐个模块击破。

1.2 拆完后的结果:每个模块需要什么技术

做完区域划分后,还要给每个模块想一下"它最核心的布局难点是什么"。我当时拆出来的结果大概是这样的:

页面区域核心内容主要用到的CSS能力
红色顶栏logo、搜索框、按钮flex横向排列、input复位
白色导航行菜单项、下划线动效flex、伪元素、hover过渡
推荐歌单区多张封面卡片网格grid、圆角、阴影
右侧边栏歌手头像、文字信息flex纵向排列、nth-child序号
底部播放条歌曲信息、控制按钮、进度条fixed固定定位、毛玻璃背景

这种"先拆模块、再学技巧"的方式,比拿着标签库从头翻到尾有效得多。因为每个模块都有明确的目标,你用到一个属性时是带着问题的,印象会深很多。尤其是grid和flex,如果只是看文档,你很难判断什么时候用哪个;但当你面对"左侧固定宽度、右侧自适应"这种真实需求时,自然就理解了为什么选grid而不是flex。

2. HTML骨架:用语义化标签先搭出整页结构

2.1 页面模板与那些容易被忽略的meta

HTML是整个页面的骨架,CSS只是往骨架上贴的皮。骨架搭得是否合理,直接影响CSS写起来顺不顺手。先看最基础的文件头:

<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>仿网易云音乐首页</title> <link rel="stylesheet" href="css/style.css"> </head>

<!DOCTYPE html>这个声明很多人会漏,但它在HTML5里就一个作用:让浏览器以标准模式渲染页面。少了它,浏览器可能进入怪异模式,盒模型直接和你想的不一样,明明设了宽度却莫名其妙多出边距,排查时极其痛苦。lang="zh-cn"也别删,它影响屏幕阅读器和搜索引擎对页面语言的理解。

viewport这个meta在做纯PC端仿站时看似没用,但只要你把页面缩窄或拿到手机上看一眼,没有它页面就会默认按980px宽度缩放,字小到看不清。加上它至少保证移动端能正常横向滚动,不至于完全不能看。字符集声明用utf-8基本是标配,后面会专门说这个坑。

2.2 导航区:一个header里装两条导航行

网易云的顶栏和菜单行视觉上是两行,但在HTML结构上,我用一个<header>包住它们是合理的,因为它们在语义上都属于页头。

<header class="site-header"> <div class="top-bar"> <h1 class="logo">网易云音乐</h1> <input type="text" class="search-input" placeholder="搜索音乐、歌手、歌词"> <a href="#" class="login-link">登录</a> <a href="#" class="download-btn">下载客户端</a> </div> <nav class="main-nav"> <ul> <li><a href="#">发现音乐</a></li> <li><a href="#">我的音乐</a></li> <li><a href="#">朋友</a></li> <li><a href="#">商城</a></li> <li><a href="#">音乐人</a></li> </ul> </nav> </header>

这里有几个值得说的地方。logo我用<h1>而不是<div>,因为整个页面的最高层级标题就是品牌名,用h1对语义和SEO都更友好。主菜单用ulli而不是一排div,因为菜单本质上是一个列表,用无序列表是无障碍和语义化实践里的基本操作。之后做CSS时,把li设成flex子项,天然就是横排。

注意我没有给菜单项里的链接加实际href地址,因为这是仿站练习,不需要真实跳转,用href="#"占位即可。如果你希望点击能定位到页面内的某个具体模块,也可以把#替换成锚点id。

2.3 主体区域:main、section、aside的分工

主体内容我用<main>包住整个内容区,里面再做左右两栏。左侧用<section>放banner和推荐歌单,右侧用<aside>放歌手排行榜和入驻信息。这两个标签的语义差别值得好好体会:section表示页面主体里一个有主题的区块,aside表示与主体内容关系较弱的辅助内容——右侧栏在这个页面里正好符合这个定位。

<main class="page-main"> <div class="content-wrapper"> <section class="main-column"> <div class="banner">…轮播图区域…</div> <section class="playlist-section"> <h2>推荐歌单</h2> <div class="playlist-grid"> <div class="playlist-card">…歌单卡片×8…</div> </div> </section> </section> <aside class="side-column"> <section class="hot-singers"> <h2>热门歌手</h2> <ul class="singer-list">…歌手列表…</ul> </section> </aside> </div> </main>

banner区域我暂时用一个div占位,因为纯CSS模拟轮播很麻烦,这个项目里静态展示一张图就行。真正要学的是"推荐歌单"那一块——歌单卡片是一组结构完全相同的内容块,用同一个class反复复用,这是CSS类选择器最擅长的场景。

2.4 底部播放条的DOM怎么放才合适

播放条在视觉上永远固定在浏览器底部,但它在DOM里的位置不一定非要写在最后。我的习惯是放在<main>之前、header之后,或者直接放body最末尾。两种都可以,但你要保证它在任何父容器里都不会被overflow:hidden裁掉。

<div class="player-bar"> <div class="player-info"> <img src="images/cover.png" alt="歌曲封面"> <div class="player-meta"> <span class="song-name">认真的雪</span> <span class="song-author">薛之谦</span> </div> </div> <div class="player-controls"> <span class="ctrl-btn prev-btn"></span> <span class="ctrl-btn play-btn"></span> <span class="ctrl-btn next-btn"></span> </div> <div class="player-progress"> <div class="progress-bar"> <div class="progress-current"></div> </div> </div> </div>

播放条用fixed定位后,它会脱离文档流,不占正常布局空间,所以哪怕它在DOM中靠前,页面其余内容依然可以正常排列。把播放条放在body最后唯一的风险是:如果某个中间容器设置了transformfilter属性,fixed定位会相对那个容器而不是视口,这是很多人踩过的隐形坑。为了避免这种问题,最稳妥的做法是让播放条直接作为body的子元素,中间不要有任何设置了transform的父节点。

3. CSS布局实战:flex、grid和fixed定位的分工协作

3.1 顶部红条:flex让logo、搜索框、按钮站成一排

顶部红条是整个页面最容易出效果的部分。网易云的红不是纯红,偏暗带着一点沉稳感,我用#c20c0c作为主色。顶栏本身用flex布局,设置align-items:center让所有子项垂直居中:

.top-bar { display: flex; align-items: center; padding: 0 24px; height: 60px; background: #c20c0c; } .logo { margin-right: 30px; color: #fff; font-size: 24px; font-weight: bold; } .search-input { width: 180px; height: 28px; border: none; border-radius: 14px; padding: 0 14px 0 32px; background: rgba(255,255,255,0.2) url("data:image/svg+xml,...") no-repeat 8px center; color: #fff; font-size: 12px; } .search-input::placeholder { color: rgba(255,255,255,0.7); }

这里最值得讲的是搜索框。input本身继承了很多浏览器默认样式,border:noneoutline:none都要手动复位。圆角14px是高度28px的一半,直接把长方形变胶囊。背景我们可以用linear-gradient或者半透明白色加内联svg图标,不需要额外图片文件。放大镜图标我用background-image嵌一段svg,data URI方式的好处是零外部请求,适合练习。

3.2 菜单下划线动效:伪元素让它"活"起来

白色导航行里的菜单,真正的视觉记忆点是鼠标悬停或选中时,下方会出现一条红色下划线,而且是从左到右"长"出来的。用CSS实现这种动效,核心是::after伪元素加transform缩放:

.main-nav ul { display: flex; list-style: none; margin: 0; padding: 0; } .main-nav li a { position: relative; display: block; padding: 0 20px; line-height: 50px; color: #333; font-size: 14px; text-decoration: none; } .main-nav li a::after { content: ""; position: absolute; left: 0; bottom: 0; width: 100%; height: 3px; background: #c20c0c; transform: scaleX(0); transition: transform 0.3s ease; } .main-nav li a:hover::after { transform: scaleX(1); }

scaleX(0)做初始态、hover时变为scaleX(1),下划线就像被拉出来一样。为什么用transform而不是直接toggle宽度?因为transform的动画性能远好于改width——它不会触发layout和paint,页面元素多时能保持流畅。把transition写在默认态而不是hover态,可以保证鼠标移出时也有平滑的收起动画。

3.3 双栏主内容区:grid两列搞定一个经典页面格局

左侧宽、右侧窄的双栏结构是内容型网站的经典布局。用grid来实现非常直接:

.content-wrapper { display: grid; grid-template-columns: minmax(0, 1fr) 320px; column-gap: 20px; max-width: 1100px; margin: 0 auto; padding: 20px; }

左边minmax(0, 1fr)的意思是:这列的宽度是剩余空间的1份,但允许收缩到0,避免内容中的长单词或图片把布局撑破。右边固定320px,给侧边栏一个稳定宽度。两栏之间的间距用column-gap,省去给元素单独设margin的麻烦。

这里我顺手解决了一个初学者常见的疑问:什么时候用grid,什么时候用flex?简单判断标准是——如果你关心的是"一排多个怎么排",用flex;如果你关心的是"一个区域里行和列同时怎么排",用grid。双栏布局同时涉及行和列,grid更合适;而一个按钮组里三个按钮横排,用flex更顺手。

3.4 歌单卡片网格:用auto-fill实现自适应列数

推荐歌单那部分,需要展示8张甚至更多卡片。我用的方案是grid-template-columnsauto-fillminmax

.playlist-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 20px; } .playlist-card img { width: 100%; aspect-ratio: 1 / 1; border-radius: 8px; object-fit: cover; }

这个组合的威力在于:你完全不需要写媒体查询,浏览器会自动根据容器宽度计算每行能放几张卡片。卡片太窄时最小宽度140px会触发换行,宽度富余时每张卡片会自动拉伸。aspect-ratio是我认为所有新手都该早点学会的属性,它让正方形封面不再依赖padding-top hack,一行CSS就搞定高度和宽度的比例关系了。

歌单封面下面还要放标题和播放量。标题一行放不下时要用文字截断,播放量需要加一个小的三角播放图标,这些放到第4节细说。

3.5 底部播放条:fixed固定和毛玻璃背景

播放条是整个页面里层级最特殊的东西。固定到视口底部只需要两行关键代码:

.player-bar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 999; height: 60px; background: rgba(0, 0, 0, 0.8); backdrop-filter: blur(10px); display: flex; align-items: center; padding: 0 20px; color: #fff; }

黑色半透明背景配backdrop-filter: blur(10px),就是现在很多播放器那种毛玻璃效果。注意这个属性在某些旧浏览器上不支持,不过练习项目里无所谓,先体验效果。播放条内部还是老套路,三段式flex:左中右分别放歌曲信息、控制按钮、进度条。控制按钮里的圆形按钮我用一个公共class加不同背景图标实现,播放按钮那个三角形UI在下一节单独讲。

4. 还原网易云视觉风格的细节操作:伪类、渐变、三角形、文字截断

4.1 用border画播放按钮,告别图片依赖

播放按钮的三角形图标,很多新手第一反应是切一张png。其实用边框就能画:

.ico-play { width: 0; height: 0; border-left: 12px solid #fff; border-top: 8px solid transparent; border-bottom: 8px solid transparent; }

原理是:元素的width和height为0时,边框会围成一个矩形色块。如果其中一条边框有颜色且很宽,另外两条透明边框从两端压过来,就形成三角形。我们把左边框设为实色、上下边框设为透明,得到的是一个右朝向三角形。这个技巧在很多场景都通用——下拉箭头、音频播放按钮、分页器图标,都可以用它画出来,不需要额外请求图片资源。反过来说,把上边框画成实色、左右透明,就是下指箭头。

4.2 封面hover蒙层与播放按钮出现效果

真实网易云的歌单封面,鼠标放上去会盖一层半透明白色蒙层并浮出一个播放图标。这个交互非常适合练习伪类和透明度过渡:

.playlist-card { position: relative; } .playlist-card .mask { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.3); border-radius: 8px; opacity: 0; transition: opacity 0.3s; } .playlist-card .mask .play-icon { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } .playlist-card:hover .mask { opacity: 1; }

这里的关键是inset: 0,它是left/top/right/bottom都为0的简写,让蒙层铺满整个相对定位的封面容器。播放图标再通过translate(-50%,-50%)精确居中。蒙层用opacity控制显隐,配合transition有淡入效果。新手容易犯的错是把display:none当作隐藏手段——display切换时transition是不生效的,要隐藏元素又想有过渡动画,优先考虑opacity加visibility的组合,或者opacity加pointer-events:none。

4.3 标题文字的渐变效果

网易云的某些专题标题或者榜单名称,会有红色到橙色的渐变感。CSS做文字渐变有一个不算直观但很好用的套路:

.section-title { font-size: 22px; font-weight: 700; background: linear-gradient(90deg, #ec4141, #ff6a00); -webkit-background-clip: text; background-clip: text; color: transparent; }

核心是background-clip: text,它让背景只在文字笔画内部显示。而文字自身颜色设置为transparent,这样背景就从文字里透出来,形成渐变字。要提醒的是-webkit-background-clip这个带前缀的写法在部分浏览器里还是必须的,所以保留前缀兼容性更好。如果之后你做了多行文字渐变,记得背景尺寸和背景位置也要跟着处理,否则渐变会在换行处重新开始。

4.4 单行与多行文字截断

歌单标题、歌手名、歌名这种文本,经常需要限制宽度并截断。单行截断是基础中的基础:

.song-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

三个属性缺一不可。white-space: nowrap禁止换行,overflow: hidden把超出的部分藏掉,text-overflow: ellipsis告诉浏览器用省略号表示被截断的内容。推荐歌单如果希望最多显示两行、超出部分省略,用多行截断:

.playlist-desc { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

-webkit-line-clamp这个属性虽然带前缀,但在现代浏览器中已经广泛支持。它和单行截断的区别在于,它依赖-webkit-box布局模型,所以不能对其他display属性随意覆盖。

4.5 搜索框和链接的细节复位

最后还有一些"一眼决定成败"的细节。链接默认会有下划线,进入项目第一步就该写一个全局复位:

a { text-decoration: none; color: inherit; }

搜索框需要把光标聚焦时的蓝色外框去掉,或者换成与主题一致的红色系:

.search-input:focus { outline: none; border-color: transparent; }

如果觉得完全去掉outline对键盘用户不友好,可以用outline: 1px solid rgba(255,255,255,0.6)替代。另外,按钮的默认边框、input的默认字体,都要在项目里提前统一,否则不同浏览器渲染出来会有差异。这些细碎的东西看着小,但正是它们决定了成品是否"像那么回事"。

5. 仿站过程中容易踩的坑:实测排查与修复

5.1 为什么别直接复制官方样式表

我见过不少人做仿站项目时,直接右键页面源码把官方CSS文件下载下来引用。这其实完全违背了这个练习的初衷。官方样式表动辄几千行,大量class和线上业务绑定,复制下来后你根本不知道改了哪里会出什么问题,页面稍一变动就崩。仿站的价值在于"理解——重构"这个过程,你写出来的代码可能和官方完全不一样,只要视觉接近、结构合理,就是一次成功的练习。抄答案的仿站,做完之后你依然不会独立布局。

5.2 图片加载失败和路径问题

本地图片路径写错是静态页面最常遇到的事,症状就是图片显示成裂图。我建议所有图片路径都统一从项目根目录出发写,例如images/cover1.jpg,而不是./images/cover1.jpg,这样可以减少层级错乱。另外给每个img加上宽高和背景色兜底:图片加载失败时,这个元素不至于变成一条细线,至少能看到一个色块占位。属性上还可以加onerror="this.src='fallback.png'",不过纯HTML练习时我们尽量少碰内联JS,直接用CSS把背景色铺好就够了。

5.3 flex子项被压缩成一条线:flex-shrink的真相

主内容区卡片横排时,很容易出现"明明设了宽度,但子项还是挤成一团"的问题。这是因为flex容器里的子项默认flex-shrink: 1,当容器空间不足时,子项会按比例收缩。想要子项保持固定宽度,要么给父级设置flex-wrap: wrap让子项换行,要么给子项设flex-shrink: 0。我实践下来的习惯是:卡片网格优先用grid(自动换行天然友好),按钮组和导航用flex并把flex-shrink设为0。知道了这个属性背后的逻辑,排查布局被压缩的问题就是一分钟的事。

5.4 外边距塌陷和字符集乱码

写CSS时,父容器里第一个子元素的margin-top会"穿透"到父容器上,导致父容器整体下移,这就是外边距塌陷。解决方式很直接:给父容器加padding-topborder-top或者设置display: flow-root。后者是更现代的方案,副作用最小。字符集方面,HTML文件如果没保存成utf-8编码,即使写了<meta charset="utf-8">也可能乱码。很多编辑器默认保存ANSI编码,中文注释会变成乱码,检查时先确认编辑器右下角的编码格式是UTF-8。

5.5 快速验证和调试习惯

最后分享一个我很受用的调试习惯:每完成一个模块,就单独给这个模块加一个临时背景色或者outline,看它在页面里的占位是否符合预期。比如导航做完了,先给header加一个亮色背景确认宽度是100%;内容区做完了,临时给grid容器加outline: 2px dashed,确认两栏宽度和间距对不对。这种"看得见边界"的调试方式,比对着控制台数值空想高效得多。全部模块做完之后,再把临时颜色一行一行删掉,替换成最终样式。

这个项目做完,你会发现自己对flex、grid、伪元素这些概念的掌握程度完全不一样了。之后再做仿站,建议选择一个比网易云首页更复杂的页面,比如某电商详情页或者视频网站首页,用同样的流程拆解、搭骨架、写布局、抠细节,每做完一个,你的CSS实战能力都会实打实上一个台阶。我个人的体会是:基础语法看十遍不如动手做一个完整页面,尤其是把页面拆成模块、再用布局实现它的过程,才是从"会读代码"到"会写页面"最关键的转折点。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 4:22:21

程序化建模实战:让AI写代码生成可靠3D模型

先讲个真实经历。上个月我需要一个带法兰边的异形管道接头&#xff0c;第一反应是让 AI 直接生成 3D 模型。折腾了半小时&#xff0c;模型倒是“像那么回事”&#xff0c;但一导入工程软件就露馅&#xff1a;面是碎的、尺寸标注全是小数、布尔运算之后甚至出现悬空点。我换了个…

作者头像 李华
网站建设 2026/9/8 4:18:55

Kimi API实战:从IDE接入到智能体开发的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 4:15:44

毕业论文降重与改写全攻略:从同义词替换到AI工具的进阶之路

1. 引言&#xff1a;毕业论文修改&#xff0c;为何如此纠结&#xff1f; 在即将提交毕业论文的关键时刻&#xff0c;面对众多文本修改方式的选择&#xff0c;我和我的同学们常常感到迷茫。是否应该依赖传统的同义词替换&#xff0c;还是试试通用大模型辅助改写&#xff0c;又或…

作者头像 李华
网站建设 2026/9/8 4:15:27

EmEditor便携版实战:解压配置与超大日志文件秒开技巧

简介&#xff1a;EmEditor 20.6.0 便携版是面向 Windows 10 用户的高效文本编辑器&#xff0c;凭借轻量运行与强大扩展能力&#xff0c;被许多程序员和高级用户选为系统记事本的替代品。它支持打开数 GB 级大文件而不易崩溃&#xff0c;并提供多种编程语言的语法高亮与常用编码…

作者头像 李华
网站建设 2026/9/8 4:14:18

Agent Harness 核心实践:上下文压缩与动态记忆实现详解

前阵子做 Agent 项目落地时&#xff0c;我一直被几个问题反复折磨&#xff1a;Agent 跑着跑着上下文就超限了&#xff0c;长对话后模型开始“失忆”&#xff0c;工具调用链路一长就出现各种莫名其妙的终止报错。最开始我以为是模型能力不行&#xff0c;后来把问题拆开排查才发现…

作者头像 李华