☰
学成在线PSD素材切图全流程:从设计稿到可运行页面
2026/10/6 8:55:08 网站建设 项目流程

简介:学成在线PSD素材及代码是一套面向前端初学者的教学案例包,源自黑马程序员与pink老师的前端课程,涵盖了页面设计原稿与配套实现源码,可帮助学习者理解从PSD设计图到HTML/CSS页面的完整还原流程。压缩包共11个文件,约17.71MB,其中包含4份PSD设计源文件(首页、课程列表页、课程介绍页、职业规划页)、5张页面所需的PNG切图、1个index.html页面结构以及1个style.css样式表。学习时既可以在Photoshop中逐层分析设计思路,也可以对照源码研究盒模型、浮动布局、配色与字体设置等知识点,掌握教学型页面的经典实现方案。这份案例既适合刚接触HTML/CSS的新手模仿练习,也适合有一定基础的开发者查漏补缺。目前已有14050人学习或下载,素材与代码组织清晰,解压即可直接查看并修改,是提升前端页面还原能力和编码熟练度的实用练习资源。

1. 学成在线PSD素材及代码到底在做什么:一份设计稿到可运行页面的完整链路

你可能遇到过这样的情况:下载了一个叫“学成在线”的压缩包,解压后里面是一堆PSD文件和十几个散落的HTML、CSS、JS文件。打开PSD一看,页面设计得挺完整,但切图没做好,代码和素材对不上,浏览器里跑起来不是图片裂了,就是样式全乱。这个标题看似简单,实际上说的是一个完整的前端切图落地场景:把学成在线的PSD设计稿,通过切图、导出素材、写语义化页面代码、加交互脚本,最终变成一个真正能部署运行的网页。它适合正在练手切图的初级前端、需要交付完整站点的外包工程师,以及想搞懂设计稿如何转代码的产品同学。下面这套流程,是我自己做这类“PSD素材及代码”项目时反复用过的方案。

2. 把PSD拆成可用素材:切图流程、命名规范与目录设计

拿到PSD后的第一件事不是急着打开代码编辑器,而是先花半小时把设计稿吃透。很多人跳过这一步,直接右键“导出为PNG”,结果导出几百张没有分类、没有命名规则的碎片图,后面写CSS时根本找不到哪张是哪张。学成在线这类教育培训站点的PSD,结构其实很规律:顶部导航、轮播Banner、课程卡片列表、新闻资讯区、底部友链和版权。你需要先把这些区域在图层面板里标记出来,然后才开始切图。

2.1 先读设计稿:识别模块层级与重复组件

打开PSD后,先在图层面板里把图层组按“header / banner / course / news / footer”这样的大模块重命名,这个动作能让你后面切图时思路清晰。学成在线的设计稿里,课程卡片通常是重复出现的组件,比如四个课程卡片横排一行的结构,在图层面板里往往是一个组里复制了多次。遇到这种情况不要逐个切,先确定它的统一尺寸和样式,再只切一次,复用同一套类名和图片。

具体我会这样做:先建一个“切图清单”,列的字段是模块名、元素名、类型(图标/背景/插图)、尺寸、格式、倍率。把PSD里所有需要导出的元素在清单里过一遍,再动手导出。这一步看起来琐碎,实际能省掉后续排查图片对不上的大量时间。学成在线这类页面的元素数量通常在五十到一百个之间,不提前列清单,导到后面必然乱。

提示:如果你电脑里没装Photoshop,也可以先用蓝湖、PxCook这类工具解析PSD,它们能标注尺寸和颜色。但真正切大图、处理透明图层时,还是回到Photoshop操作最靠谱。

2.2 从PSD导出三类素材:图标、背景、插图

我一般把需要导出的素材分成三类对待。第一类是图标类,包括导航展开箭头、课程分类小图标、搜索按钮、社交平台小logo这类尺寸小、带透明通道的元素。在Photoshop里选中目标图层或组,右键选择“快速导出为PNG”,如果图层里有多个尺寸相同的图形,可以把它们放到一个组里一起导出。注意导出时把“转换到sRGB”勾上,不然放到网页上颜色会偏灰。

第二类是背景类和装饰类,比如Banner底图、渐变背景层、页面顶部的大色块。这类元素如果是有复杂照片内容的大图,导出为JPG更合适,体积只有PNG的几分之一;如果是纯色或者简单渐变的背景,尽量用CSS实现,不要导出图片,视觉更清晰、加载也更快。第三类是课程封面这类插图,按设计稿的实际比例导出,透明区域用PNG,实底用JPG。

