
手上这套实战项目就是典型的用 HTML CSS JS 从零手搓的大数据可视化大屏从标题就能看出来——销售额度展示 销售分类排行榜。做大屏实战项目最爽的一点是代码量不大但出来的效果足够唬人比赛演示、课程作业都拿得出手。尤其是这种“销售排行榜”方向业务逻辑直观、数据展示形式丰富很适合作为第一个从 0 到 1 完成的完整大屏作品。这套大屏能做什么简单说就是把一堆销售分类数据通过排行榜、进度条、柱状图、数字面板等形式铺满一块大屏让观看者一眼就能看出“哪个品类卖得好、哪个品类在拖后腿、整体盘子有多大”。适合拿来当比赛项目、期末大作业甚至作为毕设里的数据可视化子系统。对技术基础的要求也不高会 HTML 结构、CSS 布局、JS 数组操作就能完整复现。1. 项目拆解一个排行榜大屏的完整逻辑1.1 标题背后的三层需求“销售额度展示销售分类排行榜”这个标题拆开来看其实是三个层次的需求叠加。第一层是“销售额度展示”。这意味着页面必须有大数字、总量指标、各分类的销售金额而且这些数字要足够显眼能一眼看到体量。这不是后台管理系统里那种小表格而是面向演示场景的“大卡片”。第二层是“销售分类排行榜”。排行榜天然是纵向列表有排名、有分类名、有销量数、有对比条。它的核心不是展示所有数据而是强调“排序后的差异”让第一名和最后一名的差距变得可视化。第三层是“大屏”这个载体。大屏意味着 1920x1080 起步的分辨率、深色背景、科技感边框、数据动态刷新以及从远处观看也能看清的字体大小。这才是大屏项目和普通网页项目的本质区别。把这三层需求串起来项目的页面结构就很清晰了顶部一个总标题和核心销售总额数字中间主体是一到多个排行榜模块每个排行榜由排名、分类名、销售额、占比进度条组成。1.2 什么样的人适合拿这个项目练手这个项目最合适的群体是有 HTML CSS 基础、JS 刚学到 DOM 操作和数据遍历阶段的初学者。因为它的技术点非常聚焦不会让你碰后端接口、数据库、打包构建这些复杂内容所有数据都可以先用本地 JS 数组模拟等掌握了这套流程再把数据源替换成真正的接口就行。如果是拿去比赛这个项目属于“高性价比”类型。大屏项目天然在视觉效果上占便宜就算逻辑不算特别复杂往投影上一放再配合动态数据刷新评审老师第一印象就是完整的、可落地的作品。如果是做课程作业它又足够轻量一个人花一周时间从零做完完全没问题而且代码每一行都能讲清楚答辩的时候不会出现“自己写的不懂”这种尴尬情况。1.3 技术方案选择为什么仍然用原生三件套这里聊一个很多人纠结的问题都 2025 年了大屏项目为什么不用 Vue 或者 React还要用原生 HTML CSS JS我的答案很简单这个量级的项目框架是在给自己找麻烦。一个页面、一个数据集、三五个图表模块用原生 JS 写完全够用页面加载更快代码结构也更直观。尤其是比赛答辩时评委问“这个排行榜排序怎么实现的”你直接说“用 JS 的 sort 方法处理数组再遍历渲染到 DOM”一句话能讲清楚。如果你说“我用 Vue 的 computed 计算属性”还得额外解释一套响应式原理。但原生三件套也有它的痛点最典型的就是数据更新时的 DOM 管理。项目里我用了一个非常朴素但有效的方式把“渲染排行榜”封装成一个 render 函数数据一变就重新调用 render把排行榜容器里的内容整体重绘。这个思路其实就是前端框架里“单向数据流”的雏形后面对比着学框架会非常顺畅。2. 页面结构设计与大屏布局方案2.1 先画草图再写页面做任何大屏项目我都不建议直接开写代码。先用一张纸或者一个画图工具把页面拆成几个区域标清楚哪个区域放什么再做布局。这一步能省掉后面 80% 的布局返工。我这个项目的布局思路是典型的 “上下三段式”。最上方是标题栏放项目名称、销售总览数字、日期时间中间是核心内容区分成左、中、右三栏左边放“销售额分类排行榜”右边放“销售增长排行榜”中间则用一组核心指标卡片和一个简单的柱状对比图填充。这样整个页面主次分明排行榜不会和别的模块抢视觉焦点。如果你想做成单排行榜的大屏结构可以更简单顶部标题栏中间主体就是一张铺满整个区域的大榜单。这种方案适合数据维度比较单一的场景但我更推荐双榜单加指标卡的组合因为页面内容更丰富演示时也能多讲几个角度。2.2 用 CSS Grid 快速搭建大屏骨架大屏布局我首选 CSS Grid它是天然的二维网格系统特别适合把页面切割成几个规整的模块区域。基础的代码结构是这样body { margin: 0; background: #0a1030; color: #fff; font-family: Microsoft YaHei, sans-serif; } .screen { width: 1920px; height: 1080px; display: flex; flex-direction: column; } .screen-header { height: 120px; display: flex; align-items: center; justify-content: space-between; padding: 0 40px; } .screen-body { flex: 1; display: grid; grid-template-columns: 30% 40% 30%; grid-template-rows: 1fr 1fr; gap: 20px; padding: 20px; }注意这里我用了一个很关键的思路把.screen这个容器直接固定成 1920x1080然后再通过 transform scale 做整体缩放适配。这个方案比媒体查询大屏要省心的多后面第 5 部分我会专门展开讲。2.3 排行榜模块的基础结构排行榜模块内部的结构我采用了 “面板容器 榜单项” 的方式。整个排行榜在一个半透明深色面板里面板顶部是标题栏下面是一个列表容器。每一个榜单项又由四部分组成排名序号、分类名称、销量进度条、销量金额。div classrank-panel div classpanel-title h3销售分类排行榜/h3 /div ul classrank-list idrankList !-- 榜单项由 JS 动态渲染 -- /ul /div榜单里的每个 item渲染出来大约是这样的结构li classrank-item span classrank-num01/span span classrank-name数码家电/span div classrank-bar div classrank-bar-fill stylewidth: 86%;/div /div span classrank-value¥ 43,620/span /li把榜单项设计成这种四段式是最稳的组合——既有数字排名带来的竞争感又有横向进度条带来的直观对比。我建议所有想做排行榜大屏的朋友都先用这个基础模板跑通再去玩花样。3. 排行榜数据组织与渲染逻辑3.1 用数组模拟真实数据源没有后端接口的时候数据就放在 JS 文件里模拟。这一步不是胡编乱造而是要模拟真实的业务数据结构。我常用的结构是数组套对象const salesData [ { id: 1, category: 数码家电, sales: 43620, target: 50000 }, { id: 2, category: 服饰鞋包, sales: 38950, target: 45000 }, { id: 3, category: 美妆个护, sales: 31580, target: 35000 }, { id: 4, category: 食品生鲜, sales: 28640, target: 30000 }, { id: 5, category: 家居日用, sales: 19850, target: 25000 }, { id: 6, category: 图书文教, sales: 15230, target: 20000 }, { id: 7, category: 运动户外, sales: 9860, target: 15000 }, { id: 8, category: 宠物生活, sales: 6420, target: 10000 } ];每个对象里的 target 字段是目标值用来计算百分比。实际项目里这个字段可能是 KPI 指标没有目标值也可以直接用数组里的最大值作为进度条的 100% 基准这两种方式我都写过。3.2 排序、百分比计算、DOM渲染三步走排行榜的核心逻辑就是三件事排序、算比例、渲染。第一步用 sort 方法按销售额降序排列数据。这里有一个我踩过坑的细节sort 会改变原数组如果不希望原数据被污染要先浅拷贝一份再排序。代码这样写最稳妥function getRankList(data) { return [...data].sort((a, b) b.sales - a.sales); }第二步算出每个分类销售额占榜首销售额的比例。这里用相对比例而不是绝对百分比是因为如果直接用每条数据除以总销售额进度条之间的差异会不明显视觉上满屏都是细短的条没有层次感。相对到最高值的比例条与条之间的差距就非常清晰const maxSales sortedData[0].sales; const percent Math.round((item.sales / maxSales) * 100);第三步用 map 方法把数组转换成 HTML 字符串一次性插入到排行榜容器里。很多人初学时会用循环一次次 appendChild这样也不是不行但整体重绘时容易造成页面反复重排。我推荐用字符串拼接加 innerHTMLfunction renderRankList() { const sortedData getRankList(salesData); const maxSales sortedData[0].sales; const listHTML sortedData.map((item, index) { const percent Math.round((item.sales / maxSales) * 100); const rank String(index 1).padStart(2, 0); return li classrank-item span classrank-num rank-${index 1}${rank}/span span classrank-name${item.category}/span div classrank-bar div classrank-bar-fill stylewidth: ${percent}%;/div /div span classrank-value¥ ${item.sales.toLocaleString()}/span /li ; }).join(); document.getElementById(rankList).innerHTML listHTML; }这里有几个细节值得展开说。padStart(2, 0)能让排名数字变成 01、02、03 这种两位格式视觉上对齐、美观。toLocaleString()能让数字自动加千分位分隔符变成 43,620 而不是 43620这个细节在演示时很加分。百分比宽度直接以内联样式写在元素上可以保持 JS 对数据的控制权避免 CSS 里还要维护一套对应关系。3.3 数据刷新与动态效果大屏项目最忌讳的就是“静态死数据”。哪怕没有后端也要通过定时器模拟数据变化让图表和数字动起来。常见玩法是每隔一段时间给数据做一次扰动然后重新排序、重新渲染。这个过程中排名可能会变化观看者就能看到榜单“跳动”的动态感。function updateData() { salesData.forEach(item { item.sales Math.round((Math.random() - 0.3) * 2000); item.sales Math.max(item.sales, 1000); }); renderRankList(); } setInterval(updateData, 3000);注意这里随机增量是(Math.random() - 0.3)也就是多数时候销售额上涨、少数时候轻微下滑这样数据走势更接近真实场景不会出现所有数据同时乱跳的虚假感。每次刷新后榜单前三名的变动是最抓眼球的因为前三名的样式和其他名次不一样。3.4 前三名高亮用 CSS 类控制视觉层级排行榜大屏必须有视觉焦点最通用的做法就是前三名高亮。第一名用金色渐变第二名用银色系第三名用铜棕色系从第四名开始回到统一的暗色风格。在渲染代码中我根据索引给前三名单独添加类名const rankClass index 3 ? rank-top rank-top-${index 1} : ;对应 CSS 里三个名次的排名序号和进度条颜色分别定义.rank-top-1 .rank-num { background: linear-gradient(135deg, #f6d365, #fda085); color: #1a1a2e; font-weight: bold; } .rank-top-2 .rank-num { background: linear-gradient(135deg, #c4c4c4, #e8e8e8); color: #1a1a2e; } .rank-top-3 .rank-num { background: linear-gradient(135deg, #cd7f32, #e8a05c); color: #1a1a2e; }如果榜首数据和其他数据差距特别大还可以给第一名单独做一个“冠军光晕”效果比如用 box-shadow 在进度条外层加一层柔光。视觉效果非常突出而且实现成本极低。4. 可视化增强进度条、数据卡片与柱状图4.1 为什么排行榜旁边还要配图表很多初学者会问已经有排行榜了还需要图表吗这个问题我从实际演示角度回答你需要。排行榜能告诉你名次但很难直观告诉你“第一名比第二名多多少比第八名多几倍”。柱状图就是为了补上这个“量级感知”的空缺。我在大屏中间栏放了一个横向柱状图数据和左侧排行榜完全同源让观看者既能看到名次列表又能通过柱子长度感受差距。4.2 用 CSS 直接实现横向柱状图不引任何图表库用 CSS 也能做出漂亮的横向柱状图。原理很简单把每个分类做成一行里面放一个容器再用宽度百分比表示数值大小。div classchart-row span classchart-label数码家电/span div classchart-track div classchart-bar stylewidth: 87%;/div /div span classchart-value43,620/span /div.chart-bar { height: 14px; border-radius: 4px; background: linear-gradient(90deg, #36d1dc, #5b86e5); transition: width 1s ease; box-shadow: 0 0 8px rgba(91, 134, 229, 0.6); }这里最关键的是给进度条加了transition: width 1s ease数据更新时条会从原来的宽度平滑拉长或缩短到新宽度。这个动画是大屏“活起来”的点睛之笔成本只有一行 CSS。注意用 CSS 实现图表时数据变化后要重新计算百分比并更新内联样式。更新时最好先清空容器再重新渲染保证动画都是从初始状态开始不会出现新条覆盖旧条的问题。4.3 数据卡片把核心指标单独放大排行榜之外我建议在页面顶部或者中部放 3 到 4 张指标卡。这个页面里我放了总销售额、订单总数、客单价、目标完成率四个维度。每个卡片风格统一上边一个小标签中间一个巨大数字底部一条迷你趋势线或者进度环。div classmetric-card p classmetric-label总销售额/p p classmetric-value idtotalSales¥ 194,150/p p classmetric-footer较昨日 8.6%/p /div指标卡的数值同样由 JS 计算和更新。比如总销售额就用 salesData 数组 reduce 方法算出来const totalSales salesData.reduce((sum, item) sum item.sales, 0); document.getElementById(totalSales).textContent ¥ totalSales.toLocaleString();这种“排行榜展示结构、数字卡片展示总量、柱状图展示对比”的三件套组合基本覆盖了大屏数据展示的所有基础形态。下次你想做其他主题的大屏比如学生成绩榜、设备巡检榜、能耗监控榜把数据源替换掉页面结构完全可以复用。4.4 升级路线什么时候引入 ECharts如果你的比赛主题需要更丰富的可视化效果比如地图、折线趋势、环形图那纯 CSS 就有点吃力了这时候可以引入 ECharts。这是大屏升级最常用的方案。在 HTML 中通过 CDN 引入script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script然后初始化一个柱状图实例const chart echarts.init(document.getElementById(chart)); chart.setOption({ grid: { left: 80, right: 20, top: 20, bottom: 30 }, tooltip: { trigger: axis }, xAxis: { type: value, axisLabel: { show: false } }, yAxis: { type: category, inverse: true, data: categories, axisLabel: { color: #fff } }, series: [{ type: bar, data: sales, barWidth: 12, itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [ { offset: 0, color: #36d1dc }, { offset: 1, color: #5b86e5 } ]) } }] });这里用inverse: true把 y 轴翻转成从高到低排列正好对应排行榜的名次顺序。引入 ECharts 后数据更新时调用chart.setOption就会自动过渡动画比自己写 CSS 省心不少。但注意图表库只是一个工具页面整体布局、配色、数据组织才是大屏的灵魂这两点没做好就算用再炫的图表库也救不回来。5. 大屏适配与常见问题排查5.1 大屏分辨率适配transform scale 方案大屏项目第一个绕不开的坑就是分辨率适配。你按 1920x1080 做好的页面放到 2K、4K 屏上会偏移放到笔记本上又超出屏幕怎么办我强烈推荐 transform scale 等比缩放方案。思路是页面主体.screen始终按 1920x1080 设计然后用 JS 计算屏幕可视窗口和设计尺寸的缩放比例把整个页面等比缩放并居中。function scaleScreen() { const designWidth 1920; const designHeight 1080; const scaleX window.innerWidth / designWidth; const scaleY window.innerHeight / designHeight; const scale Math.min(scaleX, scaleY); const screen document.getElementById(screen); screen.style.transform scale(${scale}); screen.style.transformOrigin left top; const gapX (window.innerWidth - designWidth * scale) / 2; const gapY (window.innerHeight - designHeight * scale) / 2; screen.style.marginLeft gapX px; screen.style.marginTop gapY px; } window.addEventListener(resize, scaleScreen); scaleScreen();这套方案我实测下来非常稳。要注意两点一是用Math.min取较小缩放比例保证页面完整可见不会出现某一边被裁剪二是 transformOrigin 要设置成left top方便计算居中偏移量。如果屏幕特别大比如 4K 显示器建议把设计尺寸策略调整为 2K 基准或者接受像素模糊的结果——大屏在 4K 下完全无模糊是需要换矢量字体或者 SVG 的成本太高比赛演示阶段通常不必纠结这个。5.2 字体大小不随缩放变化怎么办有朋友会遇到一个问题页面整体已经被 scale 缩放了但某些字体看着还是偏小或者偏大。这是因为字体大小如果写在 px 里会在 scale 缩放时跟着整个页面一起变。如果你希望字体保持独立大小用 rem 单位配合根元素 font-size 动态计算即可。大屏项目里我一般这样处理标题字号 36px、大数字 48px、正文 20px、辅助文字 16px。整体调完之后用人眼在 2 米外看一眼页面如果最下面的辅助文字还能看清说明字号及格了。记住一个原则大屏是给“远处看”的字体宁可大一点不要为了放更多内容把字缩得跟手机端一样。5.3 数据更新时排行榜闪动或者跳动出现排行榜闪动绝大多数情况是渲染时机问题。比如 setInterval 定时器刷新数据时数据还在变化中就被插入 DOM或者新旧数据交替时列表长度不一致导致布局抖动。解决办法有两个层面。第一数据层面更新数据时同步计算排序和百分比不要分步骤操作数组第二DOM 层面给榜单项的进度条加transition属性让宽度变化平滑过渡而不是瞬间跳变。如果跳变严重还可以用requestAnimationFrame做数字滚动动画处理但比赛项目里先把 1 秒 transition 用顺手就足够了。5.4 项目文件结构组织源码放在文末读者拿到手第一件事应该是能跑起来所以文件结构要清爽。我推荐这样组织sales-rank-dashboard/ ├── index.html ├── css/ │ ├── base.css │ └── style.css ├── js/ │ ├── data.js │ └── main.js └── README.mddata.js 里只放模拟数据main.js 里放渲染和更新逻辑。index.html 在 body 结束前引入这两个 JS注意先后顺序先引 data.js再引 main.js否则 main.js 访问不到数据变量。本地预览直接用 VS Code 的 Live Server 插件双击打开 html 也基本能用但涉及 ES6 module 的话就必须起服务了。6. 比赛答辩与作业展示的加分细节6.1 评委到底在看什么带过不少学生项目我总结评委对大屏类作品的评判点按权重排序大概是演示的流畅度和稳定性、数据可视化的直观性、页面美观度、技术实现的合理程度、有没有真实的业务逻辑。很多人误会“效果越炫越好”于是往页面里塞粒子动画、3D 旋转、音乐播放结果演示时动画卡顿评委重点全跑偏了。其实一个干净、规整、数据逻辑清晰的大屏比堆特效的处理效果要好得多。你可以在答辩 PPT 里放“系统架构”和“数据处理流程”而页面本身保持克制和高速响应。6.2 三个低成本高加分的扩展方向如果做完基础版还有时间我建议优先做这三个扩展点性价比非常高。第一个把静态 mock 数据换成 10 条左右的分类数据并且模拟“实时刷新”。这个最基本的动态化就能让评委确认你是“活数据”而不是写死的静态页面。答辩时可以加一句“这套代码预留了 fetch 接口位置后端就绪后可以把模拟数据直接替换为真实数据”。第二个做一个排名变化的趋势提示。比如个上榜分类前面加一个小箭头销售额上升显示红色向上的箭头销售额下降显示绿色向下的箭头。实现不复杂在原有数据里加一个 preSales 字段更新时对比即可。箭头会让页面的信息量瞬间提升一个档次。第三个加一个底部时间轮播区域展示近七日的销售趋势迷你图。这个用 ECharts 的折线图几行就能搞定但会让页面显得更丰满也更贴合“大数据可视化”的主题。6.3 答辩时怎么讲这个项目如果你要拿着个项目去答辩或者比赛我建议按照“需求—方案—实现—效果—扩展”这条线来讲。先描述业务场景销售团队需要实时了解各品类销售情况和排名变化再讲设计方案用大屏展示排行榜、指标卡和柱状对比图接着讲实现细节数据如何组织、排序如何完成、如何更新渲染最后现场演示一次数据动态刷新并指出项目的扩展空间。不要从头讲 HTML 是什么、CSS 是什么评委对基础概念没有兴趣。把时间花在“数据怎么处理”和“为什么这样设计界面”上更容易拿到高分。如果你对项目里的每一行代码都能解释清楚尤其是我上面提到的 sort 排序、reduce 求和、scale 适配那就算评委临场深挖你也不会慌。这个项目我前后做了好几版最初版本只有单调的静态排行榜后来逐步加了数据卡片、横向柱状图、动态刷新和缩放适配才算真正有了大屏的感觉。做下来最深的体会是大屏项目的难点从来不在某一个特效上而是如何把一堆零散的数据组织得有逻辑、有层级、有视觉重点。把这个想明白了剩下的事情无非是 HTML 搭骨架、CSS 上妆、JS 注入灵魂。后面你换主题做其他大屏的时候这套思路可以完整地复刻过去。