我上周做内部技术分享的时候,又被PPT折磨了一次。讲的是前端性能优化,结果自己先被Keynote的性能折腾得够呛:改了一个标题字号,整页版式跟着错位;从编辑器里复制进来的代码块,粘贴后高亮丢得一干二净;演示时想放大一张截图,动画卡成了逐帧播放。台下坐着的都是写代码的同事,那一刻我差点直接把浏览器里的官网Demo当演讲稿。散会之后我认真想了想:我本来就是做前端的,为什么做演示稿的时候,反而把自己最擅长的一整套工具链全扔了?
从那次开始,我把对外分享用的Slides全部改成了前端方案。这里说的Frontend Slides,不是某一个固定开源项目的名字,而是用HTML、CSS、JavaScript以及围绕它们的前端框架去制作演示文稿的一套方法。它可以是一个手写的单页面,也可以基于reveal.js、Slidev这类现成工具来做。这篇文章不打算只推荐某个“最好”的框架,而是把前端Slides从原理、选型到实操的完整链路讲清楚:核心代码为什么这么写、工具到底怎么选、演示现场会遇到什么幺蛾子、最后怎么部署成一个所有人打开链接就能看的在线稿件。如果你是前端从业者,或者经常做技术分享,哪怕完全没用过代码写Slides,按这条路线走一遍也能上手。
1. 先想清楚:代码写Slides到底是在解决什么问题
1.1 传统PPT最让人难受的四个场景
很多人一提PPT就说“它够用了”,这话没毛病,日常汇报确实打开Keynote或者PowerPoint拖几下就行。但一旦你讲的领域偏技术,问题就来了。
第一个场景是代码展示。技术演讲里离不开代码片段,直接从IDE复制进PPT,字体缩进偶尔会乱,高亮基本全丢;你只能手动套一个“代码样式”的文本框,行号、关键字颜色、注释颜色全部自己调。讲三页代码没问题,讲三十页代码,光调格式就够加班。
第二个场景是版本管理。PPT本质是二进制文件,公司里两个人同时改一个演示稿,用网盘同步大概率互相覆盖。就算用Git管理,二进制文件也没办法做正常的diff,谁也说不清楚上一次“微调”到底改了哪一页。
第三个场景是临时改动。演讲前两小时某位负责人跑来说“这里加一页、那里删一段”,用PPT改会牵涉到版式、母版、动画序列。前端Slides里,加一页就是加一段Markdown或一个组件,干净利落。
第四个场景是跨设备观看。现在很多分享不再是会议室里一群人看投影,而是线上会议、直播、录屏,PPT需要导出成PDF或者录屏视频。前端Slides天然就是网页,分享一个链接,观众在手机、平板上都能看,不需要安装任何办公软件。
1.2 前端Slides真正解决的和解决不了的
把Slides当成一个前端项目以后,很多传统痛点自然就没了:代码高亮由Shiki或者Prism来处理,所见即所得;整个项目可以放进Git,每次修改都能review;构建产物是静态站,部署以后随时更新链接,观众打开永远是最新版;样式用CSS控制,字号、间距、主题色全部可复用。
但我也得泼一点冷水。前端Slides不是万能药,它解决不了“不会排版”的问题。PPT擅长的是可视化拖拽,你随手放一张图、拖一个文本框、加个箭头就能出效果。前端方案里,这些都要通过布局代码来完成。如果你只想做一份很随意的图文汇报,又不想学CSS,前端Slides的初期效率大概率比PPT低。
另外,像手写批注、现场圈画、白板演示这类场景,PPT配合触控笔确实更方便。前端Slides并不是要取代PPT,它更适合内容密度高、代码多、需要版本维护、需要以网页形式分发的场景。
1.3 谁适合改用前端Slides
我的判断标准很简单,符合下面任一条就可以认真考虑前端方案:
- 分享内容里代码占比高,需要高质量语法高亮,比如框架原理、工程化、源码解析。
- 你需要把同一套演示稿在不同场次反复讲,每次只改数据和局部内容。
- 你希望演示稿参与代码评审,让同事通过Git提意见。
- 你希望演讲结束后,观众拿到一个能够继续交互的链接,而不是一份静默的PDF。
- 你所在团队本身就有前端工程化基础,愿意为一次高质量分享多花一两个小时。
反过来说,如果这份演示稿是给客户看的花哨提案,强调视觉冲击力,或者你只有十分钟准备时间,对技术细节无感,那还是用回传统工具吧,别和自己过不去。
2. 核心原理:一张Slide本质上就是一个视图
2.1 先忘掉“页”的概念,想成“路由”
传统PPT的一页,在浏览器里可以理解成一张独立的视图。前端Slides所有花活,本质都是在管理“当前应该显示哪一块内容”的状态。
我见过很多人第一次接触这类工具时,以为Slides是某种魔法,其实背后的模型非常简单:每一个Slide就是一个DOM节点,或者是React/Vue里的一个组件。前端框架根据当前页码决定渲染哪一个节点,切换页码就是修改页码状态的更新过程。
这和我们平时做页面路由非常像。浏览器路由分为hash路由和history路由,Slides工具往往选择hash路由。原因很直接:hash变化不会触发页面刷新,而且刷新以后还能停留在当前页;用户手动改地址栏里的#/3也能跳转到指定页。
2.2 不用框架,十几行代码也能跑通切换
为了让你彻底放心,可以先用原生HTML和JavaScript演示一下最核心的切换逻辑。假设页面上有这么几个Slide容器:
<section class="slide active">第一页</section> <section class="slide">第二页</section> <section class="slide">第三页</section>对应的JavaScript只需要监听hashchange事件,把当前hash解析成页码,再切换对应节点的类名:
function updateSlide() { const hash = location.hash || '#/0'; const index = parseInt(hash.replace('#/', ''), 10) || 0; document.querySelectorAll('.slide').forEach((el, i) => { el.classList.toggle('active', i === index); }); } window.addEventListener('hashchange', updateSlide); updateSlide();CSS里把非当前页隐藏起来:
.slide { display: none; } .slide.active { display: block; }这样就已经具备了最基础的Slides能力:浏览器前进后退可以切换页面,刷新后停留在当前页。所有成熟工具做的,无非是在这个基础上增加过渡动画、嵌套布局、演讲者备注、代码高亮、自动缩放等能力。
2.3 一屏正好放一张Slide:缩放适配怎么做
前端Slides和普通网页一个显著区别是:普通网页可以纵向滚动,但Slide必须保证在某个固定尺寸下完整展示。通常设计稿尺寸是1920x1080或者1280x720。
直接给每个Slide设置固定宽高听起来简单,但观众屏幕大小不一,投影分辨率也千差万别。常见做法是设定一个基准视口尺寸,再动态计算缩放比例,用CSS的transform: scale()把Slide整体缩放到正好填满可用区域。
比如设计稿宽960、高540,当前视口是1920x1080,缩放比例就是Math.min(1920/960, 1080/540),取两个比例里的较小值可以避免溢出。窗口变化时监听resize事件重新计算一次。这就是很多Slides框架“自适应屏幕”的核心逻辑,原理并不复杂。
2.4 为什么不是所有网站都适合这套机制
理解了这个原理,你也会明白为什么前端Slides不适合用来做长文章。它的核心是“锁定视口”,所有内容必须被塞进一屏。一旦某页内容太长,只能在Slide内部滚动,体验会非常割裂。搜索引擎也不喜欢这种隐藏内容的方式。
所以,前端Slides的定位应该是“演示场景下的应用”,不是普通的文档站点。你可以在旁边附一个链接给观众看完整文章,但不要把技术博客改写成Slides。这是两个完全不同的信息载体。
3. 选型对比:手写一套、reveal.js、Slidev该怎么挑
3.1 手写方案的定位和边界
自己手写Slides的优势是零依赖、完全可控。如果你只需要十几页,每页内容就是标题加几句要点,又不想引入构建工具,那么原生HTML加几十行CSS就是一个很好的方案。我早期做过一个团队内部的黑客松分享,整个项目只有一个index.html和一个style.css,部署到Nginx就完事,维护成本极低。
但手写方案的上限也很明显:代码高亮、演讲者备注、快捷键、打印导出、组件化,这些能力都需要你自己造轮子。尤其当你需要把一页Slide拆成多个小组件复用,或者加入复杂的代码展示效果,手写成本会指数级上升。建议把“手写”当成理解原理和应付极简需求的备选方案,而不是长期主战方案。
3.2 reveal.js:稳定成熟的老牌选择
reveal.js从2011年前后就存在了,生态非常稳定。它采用纯HTML结构,一个<section>就是一张Slide,支持Markdown语法,但整体还是“HTML为中心”的使用方式。主题丰富,插件多,比如代码高亮、注释、拼图、自动播放等。
用reveal.js做Slides,适合喜欢自己掌控HTML结构的人。你可以把任意HTML、CSS、JS嵌进去,自由度很大,也因此比较容易写出“一次性”的页面代码。它的缺点是整体开发体验偏传统,如果你已经习惯Vite、Webpack这一套现代前端工程化流程,会觉得它在构建和组件化方面不够顺手。
3.3 Slidev:Markdown驱动,为开发者定制的现代方案
Slidev是我目前最常用的方案。它是基于Vite和Vue 3构建的,核心思路是“把内容写进Markdown,把交互交给组件”。每一页Slide就是Markdown里用---分隔的一节,头部可以用YAML配置主题、布局、字体等元信息。
和reveal.js相比,Slidev更贴近“写文档”的习惯。分享内容本身是纯文本,方便Git diff,代码高亮内置了Shiki,支持常见的代码编辑器配色。演讲者视图、录屏模式、远程控制这些功能都内置了,不需要额外拼插件。
由于它底层是Vue应用,你可以在Markdown里直接使用Vue组件,甚至把复杂图表封装成组件,按需引入。这个特性让它既能快速写内容,又能应对复杂定制场景。
3.4 选型对比:一张表把决策讲清楚
下面是我自己总结的对比表,维度不一定全,但覆盖了最常见的判断点:
| 维度 | 手写 | reveal.js | Slidev |
|---|---|---|---|
| 上手成本 | 最低 | 较低 | 中等 |
| 代码维护体验 | 差,全靠自己 | 一般,HTML为主 | 好,Markdown为主 |
| 代码高亮 | 需手动引入 | 插件支持 | 内置Shiki |
| 主题定制 | 自己写CSS | 主题丰富 | 主题可配置,可组件化 |
| 组件化 | 差 | 较弱 | 强,Vue组件 |
| 打印导出 | 自实现 | 有导出插件 | 内置导出命令 |
| 远程控制 | 自实现 | 有现成方案 | 内置远程控制器 |
| 适合场景 | 极简演示 | HTML老手,快速部署 | 技术分享、文档化演示 |
3.5 我的实际推荐
遇到新项目,你不需要在三个方案里纠结太久。我的习惯是:如果这次分享内容很多、代码量不小,就直接选Slidev;如果公司内部已经有了一个可用的reveal.js模板,要求快速修改,我就在它上面改;如果只是临时给组内讲十分钟,连依赖都不想安装,那我宁可用手写HTML也不去开一个重型工程。
选型最重要的是匹配场景,不是追求最新技术栈。框架本身不是生产力,内容才是。
4. 从零开始:用Slidev做一份带代码高亮和演讲者备注的Slides
4.1 环境准备与项目初始化
我用Slidev举例,因为它的上手路径最接近“正常前端项目”。你本机需要Node.js 18及以上版本,然后打开终端执行:
npm create slidev@latest my-slides命令运行后,它会问你是否安装依赖,选择“是”。初始化完成后进入目录,启动开发服务器:
cd my-slides npm run dev浏览器打开http://localhost:3030,你就能看到一页默认的示例Slide。Slidev的开发模式改了Markdown或代码会热更新,这一点和普通Vite项目完全一致,改完立即刷新页面,不用手动重启。
4.2 第一份slides.md怎么写
Slidev的核心文件是项目根目录下的slides.md。打开它,你会看到类似下面的结构:
--- theme: seriph --- # 前端性能优化 今天聊三个方向 --- # 第二页 - 指标 - 工具 - 案例 --- # 第三页 一张图胜过千言万语每一页Slide用一行---分隔。文件最顶部的---包裹区域是YAML配置,用于设置主题、布局、字体等元信息。Markdown里的#、-等语法最终会被渲染成网页内容。
如果我想展示一段带语法高亮的代码,只需要像写普通Markdown一样写代码块,Slidev会自动用Shiki高亮:
--- # 代码页 --- ```javascript const sum = (a, b) => a + b; console.log(sum(1, 2)); ```你不需要手动指定高亮主题,它默认会跟随当前代码编辑器的配色方案。这一点对技术分享真的太重要了,省掉了大量粘贴代码后调整格式的琐碎工作。
4.3 代码高亮、演讲者备注和快捷键
在Slidev里,演讲者备注写在每页Slide末尾的注释里:
--- # 第二页 --- - 指标 - 工具 - 案例 <!-- 这里写演讲者备注,观众不会看到 -->进入演示模式后,按键盘上的P键可以打开演讲者视图,当前页、下一页、备注、计时器都会显示在同一屏上。如果你的外接显示器或者副屏放不下了,可以把演讲者视图拖到另一块屏幕,主屏幕继续放全屏Slides。
我常用的快捷键有这些:
- 空格或右方向键:下一页
- 左方向键:上一页
P:切换演讲者视图F:切换全屏O:打开总览模式,方便跳页D:切换深色模式
这些快捷键不是花架子,当你讲到一半被观众打断提问时,用O快速跳回前面的某一页,比连续按十几次左方向键体面得多。
4.4 换主题和布局:别让默认样式绑架你
Slidev自带几个主题,比如seriph、default、glass等。用主题只需要在YAML头部修改:
--- theme: default ---如果默认主题的标题颜色、正文字号、背景色不够用,你还可以在项目根目录创建style/index.css,通过CSS变量覆盖主题样式。比如想让标题字体更大:
.slidev-layout h1 { font-size: 2.5rem; }针对一些固定的布局需求,Slidev提供了layout字段,例如左右两栏布局:
--- layout: two-cols --- # 左栏内容 - 第一点 ::right:: # 右栏内容 - 第二点这种布局在对比方案、展示代码和截图时非常实用。你不需要自己写一行布局CSS,只需要在正确的位置用::right::切分左右两栏。
从建项目到写出第一份像样的分享稿,熟练以后大概三十分钟以内就能完成。前几次可能慢一点,因为你要熟悉布局语法和主题配置,但一旦踩顺了,效率真的比打开一个空白PPT再一点点排版高得多。
5. 演示现场最常翻车的三个地方:字体、动画和远程翻页
5.1 字体加载带来的“演示机翻车”
有一次分享前,我把Slides部署好了,临时换了台演示电脑,一打开发现标题字体全变了,中文变成了宋体,英文变成了奇怪的无衬线体。原因很简单:我在开发机上安装了某个商业字体,但没有通过Web Font的方式引入,也没有指定可靠的字体回退方案。
前端Slides是跑在浏览器里的,最终效果取决于那台机器的字体环境。如果依赖本机字体会导致不同设备表现不一致。跨设备演示前,要么在项目里把字体打包成Web Font,要么明确指定字体系列栈,把系统中常见的字体放在回退列表里:
body { font-family: "Inter", "PingFang SC", "Microsoft YaHei", sans-serif; }另外,如果你要在无网环境下演示,字体文件必须打进静态资源目录,不能依赖在线字体服务。这个坑我踩过一次之后,都会在演示前把网络断掉测一遍所有页面,确保离网也完全可用。
5.2 动画:为解释服务,不为炫技服务
前端Slides最大的优势之一是可以写丝滑的CSS过渡、SVG动画甚至Canvas动画。但我也见过不少人把Slides做成了“交互动效演示”,每页都有飞入飞出、旋转、缩放,结果内容反而被动画淹没了。
分享时听众的注意力很宝贵。动画应该用来解释“动态变化”,比如性能指标升降、数据结构流转、组件生命周期,而不是让标题从左向右飞进来。Slidev默认的过渡动画已经足够克制,如果你要自定义页面切换,建议统一方向和时长,不要每页都换一个花式效果。实测下来,动画时长控制在200到500毫秒之间最舒服,太短像闪屏,太长又拖节奏。
5.3 远程翻页:手机控制端没反应怎么办
线下演示时,把笔记本电脑放到演讲台,人却站在屏幕前走来走去,这时就需要远程翻页。Slidev内置了远程控制功能:启动npm run dev或构建预览后,浏览器地址栏会出现一个小图标,点击后生成二维码,手机扫描就能进入遥控页面。
听起来很美好,但实际演示时最容易翻车的是“手机和电脑不在同一个局域网”。很多公司Wi-Fi默认开启了AP隔离,手机能连Wi-Fi但访问不到电脑上的服务。我现在的做法是:手机开热点,电脑连上同一个热点,先测试一下能否访问网址,再进入演示环节。这个操作看起来笨,但能避免现场尴尬。
另外,遥控页只能触发翻页,不能替代可靠的物理遥控器。如果条件允许,我建议准备一根备用HDMI线,或者直接用键盘翻页。远程控制是加分项,不是唯一方案。
5.4 备用方案:导出PDF兜底
再成熟的技术方案,也架不住现场投影仪抽风、视频线接触不良、系统更新强制重启。所以我现在每次分享前,都会用Slidev的导出功能生成一份PDF,放在手机或平板上:
npx slidev export这个命令会启动无头浏览器,把每一页Slides截图排版成PDF。PDF不存在字体缺失、浏览器兼容性问题,任何设备都能打开。就算现场电脑彻底废了,我也能掏出平板照着PDF讲,至少不会让观众干坐着。
PDF不是用来替代网页版,而是作为兜底。如果你讲的内容里有大量动态演示,PDF可能没法覆盖,可以在对应页放一张截图或者二维码,引导观众现场打开互动Demo。
6. 构建与部署:把演讲链接发给与会者
6.1 构建静态站点的标准流程
前端Slides的最终交付形态应该是一个静态网站目录。Slidev的构建命令很简单:
npm run build构建完成以后,项目里会多出一个dist目录,里面是纯静态的HTML、CSS、JS资源。把这个目录扔到任意静态服务器上就能运行,不需要Node环境。
需要注意,如果你要部署到GitHub Pages这种带子路径的地址,比如https://yourname.github.io/my-slides/,必须给项目配置正确的base路径。常见做法是在项目根目录创建vite.config.ts:
export default defineConfig({ base: '/my-slides/', plugins: [vue()] })如果不配置base,构建出的资源路径可能从根目录开始找,部署上线后会出现样式丢失、页面白屏的情况。这个坑是静态部署里的经典问题,几乎每个人都会遇到一次。
6.2 部署和更新:给观众一个“永远能打开”的链接
静态站点可以部署到各种平台,比如GitHub Pages、Netlify、Vercel、对象存储加CDN,甚至你内部的一台Nginx服务器。我的习惯是:内部技术分享放到内网静态服务器,外部分享部署到线上托管平台,并开启自动部署。每次改完内容,提交Git,CI自动跑构建和发布,观众拿到手的一直是最新版本。
还有一点值得注意:如果你不想让Slides被搜索引擎收录,或者不想让人随意修改,可以部署后用访问控制插件限制权限。但大多数技术分享场景下,公开部署反而更好,观众会后能从链接里看到你的代码示例和引用资料,比发一份只会让人“只读”的PDF更容易传播。
6.3 导出PDF的格式问题
用npx slidev export导出PDF时,有几个小问题容易忽略。一是动画状态,如果一个元素默认是隐藏的,导出后可能不会显示,你需要确保关键内容在静态状态下完整可见。二是中文和特殊字符,如果代码或图表里包含emoji和特殊符号,要检查PDF里是否被无头浏览器正确渲染。三是尺寸,默认导出是宽屏16:9,但如果你某几页用了从右到左的滚动布局,导出后可能错位。
我的习惯是导出后快速翻一遍PDF缩略图,重点看含有代码高亮、图表和上下标的部分。别信“代码生成的一定没问题”,构建环节总会带来一些意外。
7. 进阶:把Slides当成一套组件库来维护
7.1 把复用内容拆成组件
当你做技术分享的频率上来以后,会发现自己总在重复做类似的东西:标题页、目录页、要点页、代码对比页、数据指标卡。Slidev里可以用Vue组件把这些“高频页面骨架”抽象出来。
在Slidev项目的components目录下新建一个MetricCard.vue,写一个简单的组件来展示指标名称和数值:
<template> <div class="metric-card"> <span class="metric-name">{{ name }}</span> <span class="metric-value">{{ value }}</span> </div> </template> <script setup> defineProps({ name: String, value: String }) </script>然后在Markdown里直接引入:
<MetricCard name="FCP" value="1.2s" />这样,后续分享里要改指标的时候,只需要改数值,不需要在每个Slide上重新排版。分享稿变成了“数据配置 + 少量排版描述”,维护成本降了一个量级。这就是把Slides当工程做和当文档做的本质区别。
7.2 沉淀自己的主题样式
除了组件,你还可以把自己的品牌色、标题风格、代码块配色沉淀成一个主题包,或者至少写一份全局CSS。团队内部做分享时,所有页面风格统一,看起来就非常专业。这个统一感不是靠一页页调出来的,而是靠CSS变量和全局样式控制。
比如在style/index.css里定义主题颜色:
:root { --primary: #2563eb; --text: #1f2937; --code-bg: #f3f4f6; }然后在组件或Markdown引用的类中使用这些变量。以后想换主色调,只需要改一处,整份Slides跟着变。这个思路和设计系统的Token机制是一样的,只不过你服务的对象是演示内容。
7.3 可访问性:容易被忽略但很重要的细节
前端Slides做出来以后,不只是演讲现场有人看。会后发出去的链接,可能有观众在手机上刷、有人用屏幕阅读器听、有人因为配色不当看不清。所以可访问性要放在上线前检查一遍。
最基本的三件事:
- 文字对比度要足够,深色背景上不要放浅灰色小字。
- 所有图片和图表要有替代文字,方便屏幕阅读器描述。
- 键盘可以完整操作,Tab键能聚焦到交互控件,而不是只有点击才能翻页。
很多Slides框架默认把页面定位成“演讲屏幕”,可访问性细节需要自己补。比如给每一页加语义化标题、给链接加上说明文字、给状态变化提供提示。这些工作看起来琐碎,但在线上传播场景里,它决定了一部分人能不能真正看懂你的内容。
我自己每次分享完,都会把部署链接发到团队群里,让没去现场的同事也能自己打开看。前端Slides带来的这种“可分发、可维护、可变”的体验,已经让我很少回头再打开传统PPT了。如果你也想试试,别急着研究花哨的主题和动画,先把第一份slides.md跑起来,比什么学习路径都管用。