1. 为什么我又造了一个PPT工具轮子先坦白一件事我做过不下二十套PPT模板从年终汇报、项目复盘到产品发布几乎每个季度都要跟幻灯片打交道。每次打开空白演示文稿那种“从零开始排版”的窒息感相信做技术分享、做项目汇报的人都懂。市面上的模板站要么收费贵得离谱要么下载下来一堆占位符和花哨动画改起来比自己画还累。于是我就想能不能用一套纯文本驱动的方式把PPT的骨架和样式彻底分离让内容归内容、样式归样式改起来像改Markdown一样顺手。ppt-master就是在这个背景下折腾出来的。它不是一个在线设计平台也不是什么AI一键生成神器而是一套基于HTML/CSS的幻灯片框架配合一套约定式的目录结构和构建脚本让你用写网页的方式写PPT最后导出成PDF或者直接在浏览器里演示。核心解决三个问题排版一致性、内容可复用、版本可管理。适合谁用经常做技术分享的开发者、需要批量产出汇报材料的产品经理、以及任何受够了拖拽对齐的“PPT苦力”。我试过用纯Markdown转PPT的工具也试过直接用reveal.js但前者样式定制太受限后者每次都要写一堆HTML标签重复劳动太多。ppt-master的思路是你只写内容块样式由主题文件统一控制布局通过简单的类名组合来切换。听起来有点像“PPT界的CSS框架”实际上手之后做一套20页的汇报从起草到导出大概能控制在两小时以内而且后续改数据、换主题都是分钟级的事。2. 整体架构与核心设计思路2.1 为什么选择HTML/CSS而不是原生PPT格式原生PPT格式比如Office的XML结构虽然功能强大但它的文件结构对开发者极不友好。你很难用Git去diff两个版本的差异更别说做代码审查了。而HTML/CSS天生就是文本格式每一行改动都清清楚楚配合Git做版本管理谁在什么时候改了哪页的哪个数据一目了然。另一个考量是渲染一致性。原生PPT在不同设备、不同Office版本上打开字体、间距、换行都可能跑偏。而HTML/CSS在浏览器里的渲染是确定的只要字体文件打包进去在哪儿看都一样。导出PDF的时候也是基于浏览器引擎的渲染结果所见即所得。当然代价是失去了PPT的某些交互特性比如复杂的动画路径、嵌入Excel图表。但对于技术分享和项目汇报来说这些恰恰不是刚需。我们更需要的是代码块高亮、表格清晰、流程图可维护。这些用HTML/CSS做反而比原生PPT更顺手。2.2 目录结构约定与构建流程ppt-master的目录结构是约定大于配置的典型。一个标准的项目长这样my-deck/ ├── slides/ │ ├── 01-cover.html │ ├── 02-agenda.html │ ├── 03-problem.html │ └── ... ├── themes/ │ └── default/ │ ├── theme.css │ └── fonts/ ├── assets/ │ ├── images/ │ └── diagrams/ ├── build.js └── config.json每个slides/下的HTML文件就是一页幻灯片文件名前缀决定顺序。themes/放主题样式切换主题只需要改config.json里的一个字段。build.js负责把所有页面合并成一个可演示的HTML文件或者调用无头浏览器导出PDF。为什么用数字前缀而不是在文件里写顺序因为文件系统的排序是天然的你重命名文件就能调整顺序比在配置文件里维护一个数组要直观得多。而且数字前缀在文件管理器里一眼就能看出页数找起来快。2.3 主题系统的设计逻辑主题系统是整个框架的灵魂。我把一页幻灯片拆解成几个原子层画布层页面尺寸、背景、栅格层内容区域划分、排版层标题、正文、代码、表格的样式、装饰层页眉页脚、页码、品牌色块。主题CSS只负责定义这些层的样式变量比如:root { --slide-width: 1280px; --slide-height: 720px; --color-primary: #2c3e50; --color-accent: #e74c3c; --font-title: Source Han Sans, sans-serif; --font-body: Source Han Serif, serif; --font-code: JetBrains Mono, monospace; --spacing-unit: 8px; }页面HTML里只写语义化的类名比如section classslide layout-title-body具体长什么样完全由主题决定。这样换主题就像换皮肤内容一行不用改。我试过把主题变量做成JSON配置然后用构建脚本生成CSS但后来发现直接写CSS变量更灵活因为CSS本身就有级联和继承调试的时候在浏览器DevTools里改一下就能看到效果不用重新构建。3. 核心功能模块拆解与实操要点3.1 页面布局系统用类名组合代替拖拽布局系统提供了六种基础布局layout-cover封面、layout-title-body标题正文、layout-two-column双栏、layout-code代码为主、layout-image-full全图、layout-table表格。每种布局对应一套栅格规则你只需要在section上加上对应的类名内容就会自动排布。比如双栏布局section classslide layout-two-column div classcol h2左侧标题/h2 p左侧内容.../p /div div classcol h2右侧标题/h2 p右侧内容.../p /div /section栅格默认是等宽的但你可以通过col-1-3、col-2-3这样的类名来调整比例。这个设计借鉴了CSS Grid的命名思路但做了简化只保留最常用的几种比例。注意不要在页面里写内联样式来调间距那样会破坏主题的一致性。如果觉得默认间距不合适应该去改主题里的--spacing-unit变量让所有页面一起变。3.2 代码块高亮与行号控制技术分享离不开代码。ppt-master集成了Prism.js做语法高亮但做了一些定制代码块默认显示行号支持高亮特定行支持显示文件名标签。pre classcode>table classtable-striped table-compact thead trth指标/ththQ1/ththQ2/thth环比/th/tr /thead tbody trtd营收/tdtd1200/tdtd1450/tdtd classpositive20.8%/td/tr trtd成本/tdtd800/tdtd850/tdtd classnegative6.3%/td/tr /tbody /table.positive和.negative类会自动给数字加上绿色或红色方便观众快速捕捉关键变化。这个细节是从财报PPT里学来的比纯黑白表格的传达效率高很多。3.4 图片与图表的嵌入策略图片直接放在assets/images/下用相对路径引用。但要注意幻灯片里的图片尺寸是固定的所以最好提前把图片裁切成合适的宽高比。我一般用16:9或4:3分辨率控制在1920x1080以内避免文件过大。图表方面我推荐用SVG而不是PNG。SVG是矢量格式放大不会模糊而且可以用文本编辑器改颜色和文字。如果你用ECharts或D3生成图表可以直接导出SVG然后嵌入到页面里。这样换主题的时候图表的颜色也能跟着主题变量走。实操心得不要把图表做成截图。截图意味着每次数据更新都要重新截一次而且分辨率不可控。用SVG或者直接在页面里用Canvas画虽然前期麻烦一点但后期维护成本低得多。4. 从零搭建一套汇报幻灯片的完整流程4.1 环境准备与项目初始化首先确保你本地有Node.js环境版本建议在16以上。然后克隆项目骨架git clone https://github.com/yourname/ppt-master-starter.git my-deck cd my-deck npm installnpm install会安装构建依赖主要是puppeteer用于导出PDF和chokidar用于监听文件变化。如果你不需要导出PDF可以跳过puppeteer的安装能省下几百MB的磁盘空间。初始化完成后运行npm run dev会启动一个本地服务器默认监听3000端口。打开浏览器访问localhost:3000就能看到示例幻灯片。修改slides/下的任何HTML文件浏览器会自动刷新所见即所得。4.2 内容编写从大纲到页面我习惯先在纸上列大纲然后一页一页地写。每页的HTML结构很固定section classslide layout-title-body h2页面标题/h2 div classcontent !-- 正文内容 -- /div /section标题用h2因为h1留给封面。正文放在.content容器里这样可以统一控制内边距。如果一页内容太多可以考虑拆成两页或者用layout-two-column做左右分栏。写内容的时候我建议先把所有页面的骨架搭出来每页只写标题和要点然后再回头填充细节。这样能保证整体节奏不跑偏避免在某一页上过度雕琢。4.3 主题定制改颜色、换字体、调间距主题定制集中在themes/default/theme.css里。最常改的是颜色变量:root { --color-primary: #1a73e8; /* 主色用于标题和强调 */ --color-accent: #ea4335; /* 强调色用于高亮和警示 */ --color-bg: #ffffff; /* 背景色 */ --color-text: #202124; /* 正文颜色 */ }改完保存浏览器里立刻生效。如果你想让标题更紧凑可以调--spacing-unit比如从8px改成6px所有间距会按比例缩小。字体方面我建议把字体文件放在themes/default/fonts/下用font-face引入。不要用系统默认字体因为不同电脑上的默认字体不一样会导致排版跑偏。我一般用思源黑体做标题思源宋体做正文JetBrains Mono做代码这三套字体都是开源的可以放心打包。4.4 导出PDF与演示模式切换导出PDF的命令是npm run build:pdf这个命令会启动一个无头浏览器把每一页幻灯片渲染成PDF页面最后合并成一个文件。导出的时候要注意页面尺寸要和主题里定义的--slide-width和--slide-height一致否则会出现白边或者裁切。演示模式则是直接打开index.html按F键进入全屏用方向键翻页。我还加了一个P键按下去会显示当前页码和总页数方便控制进度。注意导出PDF之前一定要在浏览器里完整过一遍确认没有内容溢出或者图片加载失败。无头浏览器不会报这些错但导出来的PDF会有问题。5. 常见问题与排查技巧实录5.1 字体加载失败导致排版错乱这是最常见的问题。现象是本地预览正常但换一台电脑打开字体全变了文字溢出容器。原因通常是字体文件没有打包进去或者路径写错了。排查步骤打开浏览器DevTools看Network面板里字体文件是否404。检查font-face的src路径是相对路径还是绝对路径建议用相对路径。确认字体文件格式是woff2或woff不要用ttf因为ttf文件大且浏览器兼容性差。解决方法是把字体文件放在主题目录下用相对路径引用并且在构建的时候把字体文件一起复制到输出目录。5.2 代码块高亮失效或行号错位Prism.js的高亮依赖语言定义文件。如果你用的语言比较小众可能需要手动引入对应的语言包。行号错位通常是因为代码里有多余的空行或者制表符和空格混用。排查技巧在pre标签上加上>media (prefers-color-scheme: dark) { :root { --color-bg: #1e1e1e; --color-text: #e0e0e0; } }这样在支持暗色模式的系统上幻灯片会自动变暗晚上演示的时候不刺眼。如果你想让观众手动切换可以加一个按钮用JavaScript切换>.slide { counter-increment: slide; } .slide::after { content: counter(slide); position: absolute; bottom: 20px; right: 30px; }进度条可以用一个固定在底部的div宽度用JavaScript根据当前页数动态计算。这个功能在长时间分享的时候特别有用观众能知道还剩多少页。6.3 演讲者备注的隐藏与导出演讲者备注写在aside classnotes里演示模式下默认隐藏按N键可以切换显示。导出PDF的时候可以选择把备注导出到单独的页面或者直接忽略。aside classnotes 这里提醒自己重点讲一下第三季度的增长原因。 /aside这个功能是从Keynote的演讲者备注学来的但用HTML实现更简单就是一个隐藏的div需要的时候用JavaScript控制显示。6.4 用构建脚本自动生成目录页如果幻灯片页数很多手动维护目录页很麻烦。我写了一个小脚本扫描slides/目录下的所有文件提取每页的h2标题自动生成目录页的HTML。这样增删页面的时候目录自动更新不会漏掉。脚本逻辑很简单读取所有HTML文件用正则提取h2内容然后生成一个列表插入到02-agenda.html里。你可以把这个脚本挂在npm run dev的监听里文件一变就重新生成。6.5 性能优化图片懒加载与代码分割如果幻灯片里图片很多首次加载会比较慢。可以在img标签上加loadinglazy浏览器会自动懒加载。代码块如果特别大可以考虑用highlight.js的按需加载只加载用到的语言包。另外构建的时候可以把所有CSS和JavaScript内联到HTML里减少HTTP请求。对于本地演示来说一个文件比一堆文件方便得多拷贝到U盘就能走。7. 我踩过的坑与最后分享几个小技巧第一个坑是字体版权。一开始我图省事直接用了系统自带的微软雅黑结果导出PDF的时候在没有这套字体的电脑上打开排版全乱了。后来换成开源字体虽然风格上没那么“商务”但至少保证了跨平台一致性。如果你非要用商业字体记得把字体文件打包进去并且确认授权允许嵌入。第二个坑是过度设计。刚开始用这个框架的时候我总想把每页都做得花里胡哨加各种动画和渐变。后来发现观众是来看内容的不是来看设计的。现在我的原则是一页只讲一个观点配色不超过三种动画能省就省。简洁反而显得专业。第三个坑是版本混乱。有次汇报前夜我改了五版最后自己都分不清哪版是最新的。后来养成了习惯每次改完在config.json里更新一下版本号和日期导出PDF的时候自动带上版本信息。这样至少知道手里这份是什么时候的。最后分享一个小技巧用Git的tag来标记每次汇报的版本。比如v1.0-季度汇报、v1.1-修改数据这样回溯的时候可以直接checkout到某个tag不用在一堆commit里翻。而且tag的名字比commit hash好记多了。这个框架我用了大半年做了十几套汇报材料最大的感受是把精力从排版转移到内容上。以前做PPT一半时间在调对齐、调间距、调字体现在这些都由主题统一控制我只需要专注把逻辑讲清楚。如果你也受够了拖拽对齐不妨试试这个思路。