ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Google Code Prettify代码高亮实战:文件分工、接入与避坑指南

2026/9/2 21:13:08 拓冰建站 浏览量
Google Code Prettify代码高亮实战:文件分工、接入与避坑指南 简介这是一套基于 Prettify 的代码高亮资源包面向需要在网页或博客中展示源代码的开发者解决原生 pre/code 标签样式单调、阅读体验差的问题。压缩包共 3 个文件包含 2 个 JS 脚本与 1 个 CSS 样式表整体仅 14KBprettify.css 负责关键字、字符串、注释等语法元素的配色与字体样式prettify.js 提供多语言识别与高亮逻辑run_prettify.min.js 为压缩优化版可提升页面加载速度。三者配合只需引入 link 与 script 标签并对代码块添加 prettyprint 类名即可自动完成 HTML、CSS、JavaScript、Python、Java、C 等常见语言的高亮显示。该工具支持多语言自动识别无需手动配置每条语法规则文件体积小、耦合度低可无缝嵌入现有页面。资源已有 841 人学习适合前端开发者、技术博主及文档维护者快速集成专业级代码美化能力节省手写高亮规则的精力。 最近在整理旧博客的静态页面时又翻出了那套经典的代码高亮文件夹prettify.css、prettify.js、run_prettify.min.js。这三个文件几乎是十年前Web前端常见的标配放在今天依然能跑但很多朋友拿到手之后习惯直接全部引入结果页面要么没高亮要么样式乱飘。我花了一下午把接入流程重新捋了一遍顺便把VSCode和Cursor里那种“选中代码就高亮”的现象和网页端静态高亮的差异也理清楚了。这篇就从prettify的三个文件讲起说清楚各自分工、接入方式、常见坑以及什么时候该换更现代的高亮方案。如果你正在维护一个静态博客、导出HTML文档或者想把 Markdown 渲染后的代码片段变得好看一点prettify 这套方案完全够用。它不依赖构建工具不需要npm install也不用懂什么AST语法树把三个文件往目录里一放页面里加上对应类名就能出效果。但恰恰因为它“太简单”很多人反而没搞清楚文件之间的关系接出了不少奇奇怪怪的问题。1. 代码高亮方案选型为什么还选Prettify1.1 三个文件背后的真实分工prettify.css管的是“看起来好看”。代码要分色、加边框、背景色、行号样式全靠这一份样式表。它里面定义的是 token 级别的类名比如字符串用什么颜色、关键字用什么颜色而不是直接写死在某一个元素上。prettify.js管的是“怎么把代码拆开”。它负责扫描页面里带prettyprint类的代码块把代码内容按词法规则拆成字符串、关键字、注释、标签、属性等 token再包裹上对应的span class...。这个过程不需要网络请求纯本地计算。run_prettify.min.js则是一个 loader 加自动执行器。它的作用是加载 prettify 核心逻辑并在页面 DOM 加载完成后自动扫描并启动高亮。换句话说如果你直接引run_prettify.min.js通常不需要再手动引prettify.js也不用手动调用prettyPrint()但如果你手里只有prettify.js就必须自己等页面加载完成后手动触发。很多人把这三个文件全部塞进页面结果样式重复定义、解析逻辑跑了两遍反而拖慢首屏。其实最稳妥的组合是prettify.css加上run_prettify.min.js。除非你有特殊需求想完全控制高亮启动的时机否则prettify.js可以放着备用。1.2 选型对比Prettify、highlight.js、Prism 到底差在哪我在选方案的时候并不是没用过其他高亮库前前后后也试过 highlight.js 和 Prism。这里放一张我实际测试后的对比表方便大家按场景做决策。高亮方案体积语言支持主题数量行号维护状态Prettify较小常用语言额外语言需要加载对应 lang-*.js内置几套可自定义支持基本停滞但稳定highlight.js中等可按需打包190 种语言丰富插件支持活跃Prism小按需插件主流语言社区扩展丰富丰富插件支持活跃我最后没换的主要原因是旧博客系统已经在用 prettify替换所有历史文章的成本比较高。而且 Prettify 不需要构建步骤也不需要后端配合放到任何目录都能跑。对于“文章以静态 HTML 为主、页面里就是几段代码”的场景它完全够用。不过要注意Prettify 的语言识别能力和现在的新库相比偏弱尤其对 Vue 单文件组件这类带template、script、style自定义块的文件基本没法正确高亮。所以我后面的建议是如果博客里开始大量出现这类现代框架代码趁早用 Prism 或 highlight.js不要硬拖。2. 快速接入与配置细节2.1 标准的引入顺序别再全塞进 head很多教程会告诉你把link和script都放在head里这在小页面上没问题但并不是最优做法。样式可以放头部避免页面加载时出现未高亮的裸代码造成闪烁脚本最好放到/body前或者加上defer让高亮逻辑在结构解析完之后再执行。如果使用prettify.js手动控制标准写法是这样!DOCTYPE html html head link relstylesheet hrefprettify.css /head body pre classprettyprint lang-js codefunction hello() { return world; }/code /pre script srcprettify.js/script script document.addEventListener(DOMContentLoaded, function() { prettyPrint(); }); /script /body /html如果使用run_prettify.min.js脚本只需要一行script srcrun_prettify.min.js/script它会自动处理启动时机不需要包裹DOMContentLoaded。这里有个容易忽略的坑run_prettify.min.js在加载时会读取自身 URL 上的 query string 来决定加载哪些语言扩展例如run_prettify.min.js?langcsslangsql。如果你本地化了这份文件建议保持文件名稳定别经常改后缀否则语言扩展可能加载不齐。2.2 主题定制与配色修改prettify.css默认样式偏简单直接用的效果只能说“不难看”但离好看的博客还差一截。好在它的配色规则非常直白全部通过预定义类名暴露出来你完全可以覆盖。高频用到的 token 类名大概有这些.str字符串.kwd关键字.com注释.typ类型名.lit字面量.pun标点.pln普通文本.tagHTML/XML 标签.atn标签属性名.atv标签属性值.dec声明比如var、function.var变量名.fun函数名修改主题时不建议去直接改 prettify.css更好的做法是新建一个custom-prettify.css放到 prettify.css 之后引入然后按需覆盖。我常用的自定义样式大致是pre.prettyprint { background: #f8f8f8; border: none; border-left: 4px solid #4a90d9; border-radius: 6px; padding: 14px 16px; font-size: 13px; line-height: 1.6; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word; } pre.prettyprint .kwd { color: #0077aa; font-weight: 600; } pre.prettyprint .str { color: #d14; } pre.prettyprint .com { color: #999; font-style: italic; } pre.prettyprint .tag { color: #0077aa; } pre.prettyprint .atn { color: #905; } pre.prettyprint .atv { color: #d14; }这里面的white-space: pre-wrap值得单独说。prettify 默认把代码原样输出行太长时容易撑破页面布局。加上pre-wrap后长代码会按容器宽度自动换行同时保留缩进和空格兼顾可读性和布局稳定。2.3 行号显示与复制体验的取舍Prettify 自带行号支持只要在pre上加上linenums类就能显示行号。比如pre classprettyprint linenums lang-js codeconst a 1;/code /pre但默认行号是依赖li列表实现的复制代码时容易把行号一起复制出去体验不算好。如果你更看重“代码可一键复制”我建议放弃默认行号改用 CSS 自己画一个行号区。做法是在外层包一个容器用counter计数.code-block { counter-reset: line; position: relative; padding-left: 48px; } .code-block pre { counter-increment: line; }不过这个方案在连续多行代码块上实现起来要稍微绕一点更适合在生成 HTML 时用后端逻辑预处理。如果你只是想快速展示代码又不想处理复制行号问题那就干脆别加linenums代码干净多了。3. 常见问题与排查技巧实录3.1 run_prettify.min.js 加载失败我遇到过最普遍的现象是本地化之后脚本路径不对控制台报 404然后整页代码干脆没有高亮。排查思路其实很简单三步走先看浏览器 Network 面板里prettify.css和run_prettify.min.js有没有加载成功再确认页面是否通过file://协议打开如果用了相对路径某些浏览器对本地静态文件的限制会导致脚本不执行最后看控制台有没有报错比如跨域问题。注意如果你把 prettify 文件放在 CDN 上要保证 CDN 允许跨域访问否则脚本加载成功后也可能被浏览器拦截。本地使用时路径建议写绝对路径或相对根目录的路径避免嵌套目录变深后找不到。一个更隐蔽的问题是run_prettify.min.js加载了但页面代码块没有加prettyprint类。这个库不会扫描所有pre或code它只认类名所以别漏了。可以养成习惯在写 Markdown 时通过渲染规则自动把代码块统一加上prettyprint类。3.2 代码块没高亮或者只高亮了一部分这种情况通常发生在动态内容上。比如你通过 Ajax 把文章内容加载到页面上此时run_prettify.min.js的自动扫描已经执行完毕后来插入的代码块自然不会高亮。解决办法是等动态内容插入后手动执行PR.prettyPrint()。这里有一个容易踩的坑prettify.js解析过一轮之后会在代码内容里插入大量span。如果第二次调用prettyPrint()时原代码块仍然保留着上一次生成的span就可能出现样式嵌套或者漏解析。稳妥的做法是手动调用前先移除已有代码块里的prettyprint加工痕迹或者干脆重新渲染原始代码内容。如果页面里有多个代码块其中一个没有高亮另一个正常那多半是语言识别失败。Prettify 对语言标签的写法有要求一般写成lang-js、lang-css这类不要用language-javascript这种容易被它忽略的变体。另外如果代码块里没有明确的语言标签它会尝试自动识别但识别准确率不如新库必要时建议手动加上语言类。3.3 VSCode 和 Cursor 里高亮正常为什么网页端还是老样子这其实是两个完全不同的系统。VSCode 和 Cursor 编辑器里的高亮依赖的是语言服务比如 TextMate 语法、Vue 的 Volar 语言服务它们能做非常细的语法解析。而 prettify 本质上是一套基于正则和词法规则的简易高亮器精度自然没法比。你可能会在编辑器里看到一行漂亮的 Vue 代码高亮然后直接复制粘贴到网页里发现变成一片灰这是正常的。编辑器复制出来的文本并不包含高亮 token到网页之后需要重新走一遍高亮库的解析。如果你想在博客里展示.vue文件代码我的建议是不要试图让 prettify 直接高亮整个 SFC而是把template、script、style三块拆开分别用lang-html、lang-js、lang-css高亮效果反而更稳定。如果你希望网页端也复制出带高亮的代码那需要的不是 prettify 这类静态高亮库而是一个能在复制时生成带样式 HTML 的剪贴板插件。这和本文主题有点偏离但有助于理解编辑器里的高亮和博客里的高亮从来不是一回事。4. 性能优化与进阶扩展4.1 只在文章页加载不要全局引入如果整个站点每个页面都加载 prettify首页和分类页会白白浪费流量。我建议只在真正包含代码块的页面加载高亮资源。实现方式可以先用一个简单的判断比如页面主体存在.post-content时才动态插入链接和脚本。if (document.querySelector(.post-content)) { const link document.createElement(link); link.rel stylesheet; link.href /libs/prettify/prettify.css; document.head.appendChild(link); const script document.createElement(script); script.src /libs/prettify/run_prettify.min.js; script.defer true; document.body.appendChild(script); }这段代码的好处是低侵入不动原有的页面结构。如果站点是单页应用还可以放在路由回调里判断只有进入文章详情页时才加载。实测下来一个中等流量的静态博客按需加载能让首屏体积减少几十KB对移动端用户感知更明显。4.2 动态加载后手动调用 prettyPrint如果你的页面是做成了前后端分离的结构文章正文由 JavaScript 动态拉取就需要在插入 HTML 后主动触发高亮。假设已经引入了prettify.js那么动态加载文章后可以这样处理fetch(/api/article/1) .then(res res.text()) .then(html { content.innerHTML html; // 给所有代码块补上 prettify 类 content.querySelectorAll(pre).forEach(function(pre) { pre.classList.add(prettyprint); }); // 触发高亮 if (window.PR) { window.PR.prettyPrint(); } });这段示例的重点是window.PR.prettyPrint()。prettyPrint在全局上也可以直接调用但为了更规范我建议判断window.PR是否存在防止脚本没加载时直接报错。动态插入的代码块一定记得先加prettyprint类再调用高亮顺序反过来高亮逻辑会跳过它。4.3 配合 Markdown 渲染器自动添加类现在写博客大多先写 Markdown再用渲染器转成 HTML。如果你用的是 marked 或 markdown-it默认输出的代码块结构是precode classlang-js但 prettify 需要pre classprettyprint两者对不上。一个通用做法是在渲染完成之后做一次 DOM 补全。document.querySelectorAll(.post-content pre code).forEach(function(code) { const pre code.parentNode; pre.classList.add(prettyprint); const langClass code.className.match(/lang-(\w)/); if (langClass) { pre.classList.add(lang- langClass[1]); } }); if (window.PR) { window.PR.prettyPrint(); }这段代码建议放在 Markdown 渲染回调里而不是每次页面滚动都执行。要注意的是code上原本的lang-*类可以保留但不建议删除因为其他插件或样式可能还在用。对于 Vue 项目里常见的 Markdown 预览也可以在watch回调里调用同样的逻辑实现“输入 Markdown 实时预览高亮”的效果。最后再分享一个我这次的体会把旧博客从全局无差别高亮改成按需加载后首页体积少了差不多60KB首屏速度明显提升。Prettify 虽然老但它“文件少、流程直、可定制”的特点让它在不需要复杂构建的静态站点里依然有位置。而一旦你的内容开始出现 Vue 单文件组件这类带自定义块的文件我的建议是尽早切换到 Prism 或 highlight.js不要硬让 Prettify 干不擅长的事。工具选型这回事从来不是越新越好而是和你内容的形态匹配最重要。本文还有配套的精品资源点击获取