每次导出时,我都会在导出对话框里确定倍率:切图默认导出1倍图,但如果设计稿是按2倍尺寸制作的,就要额外导一份2倍图。怎么判断设计稿是否是2倍?看翼标:打开“图像”菜单里的“图像大小”,如果宽度是设计页面逻辑宽度的两倍左右,比如逻辑宽度1920px、实际PSD宽度3840px,那就是2倍稿,需要导2x素材,后面给srcset用。

2.3 命名的复用:目录结构与CSS类名的对应关系

图片切完后,要先把文件分类放到约定好的目录里。我习惯的项目结构是这样的:

学成在线/ ├── index.html ├── css/ │ ├── base.css │ ├── layout.css │ └── index.css ├── js/ │ ├── carousel.js │ └── tab.js └── assets/ ├── icons/ # 小图标,PNG + SVG ├── images/ # 课程封面、Banner大图 └── sprites/ # 雪碧图

图片命名和CSS里的类名要保持一致的约定,比如课程卡片里的图统一叫course-html.jpg、course-css.jpg,对应的CSS类名就是.course-html、.course-css。这样做的好处是页面里找class时,能直接猜到对应的图片文件名,不需要反复打开资源管理器找。

命名规则建议固定为全小写、单词之间用连字符连接,比如icon-arrow-down.png、banner-main.jpg。禁止在文件名里出现空格、中文和“最终版”“V2”这种后缀,否则进入自动化流程时大概率踩坑。文件名长度控制在二十个字符以内,后面合并雪碧图时才不会被超长路径影响。

2.4 适配策略:@2x素材与retina屏的约定

素材切好之后,要面对的一个现实问题是高清屏适配。学成在线的设计稿宽度一般按1920做,但实际用户有的在普通屏看,有的在Retina屏看。我的做法是图标和关键插图各导一份2x图,1x图保留在同一目录,用srcset或image-set()让浏览器自己选。

<img src="assets/images/course-html.jpg" srcset="assets/images/course-html@2x.jpg 2x" alt="HTML课程封面">

这里逻辑很简单:src是默认1x图,srcset里声明的@2x图在2倍屏上加载,保证不模糊。CSS背景图方面,用image-set()配合background-image实现类似效果。

还有一种做法是把2x图作为主图,1x图删掉,然后用CSS里的background-size按50%缩放。但这种方式要求每个图都按统一的设计倍率切,后期维护很麻烦。我只有在开发时间紧张时才会这么偷懒。正经项目还是用srcset或image-set(),代码量就几行,清晰度和体积能同时兼顾,属于性价比最高的适配方案。

3. 写页面代码:用HTML5语义化骨架和Flex布局还原设计稿

素材准备完,接下来进入代码阶段。学成在线这类站点结构规整,用HTML5的语义化标签加Flex布局,基本能一比一还原设计稿。写代码的顺序我固定是从HTML骨架开始,然后写CSS布局,最后再处理交互。

3.1 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/base.css"> <link rel="stylesheet" href="css/layout.css"> <link rel="stylesheet" href="css/index.css"> </head> <body> <header class="site-header"> <a href="/" class="logo">学成在线</a> <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> </ul> </nav> <div class="search-box"> <input type="text" placeholder="搜索感兴趣的课程"> <button type="submit">搜索</button> </div> <a href="#" class="user-entry">登录 / 注册</a> </header> <main> <section class="banner">/* base.css */ * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", sans-serif; color: #333; background: #fff; } /* layout.css */ body { display: flex; flex-direction: column; min-height: 100vh; } main { flex: 1; width: 100%; } .container { width: 1200px; margin: 0 auto; } .site-header { display: flex; align-items: center; justify-content: space-between; height: 64px; padding: 0 24px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04); } .main-nav ul { display: flex; gap: 32px; list-style: none; } .search-box { display: flex; align-items: center; gap: 8px; } .course-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px; margin-top: 24px; }

这段CSS的核心参数都在为还原设计稿服务:导航高度64px,四个课程卡片并排用grid-template-columns: repeat(4, 1fr)实现,卡片间距24px。为什么用grid而不是flex?因为课程卡片是典型的网格布局,grid能直接控制列数和间距,不需要在子项上设置flex-basis再做减法计算间距。

