简介:学成在线案例的PSD设计素材与前端代码包来自黑马程序员培训课程,面向正在学习HTML和CSS的初学者及希望提升页面还原能力的前端开发者。整套资源以学成在线网站为原型,将设计稿与代码对照呈现,便于理解从PSD切图到页面结构的完整流程。压缩包共11个文件,含4个PSD源文件(覆盖首页、课程列表页、课程介绍页、职业规划页)、1个HTML页面、1个CSS样式表以及5张PNG切图素材,整体约17.71MB,体量适中,适合直接本地打开研习。目前已有14050人学习下载,在同类前端案例资源中关注度较高。通过这套素材可练习多图层设计稿的拆解与图标Banner切图技巧,并对照实际代码理解布局和配色如何落地为可运行的网页。
1. 学成在线这套 PSD 与代码资源,值不值得花时间拆
拿到「学成在线 PSD 素材及代码」这套资源的人,心里多半带着同一个疑问:这到底是一份能直接上手的实战项目,还是一堆需要二次加工的素材包?我在本地完整过了一遍之后可以负责任地说,它的定位介于「设计稿还原练习」和「课程项目脚手架」之间——PSD 里沉淀了首页、列表页、详情页的完整视觉方案,代码里则给出了静态页面和基础交互,两者合在一起就是一个可以反复拆解的前端练手样本。
这套资源最能解决的问题,是让学习者绕开「设计稿从哪来」的尴尬:不用再对着网上的模糊截图猜布局,也不用自己在设计工具里从零搭界面。适合三类人——正准备找工作、想拿一个完整项目撑起作品集的前端新人;需要练切图和还原能力的工程师;以及想研究在线教育类产品信息架构的产品或 UI 从业者。需要提前说明的是,素材里的代码并不是现代工程化项目的完整形态,它的价值在于给你一个可控的起点:你能在它的基础上补充构建工具链、接上真实接口,最终变成一个能部署的完整项目。
2. 拆解 PSD 素材:先搞清楚设计稿里藏着什么,再动手切图
拿到 PSD 素材,第一件事不是急着打开 Photoshop 拉参考线,而是先建立一套资源认知框架。很多人的第一反应是「不就是切图吗」,结果切到一半发现导航栏的图标缺了 hover 态、 banner 区域的背景色和标注尺寸对不上,整个还原过程被迫返工。这一章会手把手带你走完 PSD 的拆解流程,并给出一个可复用的资源管理清单。
2.1 图层结构分析:分清「骨架层」和「皮肤层」
打开 PSD 后,你需要先做一次图层结构体检。一个规范的在线教育类设计稿,通常会把图层组织成四个大组:布局骨架(header、footer、内容容器)、模块组件(课程卡片、轮播图、导航菜单)、状态样式(hover、active、选中态)、以及切图资源(图标、背景纹理、装饰元素)。你要做的第一步是把这四个大组在图层面板里标记出来,搞清楚哪些是结构必须的,哪些只是视觉装饰。
图层结构这个东西,很多人觉得「看得见就行了,何必分析」,但实际上它直接决定你后续切图的效率。如果设计稿里每个图层的命名是清晰的(比如icon/arrow-right.png、btn/bg-primary),你可以直接用脚本批量导出资源;如果命名混乱(常见的是图层 1 副本 3这种命名),你就需要手动重建一套命名规则。常见做法是:先建立一套「类型/模块/状态」的命名规范,例如icon/course/arrow-left-normal,然后分模块整理到单独的 PSD 图层组里,而不是在一个巨型 PSD 里反复缩放查找。
# 用像素测量工具快速检查设计稿中的关键尺寸 # 以 macOS 自带工具为例,截取设计稿关键区域后读取宽高 sips -g pixelWidth -g pixelHeight course-banner.psd # 输出示例: # pixelWidth: 1920 # pixelHeight: 600这段命令的作用是快速验证 PSD 画布尺寸是否符合预期。常见情况是 PSD 的画布是 1920 宽,但实际内容容器只有 1200 宽,这两种宽度对应不同的 CSS 布局策略。参数说明:-g用于读取图像属性,pixelWidth和pixelHeight分别对应像素宽高。如果你用的是 Windows,也可以直接在设计工具里查看画布信息,效果一样。这个检查的意义在于,它决定你用固定宽度还是弹性布局来还原页面。
2.2 切图规范与资源导出:满足多倍屏需求的实用做法
切图是 PSD 素材里最容易翻车的一环,翻车点不在「切不切得出来」,而在「切出来的东西能不能用」。设计稿里的字号是 16px,你在普通屏上切一张 16px 的图标,放到 2 倍屏上就糊了。标准做法是——先确定设计稿的基准尺寸。一般来说,在线教育类平台的 PSD 设计稿会有三种版本:1 倍图(最小,用来标注)、2 倍图(用于 iOS 和大部分安卓)、3 倍图(用于超高分辨率屏幕)。你需要先查询设计稿的实际像素尺寸,再决定导出倍率。
# 常见做法:一次导出多倍率资源 # 假设原始图标尺寸为 24x24,需要输出 1x、2x、3x 三套资源 mkdir -p assets/icon/1x assets/icon/2x assets/icon/3x # 用设计工具导出后,按目录归位,命名保持语义一致 # 例如:ic-course-arrow.png (1x), ic-course-arrow@2x.png (2x), ic-course-arrow@3x.png (3x)导出多倍率资源的核心逻辑不是「导出三份文件」,而是「保证同一份视觉在不同 DPR 下的显示一致性」。参数说明:@2x和@3x后缀是 iOS 生态的习惯命名,Web 端可以直接用image-set()或srcset来切换。需要特别留意的是,并不是所有资源都需要切三份。纯色背景、渐变、简单边框这类资源,用 CSS 绘制比切图更高效,也更容易维护。我一般会在切图前做一个分类:纯图标类切透明 PNG,复杂插画类切 JPG 或 WebP,渐变和圆角背景用 CSS 实现。
2.3 从 PSD 中提取设计令牌:颜色、字体、间距的量化
切图只是 PSD 拆解的一部分,真正决定还原度的是「设计令牌」——颜色值、字体规格、间距体系。设计稿里可能用了一整套看似差不多的灰色,肉眼看着都是浅灰,但实际有五种以上的不同色值。如果直接照着感觉写 CSS,后续改版时就会发现「为什么这里颜色怪怪的」。
常见做法是,在 Photoshop 里用吸管工具逐个提取关键色彩,记录到表格里,再转成 CSS 变量。
| 令牌名称 | 色值 | 用途 |
|---|---|---|
--color-primary | #FF7D2C | 主按钮、价格强调、导航激活态 |
--color-primary-light | #FFA55C | hover 态、渐变背景 |
--color-text-main | #333333 | 标题、正文主要文本 |
--color-text-sub | #666666 | 描述文本、次要信息 |
--color-bg-page | #F5F5F5 | 页面背景、间隔区域 |
--color-border | #E8E8E8 | 卡片描边、分割线 |
这个表看起来简单,但它是后续所有 CSS 变量定义的来源。操作时要注意:不同工具的颜色配置文件可能导致同一 PSD 在屏幕上显示的色彩有差异,所以建议统一在一个设计工具里取色,并且打开「颜色设置」里的 sRGB 配置。第二个要注意的是间距。如果设计稿里模块间距是「10 的倍数」,说明设计师用了一个基础的 8pt / 4px 栅格系统,你可以在 CSS 里定义--space-unit: 8px这样的间距基数,后续所有 margin 和 padding 都从基数派生,避免还原过程中出现间距不统一。字体的提取相对简单,记录字号、字重、行高三件套即可。
3. 把 PSD 还原成静态页面:从页面结构到 CSS 落地的完整路径
资源拆解清楚之后,下一步就是动手写代码。这一章的核心目标是:把你从 PSD 中看到的视觉,转换成一个语义化、可维护的静态页面。很多人一上来就写 CSS,写到一半发现布局撑不住,其实就是没先建立结构化的页面骨架。这里的思路是:先画 DOM 结构,再填样式,最后处理交互状态。
3.1 页面结构化:手写 HTML 骨架的要点与常用结构
在开始写 HTML 之前,先看设计稿的布局规律。在线教育类页面通常包含顶部导航(Logo + 导航菜单 + 用户操作区)、主视觉 Banner 区、课程分类入口、课程卡片列表、底部信息栏。你需要在 HTML 里用语义化标签把这些区块划分出来。
<!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> <body> <!-- 顶部导航 --> <header class="site-header"> <div class="container header-container"> <h1 class="logo"> <a href="/" aria-label="学成在线首页"> <img src="assets/logo.png" alt="学成在线" /> </a> </h1> <nav class="main-nav" aria-label="主导航"> <ul> <li><a href="#" class="active">首页</a></li> <li><a href="#">课程</a></li> <li><a href="#">名师</a></li> <li><a href="#">关于</a></li> </ul> </nav> <div class="user-actions"> <a href="#" class="btn btn-primary">登录</a> <a href="#" class="btn btn-ghost">注册</a> </div> </div> </header> <!-- 主视觉 Banner --> <section class="hero" aria-label="推荐课程"> <div class="container hero-content"> <h2>学成在线,专注职业提升</h2> <p>精选热门课程,从入门到精通,助你快速成长</p> <a href="#" class="btn btn-lg btn-primary">立即学习</a> </div> </section> <!-- 课程卡片列表 --> <main class="course-section"> <div class="container"> <div class="section-header"> <h2>热门课程</h2> <a href="#" class="section-link">查看全部</a> </div> <ul class="course-grid"> <li class="course-card"> <a href="#"> <img src="assets/course-cover-01.jpg" alt="前端开发入门" /> <div class="course-info"> <h3>前端开发入门与实战</h3> <p class="meta">共 120 课时 | 已更新至第 80 节</p> <div class="price-row"> <span class="price">¥ 199</span> <span class="rating">评分 4.9</span> </div> </div> </a> </li> <!-- 更多课程卡片按同一结构重复 --> </ul> </div> </main> <!-- 底部信息 --> <footer class="site-footer"> <div class="container footer-container"> <p>关于我们 | 帮助中心 | 隐私政策</p> <p>© 学成在线 保留所有权利</p> </div> </footer> </body> </html>这段结构基本复刻了设计稿的页面骨架,有几个细节值得说明。header、main、footer这些语义化标签不只是为了可读性,还对 SEO 和辅助技术友好。Banner 区域的文字层级用h1 > p > a的顺序呈现,符合视觉焦点到行动按钮的阅读动线。课程卡片使用列表结构而非一个个独立的div,是因为从语义上讲它们是一个并列的课程集合,用ul > li更合理,也方便后续做列表渲染。参数或类名上,.container是常见的居中容器类,建议统一设置最大宽度为 1200px,与设计稿的内容区宽度对齐。
3.2 布局落地的三种方案:浮动、Flex、Grid 怎么选
写完了 HTML 骨架,接下来要处理布局。学成在线这类页面里,既有复杂的整体页面布局(比如顶部导航 + 内容主体 + 底部),也有相对独立的模块布局(课程卡片横向排列)。不同尺度的布局,应该用不同技术方案来处理。
课程卡片横向排列是典型的 Flexbox 应用场景——一排四张卡片,间距统一,卡片内的信息纵向排布。而整个页面的布局骨架(头部固定 / 内容自适应 / 底部在底部)则适合用 Grid 来搭,因为 Grid 擅长二维布局控制。浮动在这个项目里其实已经没有太多必要,除非你要兼容非常老的浏览器。给你一份选型参考:
| 布局规模 | 推荐方案 | 理由 |
|---|---|---|
| 页面整体骨架 | CSS Grid | 直接划分行 / 列区域,代码可读性高 |
| 模块内排列(课程卡片 / 导航菜单) | Flexbox | 一维排列 + 间距控制简单,适配性强 |
| 文字环绕图片 | Float | 特殊排版需求,当前项目基本用不到 |
用 Flex 实现课程卡片列表时,最常用的几个属性是display: flex、flex-wrap: wrap、gap: 20px。gap替代了旧的margin方案,节省了「最后一个元素去掉多余 margin」的 hack。用 Grid 搭页面骨架时,焦点在grid-template-areas上,比如把页面分成header、main、footer三行,代码意图比单纯的grid-row更直观。
3.3 状态与交互样式:伪类、伪元素在静态还原中的常见用法
静态还原不等于只是把视觉像素对齐,交互状态也是设计稿的一部分。PSD 里通常会给出按钮或者课程卡片的默认态和 hover 态。在代码里,这些状态通常通过伪类选择器来实现。初学者常犯的错误是给每个状态单独写一个 class,然后靠 JavaScript 切换,但其实纯 CSS 就能覆盖大部分场景。
/* 课程卡片的默认样式与悬停状态 */ .course-card { background: #ffffff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); transition: transform 0.25s ease, box-shadow 0.25s ease; } .course-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1); } /* 导航菜单的当前项与悬停项 */ .main-nav ul li a { display: inline-block; padding: 8px 16px; color: #333333; text-decoration: none; position: relative; } .main-nav ul li a::after { content: ''; position: absolute; left: 16px; right: 16px; bottom: 2px; height: 2px; background-color: #FF7D2C; transform: scaleX(0); transition: transform 0.2s ease; } .main-nav ul li a:hover::after, .main-nav ul li a.active::after { transform: scaleX(1); }这段 CSS 做的是两件事:课程卡片的浮起反馈(translateY上移 + 阴影加深),以及导航菜单底部的下划线滑动效果(用::after伪元素配合scaleX实现)。参数说明:transition里的0.25s ease是一个视觉上不拖沓也不生硬的时间长度;transform和box-shadow是可控动画的属性,不会引起强制重排,动画性能表现更好。伪元素::after在这里不是装饰,而是给「当前所在位置」提供视觉锚点。实际工程中,active类由路由系统生成,而:hover样式则全部由 CSS 托管。这样分离之后,前端的交互逻辑就只需要关心状态切换,不需要在 JavaScript 里写行内样式。
4. 从静态页到可运行项目:工程化改造与联调准备
当静态页面完成,剩下的工作就不再是「能不能看到」,而是「通不通得过」。一个只靠浏览器打开本地 HTML 的页面,既没法点出动态效果,也没法接上后端数据。要让这套代码变成一个可运行的项目,至少要做三件事:补上构建工具、把硬编码数据抽离成模拟接口、拆出可复用的组件结构。
4.1 构建工具选型与初始化:Vite 作为基础运行环境
现在的前端项目已经不是「写几个 HTML 文件 + CSS + JS 就能交付」的形态了。课程大作业或作品集项目如果还停留在双机打开 HTML 文件的阶段,面试时大概率会被问住——工程化是底线,不是加分项。在不引入过重依赖的前提下,Vite 是当前环境下快速把静态页工程化的最佳选择。
# 在静态页面目录下初始化 Vite 项目 npm init -y npm install vite --save-dev # 配置 package.json 中的启动脚本 # "scripts": { # "dev": "vite --host 0.0.0.0 --port 5173", # "build": "vite build", # "preview": "vite preview" # }初始化 Vite 的重点在于调整package.json的脚本字段。--host 0.0.0.0让项目可以被局域网内其他设备访问,方便在真机或协作场景下验证页面;--port 5173是 Vite 的默认端口。参数说明:如果你在 Windows 环境下,端口可能被占用,可以改成--port 5174或其他空闲端口。完成初始化后,把原来的index.html移动到项目根目录,并在其中确认 CSS 和 JS 文件路径是否以/开头,否则构建时可能找不到文件。这一步处理完之后,npm run dev就能跑起来,页面保持热更新,改样式立刻能看效果。
4.2 数据层抽取:用 mock 数据替代 PSD 里的硬编码内容
静态页面里写死的课程列表、名师介绍、价格数据,在工程化改造时必须抽离。原因很简单——你后续如果接了真实接口,页面结构不需要动,只需要替换数据源。更现实的好处是:抽离之后,课程列表的增删只需要操作一个数据文件,不需要在 HTML 里复制黏贴整块卡片结构。
// mock/course.js export const courseList = [ { id: 1, title: '前端开发入门与实战', cover: '/assets/course-cover-01.jpg', lessons: 120, currentLessons: 80, price: 199, originalPrice: 399, rating: 4.9, students: 2380, }, { id: 2, title: 'Python 数据分析快速上手', cover: '/assets/course-cover-02.jpg', lessons: 86, currentLessons: 60, price: 159, originalPrice: 299, rating: 4.8, students: 1860, }, // 更多课程数据... ]; // 通过函数返回,方便后续直接替换为请求真实接口 export function fetchCourseList() { return Promise.resolve(courseList); }这个 mock 模块是后续联调的关键接口。它的作用不是替后端写逻辑,而是模拟一个异步数据源,让你的渲染层代码从一开始就走的是「请求数据 → 渲染列表」的路径。参数说明:lessons和currentLessons对应设计稿的「总课时 / 已更新课时」,这两个字段可以在页面上渲染出一个进度条;originalPrice字段用于展示划线价,和price配合完成价格锚点视觉。Promise.resolve让数据返回方式与真实接口保持一致,后续换fetch请求时页面代码不需要重写。抽离完成之后,把首页课程卡片区域的 HTML 改成循环渲染的模板,这一步是在锻炼「数据和视图分离」的思维。
4.3 响应式适配:在 375 到 1440 之间不穿帮
「学成在线」这类在线教育站点的访客有很大比例来自移动端,如果设计稿只覆盖了 1920 宽的桌面端,走查时打开手机模拟器大概率会翻车。响应式适配需要关注的断点有三个:手机竖屏(375 宽度)、平板竖屏(768 宽度)、桌面端(1200+ 宽度)。常见做法是移动优先,先写基础样式,再用min-width断点升级。
/* 基础样式(面向移动端) */ .course-grid { display: grid; grid-template-columns: 1fr; gap: 16px; } /* 平板及以上:一行两列 */ @media (min-width: 768px) { .course-grid { grid-template-columns: repeat(2, 1fr); } } /* 桌面端:一行四列 */ @media (min-width: 1200px) { .course-grid { grid-template-columns: repeat(4, 1fr); gap: 20px; } }这里用的是移动优先的断点策略。1fr表示卡片占满容器一整列,在窄屏下单列长卡片更容易阅读;随着视口宽度增加,通过repeat(2, 1fr)和repeat(4, 1fr)切换列数。参数说明:断点数值不要随意定,常用的参考值是 375 / 768 / 1200,分别对应主流手机、平板、笔记本和桌面显示器的内容宽度。另一个隐藏细节是字号本身也应响应式变化:大屏页面标题可以用 32px,移动端缩到 24px,如果设计稿里没有给出这套规则,你可以按照比例缩放,保持视觉层级不塌陷。
5. 学成在线 PSD 与代码落地:7 个典型踩坑与排查记录
任何真实项目都会在还原和改造的过程中遇到问题,这一章我整理了 7 个最常见的踩坑场景,每一个都按「现象 → 原因 → 解决」的顺序复盘。这些坑来自实际开发中的问题排查,适合在本地验证时对照查看。
5.1 字体渲染总感觉「少了那么点味道」
现象:页面在开发环境里看起来和 PSD 原稿差距不大,但总觉得字体形态不对,也说不上哪里不对。
原因:设计稿里使用的字体(比如「思源黑体」)在开发机器上没有安装,浏览器会回退到系统默认的中文字体,导致字形和间距发生变化。
解决:把设计稿中出现的字体写进 CSS 的font-family堆栈中,并将字体文件(如果授权允许)以font-face的形式引入项目。
@font-face { font-family: 'SourceHanSansCN'; src: url('/fonts/SourceHanSansCN-Regular.woff2') format('woff2'), url('/fonts/SourceHanSansCN-Regular.woff') format('woff'); font-weight: 400; font-display: swap; } body { font-family: 'SourceHanSansCN', 'PingFang SC', 'Microsoft YaHei', sans-serif; }关键点在于font-display: swap这个属性——它让文字在自定义字体加载完成之前先用系统字体渲染,避免白屏。参数说明:.woff2格式体积最小,现代浏览器均支持,woff作为备用;字体文件建议放在项目内部而不是使用外链,因为在本地联调和离线演示时外链不可用。如果字体体积过大(超过 1MB),考虑只引入用到的字重,避免首屏加载被拖慢。场景建议:检查设计稿时,右键文字图层查看字体族,逐项核对本地是否有对应字体,如果没有就统一走@font-face。
5.2 图片切出来之后在页面上发虚
现象:从 PSD 里导出的 Logo 或图标,放到页面上显示模糊,尤其在高分屏上更明显。
原因:导出时按 1 倍图导出,页面却展示了放大 2 倍的效果,位图被浏览器拉伸导致边缘锯齿和发虚。
解决:导出资源时按 2 倍尺寸导出,用 CSS 控制显示尺寸为原设计的一半。
.logo img { width: 120px; height: 40px; }思路是这样的:如果设计稿里 Logo 的视觉宽度是 60px,你在设计工具里导出一张 120px 宽的图片(即 2x 资源),然后在 CSS 里把图片显示宽度设为 60px。这样在高分屏上,浏览器用 120px 的图片渲染 60px 的视觉效果,画面就会保持锐利。注意:CSS 里的width和height要同时设置,避免图片因默认自适应宽度而超出容器。如果图片反复调整尺寸,干脆用max-width: 100%配合容器宽度控制,省去每次手工换算。图标类建议保留透明背景的 PNG,尽量不用 JPG,否则深色背景下会出现难看的白底矩形。
5.3 flex 布局导致卡片底部没有对齐
现象:一排课程卡片长度不同,有的卡片被拉长了,或者卡片底部的价格区域没对齐。
原因:Flex 容器里的项目在align-items: stretch(默认值)下会等高拉伸,但卡片内部不同区域的元素高度没有撑满,导致底部视觉不齐。
解决:设置align-items: flex-start让项目不拉伸,再让卡片内部采用 flex 纵向布局来填充空间。
.course-grid { display: flex; flex-wrap: wrap; align-items: flex-start; /* 防止卡片被强制拉伸 */ } .course-card { display: flex; flex-direction: column; height: 100%; } .course-info { display: flex; flex-direction: column; flex: 1; }这段方案的关键是两层搭配:外层用align-items: flex-start避免列等高强制拉伸;内层把卡片变成纵向 flex,让.course-info获得flex: 1后自动撑满剩余空间,从而把价格行固定到底部。参数说明:flex: 1表示flex-grow: 1的简写,含义是「占用剩余空间」。如果不加这一行,内容矮的卡片价格位置就会悬在半空。排查建议:在浏览器开发者工具里选中卡片元素,查看 flex 容器和项目的计算高度,能直观看出是哪个元素没有填满。
5.4 背景色差在屏幕上无法忽视
现象:页面的主色和 PSD 原稿颜色肉眼可见地不一样,设计稿偏暖,页面偏冷。
原因:Photoshop / 设计工具的颜色配置与浏览器的色彩管理不一致,常见于设计稿用了非 sRGB 的色彩配置,或 CSS 中颜色值直接复制粘贴错了。
解决:统一取色和写码的流程。取色时在 Photoshop 里手动确认 RGB 值后再填入 CSS;CSS 中统一使用十六进制或rgb()格式,不要混用多种格式。
操作上最稳妥的做法是:把设计稿中提取出来的主色值写进表格,逐个复制进 CSS 变量。如果你发现取色工具默认显示的颜色模式是 Lab 或 HSB,切换成 RGB 显示。排查时,用截图工具分别取设计稿和浏览器渲染后的颜色,对比 RGB 数值差异,就能定位是取色错误还是环境配置问题。参数建议:设计稿的编辑颜色模式设为 sRGB,浏览器渲染默认也基于 sRGB,两边对齐后色差基本可以消除。
5.5 页面在同一宽度下缩放比例异常
现象:把浏览器窗口拉窄,页面出现横向滚动条,或者卡片间距过大、排版怪异。
原因:没有预留设计稿的最小宽度限制。PSD 设计稿通常基于固定宽度(比如 1200px),直接压缩到 800px 时布局没有断点规则,就会错乱。
解决:先给大屏容器设置min-width: 1200px,在小屏断点下再释放该限制。
.container { max-width: 1200px; margin: 0 auto; min-width: 960px; /* 桌面端最小宽度,避免布局压缩变形 */ } @media (max-width: 768px) { .container { min-width: 0; /* 小屏下不再限制,交给弹性布局 */ } }min-width: 960px保证在 1024px 的笔记本屏幕上,内容不会挤压成「中间窄、两侧空」的怪样子。参数说明:最小宽度值的选取来自设计稿的栅格系统——如果设计稿在 1200px 下正好容纳四列卡片,那么最小宽度设为 960px 就足够保持三列布局,再低才切换断点。这个方案的缺点是移动端需要绕开min-width限制,所以断点处记得把它重置为0。养成习惯:写完布局后在 1024、768、375 三个宽度下快速扫一遍,大多数缩放问题都能提前发现。
5.6 切图素材和代码里的文件名对不上
现象:本地静态页面打开时大量图片裂开,控制台报 404,检查路径后发现文件都在,但名字对不上。
原因:切图导出时命名不规范(比如未标题-1.png),代码里又写成了语义化名称(course-cover-01.jpg),两者完全脱节。
解决:切图导出前先建好一份「资源命名映射表」,导出后按映射表统一改名再放入项目目录。
实际操作中,建议按模块-子模块-用途的格式命名。例如 Banner 区域的背景图为banner-hero-bg.jpg;课程卡片的封面为course-cover-01.jpg;导航图标的 hover 态为nav-icon-arrow-hover.png。命名虽然看起来繁琐,但项目跑起来后维护成本反而低。排查时,直接在浏览器开发者工具里找到裂开图片的网络请求路径,和本地文件路径做比对,差异立即显现。预防方法:每次导出后,先跑一个脚本比对assets目录下的文件名与 HTML 里的引用列表,有出入立刻修正。
5.7 底部留白异常:footer 没有吸到页面底部
现象:当页面内容不够高时,footer 跟着内容一起往上跑,页面底部出现一大片空白。
原因:整个页面的高度由内容撑开,footer 位于文档流的末尾,高度不足时自然就飘在中间。
解决:用 flex 栅格或min-height控制页面整体高度,让 footer 在内容不足时仍然贴在视口底部。
body { min-height: 100vh; display: flex; flex-direction: column; } main { flex: 1; }这里的关键是min-height: 100vh——让body至少等于视口高度,flex: 1让main区域吃满剩余空间,把 footer 推送到底部。参数说明:100vh在移动端浏览器上可能因为地址栏显隐而出现跳动,但作为基础方案它是简单有效的。如果你是移动端深度适配,可以用100dvh代替100vh,后者能更准确地反映动态视口高度。这个方案相比传统的「footer 固定定位 + padding」好在不用计算 footer 高度,结构变化时不容易翻车。
6. 把这套素材的价值榨干:三个进阶技巧与我的使用心得
到这里,你已经完成了 PSD 素材的拆解、静态页还原、工程化改造和常见坑的排查。但如果你只是照着做一遍,这套资源的价值只发挥了四成。剩下的六成,在于怎么把它变成你的作品集亮点或持续迭代的练习场。这一章分享三个进阶技巧,最后一个收尾。
6.1 技巧一:用组件化思路重写原来的静态页面
如果你准备把学成在线作为作品集项目,建议你把原本十几段重复的课程卡片 HTML 抽成可复用的组件代码。比如在原代码里反复出现的「课程卡片结构」,用一个函数或模板文件统一生成。
function renderCourseCard(course) { return ` <li class="course-card"> <a href="/course/${course.id}"> <img src="${course.cover}" alt="${course.title}" loading="lazy" /> <div class="course-info"> <h3>${course.title}</h3> <p class="meta">共 ${course.lessons} 课时 | 已更新至第 ${course.currentLessons} 节</p> <div class="price-row"> <span class="price">¥ ${course.price}</span> <span class="rating">评分 ${course.rating}</span> </div> </div> </a> </li> `; } document.querySelector('.course-grid').innerHTML = courseList .map(renderCourseCard) .join('');这个方案的核心收获不是代码量减少,而是让你提前习惯「数据驱动视图」的思维方式。注意loading="lazy"这个属性——它是一个不需要额外脚本的原生懒加载方案,页面底部图片较多时效果明显。如果你后续引入 Vue 或 React,组件的边界和这个函数的边界是类似的:输入一个course对象,输出一段结构化视图。
6.2 技巧二:用 PSD 原文校验页面还原度
改完页面之后,怎么验证还原度?肉眼一遍遍看很容易疲劳,而且看久了会产生「差不多」的错觉。我建议做一个标准化走查:在浏览器里截图页面,传到设计工具里和原 PSD 做半透明叠加对比。
具体做法是:浏览器打开页面后,用截图工具截取整个首屏;把截图粘贴到设计工具里作为新图层,调整透明度至 50%,然后放到原始 PSD 图层上对齐。这时两者的差异会非常直观——间距偏差、颜色偏差、文字位置偏差都会暴露出来。如果你的设计工具支持「差值」混合模式,叠加后的黑色区域表示完全一致,灰色区域表示有偏差,对照偏差区域逐个修正效率会高很多。这个习惯如果能保持到项目上线,你就不会再犯「凭感觉验收」的毛病。
6.3 技巧三:维护一套「素材 - 代码」对照归档
第三个技巧和代码关系不大,但长期价值最高——建立一套素材与代码文件的对照归档习惯。具体做法是:把 PSD 素材、切图源文件、最终构建产物放在同一个目录结构下,做到「看到文件路径就知道它对应页面上的哪个区块」。
xc-online/ ├── design/ │ ├── 首页.psd │ ├── 课程列表页.psd │ └── 课程详情页.psd ├── assets/ │ ├── icon/ │ ├── cover/ │ └── banner/ ├── mock/ │ └── course.js ├── css/ │ └── style.css └── index.html这个归档习惯的意义在于:任何一次切图、改需求、修 bug 都能快速定位到改动点,不用在文件堆里翻找。尤其是当你在一个团队协作或持续迭代的场景里,不会因为「文件名对不上」或「不知道这个 PSD 是哪个版本」而内耗。
最后说一个我自己的血泪教训:最初我拿到类似素材时,总想把每个图层、每个渐变效果都「原样搬」到 CSS 里,结果花在调细节上的时间远超预期。后来学会了「先还原结构,再补视觉」,先用 60% 的时间把布局和交互跑通,再用 40% 的时间打磨间距、阴影和颜色细节。这个顺序让我不再被设计稿里的某个小细节卡住大半天。希望你拿到学成在线这份素材时,也能避开这个弯路的。这套流程走一遍之后,你会发现「还原设计稿」其实是一件越拆越有把握的事,希望帮到你。
本文还有配套的精品资源,点击获取