ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

纯手写HTML/CSS还原数据卡片页面:布局与细节实战复盘

纯手写HTML/CSS还原数据卡片页面:布局与细节实战复盘 “页面绘制练习”这个标题乍看挺随意但其实是非常典型的前端基本功训练场景。我最近正好把这个练习认真做了一遍——不依赖任何组件库纯手写 HTML/CSS 去还原一个中等复杂度的数据卡片页面。这种练习看起来简单真正上手才发现布局方式的选择、间距系统的统一、细节状态的打磨每一个环节都能暴露你平时写业务代码时积攒下来的坏习惯。这篇就把我这次“练习1”的完整过程复盘一遍从拆解结构到最终像素级还原包括每一步的思路、关键代码、踩过的坑全部摊开讲适合刚入门的前端、准备面试的开发者以及写了几年代码但样式一直靠组件库的朋友。1. 为什么要把页面绘制当成正经练习1.1 页面绘制练的不是画是还原能力很多朋友一听“页面绘制”就觉得是设计师的活或者觉得这是新手才需要练的东西。实际上这项练习的核心从来不是“画得好看”而是还原能力——拿到一张设计稿你能不能把它变成结构合理、视觉接近、响应式不出错的真实现网页。我见过不少工作三五年的前端业务逻辑写得飞快但一遇到需要纯手写样式的需求就露怯间距靠猜字体大小随手拍阴影和边框从来不看设计稿规范。原因很简单平时写代码都是往组件库里塞属性对底层 CSS 的感知被严重削弱了。而页面绘制练习就是专门治这个问题的它逼着你去观察、去测量、去思考每一个像素背后的设计意图。这次练习我选了一张典型的数据看板页面作为目标带顶部导航、筛选栏、卡片栅格、图表区域和底部信息。这种页面在真实业务里出现频率极高难度又适中练一次能覆盖大部分核心布局技巧性价比相当高。整个练习我给自己定的标准是用桌面端开发缩小到 375px 宽度后主要布局不破视觉误差控制在肉眼可接受范围内。1.2 三种常见的练习方式怎么选页面绘制练习目前常见的有三条路线我建议根据自己情况选设计稿还原找一张 UI 设计稿Dribbble、花瓣、甚至买模板按图实现。这条路线最接近真实工作场景能练到完整流程。CSS Battle 类挑战用尽量短的代码画出指定图形偏技巧训练。适合想强化选择器和奇技淫巧的人但对整体布局帮助不大。临摹真实站点找一个线上网站把它的某个区块还原出来。优点是不用找素材缺点是浏览器里看原站和自己写的对比时容易被各种广告、动态效果干扰。我做练习1选择的是第一种原因很直接设计稿的信息是“静态且确定”的你能明确知道自己还原得准不准特别适合建立对间距、字号、颜色的敏感度。等这条路走顺了再去临摹带交互的真实站点也不迟。2. 动手前先做的三件事拆结构、定策略、选工具2.1 拿设计稿先拆层级而不是急着写代码我见过很多人拿到设计稿就开写结果写到一半发现某个位置不知道该用 Flex 还是绝对定位然后反复改浪费时间还容易把代码搞乱。正确做法是先花十分钟做结构拆解也就是给页面画一个“层级树”。拿我这次的数据看板页面举例我从上到下拆成了四层全局容器整个页面的最大包裹层负责最大宽度和水平居中。顶部导航固定高度内部是左侧品牌区加右侧用户操作区。内容主体左侧筛选栏加右侧卡片栅格这是整个页面布局最复杂的部分。底部信息条高度最小的简单区域。拆到这一步还不够每个大区块内部还要继续拆。比如右侧卡片栅格我先确定了它是“一行为三列”的结构再把每张卡片内部拆成“标题行、指标数字、趋势条形图、底部标签”四块。拆得越细后面写代码就越像搭积木哪里该用什么布局方式也一目了然。这里有一个很重要的原则我每次练习都会提醒自己先定结构再写样式。HTML 结构如果一开始就按语义化标签和内容嵌套组织好后续 CSS 基本是顺着结构流下来的很少需要返工。2.2 布局方案选型Flexbox 还是 Grid这是页面绘制练习里最核心的技术决策。我这次页面里同时用到了两种方案决策逻辑可以分享给大家一维排列用 Flexbox顶部导航里的品牌区和操作区是水平排列筛选栏里的筛选项是水平排列卡片底部标签也是水平排列。这些场景本质上是“一行里放几个元素”用 Flexbox 最自然代码量也最少。二维布局用 Grid卡片栅格是典型的多行多列场景如果用 Flexbox 实现需要给每个子项算 flex-basis 和间距还要处理换行后对齐的问题远不如 Grid 的repeat(3, 1fr)一行声明来得干净。这里有个判断标准可以记一下如果这个区域只在一个方向上有排列需求用 Flexbox如果横向纵向都在乎排列关系且子项数量可能变化用 Grid。别一上来就“全页 Grid”也别“万物皆 Flex”按需选择才是正路。我这次页面最终布局方案是全局用 Flex 纵向排列各大区块内容主体部分用 Flex 加上右侧栅格用 Grid。页面控制逻辑清晰代码可读性也比较高。2.3 工具链准备浏览器、参考线与标注这个练习虽然不写什么复杂工程但工具准备还是值得花点时间。首先是浏览器我用的 Chrome做页面绘制练习必开两大件DevTools 的响应式模式和标尺插件。响应式模式用于随时检查不同宽度下的表现标尺插件帮助测量设计稿里的尺寸和间距。如果你不想装插件也有替代方案直接把设计稿图片拖进浏览器按同样的缩放比例和你的页面并排对比用 DevTools 的取色器取设计稿里的颜色值。其次是参考线的使用习惯。我在动手前会先把设计稿里的关键间距记下来比如页面左右内边距是多少、卡片之间的间距是多少、导航高度是多少。我的习惯是写在一张纸上后面写代码时反复对照而不是来回切窗口肉眼估。最后强烈建议做一个简单的 CSS Reset。不同浏览器默认样式差异不小统一清零之后再开始写样式能避免很多“为什么这里多出来一个间距”的灵异问题。我这次用的是精简版去掉默认 margin 和 padding、设置box-sizing: border-box、重置图片为块级显示。3. 完整实操从骨架到细节还原一个数据卡片页3.1 先搭全局骨架容器、间距系统与 CSS Reset这一步我称之为“搭地基”。我把全局样式写在最前面目标只有一个让后续所有组件的样式都在一个可控的基准上发展。* { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif; color: #1f2933; background-color: #f5f7fa; line-height: 1.5; } .container { max-width: 1200px; margin: 0 auto; padding: 0 20px; }这里有个细节值得展开间距系统。我在设计稿里数了一下页面里出现的间距基本都是 8 的倍数——8、16、24、32。这是非常常见的设计体系叫 8px 栅格。练习时我强制自己只用这组间距值不随手敲 13px、7px 这种数字。这样做的价值是整个页面的留白节奏高度统一视觉上会特别“整”。等练多了你再看别人的页面一眼就能判断出它的间距系统是否一致这就是基本功的体现。全局容器我设置了 1200px 最大宽度和居中。数据看板类页面在宽屏下的惯用做法就是限制内容宽度避免一行拉得太长导致阅读和扫视效率下降。左右内边距 20px 是为了在中等屏幕下内容不贴边这同样来自设计稿的测量结果。3.2 实现核心组件顶部导航与卡片栅格骨架搭完后我按从外到内的顺序实现各个区块。先看顶部导航它的结构很简单左右两块。header classheader div classheader__brand数据看板/div div classheader__actions span classheader__notification通知/span span classheader__avatar管理员/span /div /header.header { display: flex; align-items: center; justify-content: space-between; height: 56px; background: #ffffff; border-bottom: 1px solid #e4e7eb; padding: 0 24px; }justify-content: space-between让左右两组元素各占一端下面的1px边框是很多设计稿里导航区域常用的分割线。这个组件难点不多但高度、内边距、分割线颜色三个值都必须从设计稿里精确取绝不能靠感觉。接下来是重头戏——卡片栅格。我的 HTML 结构是内容主体区域左侧是筛选栏右侧是一个 Grid 容器里面放了若干张卡片。section classcontent aside classfilter-bar !-- 筛选选项 -- /aside div classcard-grid article classcard div classcard__header span classcard__title总访客数/span span classcard__badge周同比/span /div p classcard__value24,521/p div classcard__chart趋势条/div div classcard__footer span较昨日 8.2%/span /div /article !-- 更多卡片... -- /div /section.content { display: flex; gap: 24px; padding: 24px 0; } .filter-bar { width: 220px; flex-shrink: 0; } .card-grid { flex: 1; display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }写到这里就是实战中最能体现“拆结构”价值的地方左侧筛选栏宽度固定右侧区域自适应占满剩余空间所以用flex-shrink: 0防止筛选栏被压缩右侧内部再用 Grid 切出三列。两层布局各司其职嵌套关系一目了然。3.3 细节打磨圆角、阴影、字重与状态页面绘制练习的进阶感主要来自细节。结构和布局对了之后离“像”还差几步。我这次重点打磨了四个细节圆角。卡片设计稿里用的是 12px 圆角。这个值不大不小在数据看板里很常见。我顺手把按钮、标签等元素的圆角也统一成设计稿里的规范避免每处都用不同的圆角值导致整个页面风格散掉。阴影。卡片阴影我用的是box-shadow: 0 1px 3px rgba(16, 24, 40, 0.08)要诀是阴影要“轻”且“柔”不能一大片黑糊在卡片下面。0 1px 3px这个组合表示阴影几乎不向下偏移只做微弱扩散视觉上能产生层次感但不抢内容。字重。数字和标题要够醒目我用了font-weight: 600辅助说明文字用font-weight: 400并加上次要颜色。中文字体在非加粗状态下的辨识度差异没有西文那么明显所以字重层级必须配合大小和颜色一起调否则很容易“糊成一片”。状态。设计稿里有一个按钮有默认、悬停两种状态。我补充了:hover样式把背景色加深一档、光标变成手型。真实页面绘制练习里交互状态经常被忽略但面试和工作中这恰恰是考察细节意识的地方。.card { background: #ffffff; border-radius: 12px; padding: 20px; box-shadow: 0 1px 3px rgba(16, 24, 40, 0.08); } .card__value { font-size: 28px; font-weight: 600; margin: 8px 0; } .card__badge { font-size: 12px; color: #3e4c59; background: #f0f4f8; border-radius: 999px; padding: 2px 8px; }卡片标签用了999px圆角直接把矩形拉成胶囊形。这个技巧做标签、徽章时特别常用比写固定圆角要省心得多。3.4 响应式收尾断点怎么定基础版本在桌面端完成之后我加了两条媒体查询来做响应式收尾。断点的选择不是拍脑袋而是按照内容什么时候“挤不下”来定的。media (max-width: 900px) { .card-grid { grid-template-columns: repeat(2, 1fr); } } media (max-width: 640px) { .content { flex-direction: column; } .filter-bar { width: 100%; } .card-grid { grid-template-columns: 1fr; } }900px 时三列卡片每张已经窄到内容放不下所以我降为两列640px 时基本进入手机竖屏状态筛选栏必须从左侧挪到顶部卡片变成单列。这里有个容易犯的错为了“做响应式”而强行写断点。正确思路是先缩浏览器窗口观察页面实际什么时候变难看再在这个临界值附近设断点。练习1我只处理到单列为止没有继续展开移动端导航的交互细节因为一次练习聚焦一个问题就够了。4. 绘制练习中最常踩的坑与排查技巧4.1 高频问题速查表练完这次页面绘制我把自己平时教学和实操中遇到的高频问题整理成了一张速查表对做类似练习的人应该很有参考价值。症状可能原因排查方向子元素把父容器撑破没有设置min-width: 0或内容里有长英文单词检查 Flex/Grid 子项的收缩属性两个元素之间有莫名空隙行内元素之间默认有空白符把元素改成display: block或flex背景色铺不满容器高度由内容决定但子元素用了浮动或绝对定位检查浮动是否清除或改用 Flex/Grid不同浏览器显示不一致缺少 CSS Reset统一 reset 之后再看效果卡片间距忽大忽小margin 和 padding 用混了明确标准间距优先用父容器的 gap图片显示后底部有空白图片默认是基线对齐display: block或vertical-align: middle这里面最容易让人抓狂的是第一个。Flex 或 Grid 的子项默认是可以被压缩的但如果里面放了一段很长的文字或者一个最小宽度很大的元素就会出现“怎么调都溢出”的情况。解决办法通常是在子项上加min-width: 0允许它让出空间。第二个问题也是新手高频坑比如写完导航发现两个span之间总有一小块空隙怎么看都不顺眼。这其实是 HTML 源码里换行符被渲染成了空格。把元素改成 flex 布局之后空白符问题会直接消失所以现代布局方案天然规避了这个老坑。4.2 用 DevTools 高效定位样式偏差在这次练习里我对比“原设计稿”和“我的实现”时最常用的就是 Chrome DevTools 的这几个功能取色器点击颜色样例旁边的色块图标可以直接吸取页面上的任意颜色用来校验我的色值是否和设计稿一致。间距可视化选中元素后DevTools 会在页面里直接高亮显示 margin 和 padding 的占用区域一眼就能看出哪个间距算错了。强制状态Elements 面板里有个:hover的可选勾选项方便检查交互状态样式写没写对。计算样式面板当不确定某个属性最终生效值是多少时这里会列出所有层叠后的结果比在源代码里翻找快得多。我用得最频繁的是启用取色器逐个对比卡片的标题色、正文色和辅助色。人在长时间盯屏后对颜色差异会变迟钝用工具取色再和阿里的设计稿色板对比误差就能准确修正到很小了。还有个小技巧写完一版后我会把设计稿图片和我的页面各截一张局部图拼在画图软件里对比透明度调低两张图叠一起看。哪里偏了、哪里歪了一目了然。这个土办法比任何工具都直观。5. 练习后的复盘怎样沉淀才算真正消化5.1 记录还原差异找出自己的盲区页面绘制练习如果只写完就丢价值会少一大半。我每次练习结束都会做一次“差异清单”把最终实现和设计稿之间所有不准确的地方列出来并归类分析原因。这次练习我归纳出了自己的三个盲区第一是对间距系统的执行力不足。虽然我定了 8px 栅格但在某些局部还是忍不住用了 10px、6px 这种不在体系内的值。后来统一改回 8 的倍数后页面整体立刻稳重了很多。这说明定规范容易守规范需要刻意训练。第二是对中文字体排版不敏感。设计稿里的某些标题用了较大的字号但我一开始对中文字体行高没有显式设置导致标题和下文的间距看起来偏散。补上合适的line-height后明显好多了。第三是对容器边界的忽视。栅格里的卡片内容长短不一导致同一行的卡片高度参差。后来给卡片内容区域设置了最小高度并让卡片使用 flex 布局纵向排列内容才做到整齐统一。把这些盲区写下来比单纯“做完了很开心”有价值得多。下一次练习1的续集开始时我会先翻一遍这份清单重点验证上次的问题有没有真正解决。5.2 把高频片段沉淀成自己的代码库页面绘制练习的另一个产出物是我会顺手把高频使用的代码片段抽成自己的小工具箱。比如我这次从页面里提炼了几个直接能复用的模式一个标准的.container全局容器样式一个卡片基础样式圆角、阴影、内边距一个胶囊标签的实现三列 Grid 栅格的响应式降级写法一个 flex 导航栏的骨架。这些片段存成一份单独的文件并不依赖任何框架。下次再做类似的页面绘制练习或者工作中临时要写静态页直接复制微调即可。这种做法既提高效率又帮助我内化了它们背后的原理。我个人的体会是页面绘制练习最怕用“刷题”的心态去搞。追求数量没有意义认真还原一张中等复杂度的页面对基本功的提升远大于草草画十张。每张页面里做的决策——为什么用 Flex 而不是 Grid、为什么间距取 24 而不是 20、为什么阴影要这么轻——才是这项练习真正的营养所在。如果你也想开始这项练习建议先别挑太难的目标找一张带导航、栅格、卡片和简单交互状态的页面从这类“骨架完整”的页面开始把每一层拆清楚、做踏实。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进