min-height: 100vh配合flex: 1的做法,让页脚永远贴在视口底部,即使内容不够一屏也不会出现页脚悬浮在半空的情况。排除了px写死高度的方案,因为用户窗口高度不固定,最稳妥的做法就是Flex纵向撑开。

3.3 处理设计中隐藏的状态:hover、active、下拉菜单

设计稿上一般只呈现静态效果,但实际交互页面必须有状态反馈。学成在线的导航栏就有典型的hover和active状态,CSS里这样处理:

.main-nav a { display: block; padding: 6px 0; color: #333; text-decoration: none; border-bottom: 2px solid transparent; transition: border-color 0.2s ease, color 0.2s ease; } .main-nav a:hover { color: #ff7c32; border-bottom-color: #ff7c32; } .main-nav a.active { color: #ff7c32; border-bottom-color: #ff7c32; } .course-card { border-radius: 8px; overflow: hidden; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); transition: transform 0.2s ease, box-shadow 0.2s ease; } .course-card:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); }

这组CSS里最关键的是给导航链接加了2px透明下边框。透明边框不会改变盒子的占位尺寸,所以hover时文字不会上下跳动,这和直接加border-bottom: 2px solid有本质区别。课程卡片的阴影和位移都加了transition,悬停时不会有生硬跳变。

下拉菜单我倾向于用CSS的visibility加opacity实现,而不是display: none,因为前者可以配合transition做淡入淡出,后者只能硬切换。这里不再展开完整代码,但原理是:下拉面板默认visibility: hidden和opacity: 0,父级li:hover时改成visible和1,配合position: absolute定位到导航条目下方。

4. 给页面添加交互逻辑:轮播、导航高亮与移动端菜单

静态页面写完后,学成在线的首页还需要几处常见交互:Banner轮播、课程Tab切换、移动端导航菜单。这些功能用原生JavaScript完全够用,不必引入jQuery或Vue。有人会觉得用框架更省事,但一个静态页面用原生JS就能解决的问题,加载Vue运行时反而增加几百KB体积,得不偿失。

4.1 轮播图实现:使用原生JS还是框架

轮播是首页视觉重心,也是交互的核心。常见做法是在HTML里放一个.banner-viewport容器,里面一张接一张排列.banner-track中的幻灯片,再用JavaScript控制transform: translateX()。示例代码如下:

<div class="banner-viewport"> <div class="banner-track"> <div class="slide" style="background-image: url('assets/images/banner-1.jpg')"></div> <div class="slide" style="background-image: url('assets/images/banner-2.jpg')"></div> <div class="slide" style="background-image: url('assets/images/banner-3.jpg')"></div> </div> <button class="banner-prev">上一张</button> <button class="banner-next">下一张</button> </div>
// carousel.js const track = document.querySelector('.banner-track'); const slides = document.querySelectorAll('.slide'); const prevBtn = document.querySelector('.banner-prev'); const nextBtn = document.querySelector('.banner-next'); let currentIndex = 0; const slideCount = slides.length; const autoPlayInterval = 4000; let timer = null; function goToIndex(index) { if (index < 0) index = slideCount - 1; if (index >= slideCount) index = 0; currentIndex = index; track.style.transform = `translateX(-${currentIndex * 100}%)`; track.style.transition = 'transform 0.35s ease'; } function nextSlide() { goToIndex(currentIndex + 1); } function prevSlide() { goToIndex(currentIndex - 1); } function startAutoPlay() { timer = setInterval(nextSlide, autoPlayInterval); } function stopAutoPlay() { clearInterval(timer); timer = null; } prevBtn.addEventListener('click', () => { prevSlide(); stopAutoPlay(); startAutoPlay(); }); nextBtn.addEventListener('click', () => { nextSlide(); stopAutoPlay(); startAutoPlay(); }); track.addEventListener('mouseenter', stopAutoPlay); track.addEventListener('mouseleave', startAutoPlay); startAutoPlay();

这段代码里有个关键参数:autoPlayInterval = 4000,也就是4秒自动切换一次。这个数字要看实际需求设置,通常商城站3到5秒比较舒服,学成在线这类内容站4秒合理。goToIndex方法里的边界判断,让轮播到最后一张时能回到第一张,形成循环。

交互上,鼠标悬停时暂停播放是个默认习惯。如果不暂停,用户正在读Banner上的文字时突然切走,体验会很差。这里用mouseenter和mouseleave两个事件绑定到track上,用户进入轮播区域就暂停,离开就恢复,逻辑简单不产生额外变量。

注意没有加“上一张/下一张”按钮的焦点管理。完整的无障碍轮播还需要处理键盘事件和aria-label,但作为静态页练习,先把视觉切换跑通,再补无障碍也不会伤筋动骨。

4.2 导航与tab切换:事件委托与数据驱动思路

学成在线首页通常有“最新课程”和“热门课程”之类的Tab切换。我使用事件委托来绑定点击事件,而不是给每个按钮单独绑定。事件委托的好处是新增或删除Tab按钮时不需要改JavaScript代码。

<div class="course-tabs"> <button class="tab-btn active">// tab.js const tabBtns = document.querySelectorAll('.tab-btn'); const tabContents = document.querySelectorAll('.tab-content'); document.querySelector('.course-tabs').addEventListener('click', (event) => { const target = event.target.closest('.tab-btn'); if (!target) return; tabBtns.forEach(btn => btn.classList.remove('active')); target.classList.add('active'); const tabKey = target.dataset.tab; tabContents.forEach(content => { content.style.display = content.id === tabKey ? 'block' : 'none'; }); });

这段JavaScript里最有用的写法是event.target.closest('.tab-btn')。用户可能点击到<button>内部的文字,也可能点的是图标或内层元素,closest()能直接从实际点击的元素向上查找到离它最近的Tab按钮,一条代码解决事件目标不准的问题。

>/* index.css 末尾追加 */ @media (max-width: 768px) { .container { width: 100%; padding: 0 16px; } .site-header { height: auto; flex-wrap: wrap; padding: 12px 16px; } .main-nav { order: 3; width: 100%; overflow-x: auto; margin-top: 8px; } .main-nav ul { gap: 16px; flex-wrap: nowrap; white-space: nowrap; } .course-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; } .search-box { margin-left: auto; } } @media (max-width: 480px) { .course-grid { grid-template-columns: 1fr; } .search-box input { width: 120px; } }

这里有没有必要用rem?我的看法是:如果页面主要是PC内容,用px加媒体查询就够了;如果页面内容大量文字排版,或者面向长期运营内容更新,rem才有优势。学成在线这类页面,固定px布局配合断点调整,实现和维护成本都更低。

移动端菜单没有单独做汉堡按钮,而是把导航变成横向可滑动的条,放在头部第二行。这种处理对内容和导航都不多的页面非常实用,省掉了一整套菜单展开与关闭的JavaScript逻辑。

5. 边写边避坑:PSD切图与页面还原的常见问题排查

5.1 字体差距过大:系统字体栈与设计稿的差距

现象:页面写完总体布局没问题,但所有文字的字号和间距跟设计稿一比明显不对劲,有的地方窄了,有的地方行距高了。

原因:设计稿里用的字体在某台电脑上没有安装,浏览器自动降级成另一个字体,大部分中文字体的度量标准不同,同一字号渲染出的高度和宽度差异很大。

解决:统一设置字体栈,把市面上主流系统里都常见的中文字体按优先级写进font-family:

body { font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", sans-serif; }

这里顺序很重要。-apple-system和BlinkMacSystemFont覆盖苹果系设备和Chrome浏览器,PingFang SC表示Mac上的中文,Microsoft YaHei是Windows上的微软雅黑,最后sans-serif兜底保证任何系统都有可用字体。如果设计稿用了特殊字体,比如思路极粗的黑体,先确认字体版权,再考虑用图片代替还是找免费字体。

5.2 背景图和切图之间有白边、黑边

现象:图标或图片放到页面上后,边缘总有一圈1像素左右的白色或黑色细线,尤其在深色背景下特别明显。

原因:PSD里元素使用了羽化、描边,或者没有严格贴着图形边缘裁切。导出时把半透明像素和背景残留一起导出来了。

解决:返回到PSD里,选择目标图层后,先用“选择”菜单里的“载入选区”把图层轮廓选出来,再执行“选择”>“修改”>“收缩”1到2像素,然后按选区导出。注意描边特效要在图层样式里检查,如果是不需要的描边就先关闭再导出。

注意:收缩选区只对实底图形有效,如果图标本身有半透明发光效果,收缩会切掉光晕。这类素材更要保留原始图层直接导出,不要在切图上做额外抠边。

5.3 雪碧图坐标错位:background-position的换算错误

现象:页面加载后所有小图标都是错位的,或显示成别的图标,背景位置完全对不上。

原因:图标在雪碧图中的位置和CSS里的background-position坐标不匹配,或者错误地把2x图的坐标用在了1x图上。

解决:不要手写坐标。现在有很多合成雪碧图的工具,比如打包脚本自动测量后生成坐标表。手动排版的唯一靠谱做法是,在PSD里把每个图标排布在不同的小格子里,格子大小统一,比如全部32x32,然后用Python或在线工具量取每个图标左上角的坐标,再填进CSS。更省事的是完全放弃雪碧图,现在HTTP/2和多通路的时代,十几个小图标逐个加载的代价已经很低,学成在线这类页面其实没必要合并雪碧图,分开加载反而免除计算坐标这一步。

5.4 垂直间距不对和margin塌陷

现象:两个区块之间的间距比设计稿大或者小,而且margin设置了却没有生效。

原因:经典的外边距合并。CSS里上下相邻的块级元素,它们的margin会合并取最大值,而不是两个值相加;父子元素也会有类似的塌陷问题。

解决:在这个项目里推荐使用display: grid或flex来避免间距问题,它们内部的子项间距用gap属性控制,完全不触发margin合并。对于必须使用margin的地方,给父级设置display: flow-root修掉塌陷。flow-root是专门用来形成独立格式化上下文的属性,副作用比overflow: hidden小得多。

5.5 图片加载慢和路径失效

现象:页面图片显示成碎图标,或者背景图加载很慢,甚至排版在图片加载后跳动。

原因:路径写错了,要么是HTML文件深层目录下找不到相对路径的图片,要么是图片文件太大没做压缩。

解决:路径上我统一用项目内根路径,例如/assets/images/banner-main.jpg这种以/开头的写法,确保网页部署在任何子目录也不会失效。图片体积方面,切图后必须用压缩工具处理一遍,PNG压到百KB以内,JPG压到两百KB以内,超过这个量就要检查是不是导出尺寸太大了。CSS里的大背景图不要直接平铺原图,优先考虑用压缩过的WebP格式,体积能再降一半。

6. 像素级验收与自动化发布:你最后需要的三个小技巧

页面写完,离交付还差一步验收。我习惯在本地把这几个动作养成固定套路,这套流程能挡住九成以上的低级错误。

第一个技巧是浏览器像素比对。打开Chrome DevTools,把页面缩放到设计稿的相同宽度,然后利用扩展工具把PSD导出的大图放在页面顶层,调整透明度逐区块比对。重点检查三处:导航高度、卡片间距、页脚边距。肉眼看到差距后,直接在DevTools里改padding和margin校验,改完再回代码文件同步数值。不要凭感觉直接改数值,那样大概率越改越偏。

第二个技巧是自动化压缩。如果项目里装了Node环境,我用一套简单Gulp脚本自动处理图片和CSS前缀,几行代码就能把重复劳动全部接管:

const gulp = require('gulp'); const imagemin = require('gulp-imagemin'); const autoprefixer = require('autoprefixer'); gulp.task('images', () => gulp.src('assets/images/**/*') .pipe(imagemin([ imagemin.optipng({ optimizationLevel: 3 }), imagemin.mozjpeg({ quality: 75 }) ])) .pipe(gulp.dest('dist/assets/images')) );

这段代码里optimizationLevel是PNG压缩级别,不是越高越好,5级以上压得很慢且收益很小,3级是日常推荐值;JPG的quality设为75,视觉上几乎看不出损失,体积能比原图缩小一半以上。跑完这套任务,把dist目录里的文件直接打包发布即可。

第三个技巧是发布前检查清单。我会依次做五件事:无痕窗口打开页面首屏,确认图片不裂、控制台没有报错;切换iPhone和Android尺寸,确认断点没有横向滚动条;把当前页面的HTML源码放进W3C校验器检查标签嵌套;用Git在本地提交一次完整代码,顺便检查有没有残留的绝对路径;最后把页面部署到测试环境,用真机走一遍轮播和Tab交互。

说句实话,我第一次做这类切图项目时,就是图快直接拿PSD里的原图当网页图片用,页面臃肿到加载半天。后来养成了切图前列清单、出图后统一压缩、写完页面逐区块比对的习惯,交付质量和返工次数都明显改善。做前端这种偏实操的活,与其追求新框架花活,不如先把这一步一步的落地动作练熟。希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询