新闻详情

新闻详情

首页 / 资讯中心 / 详情

prettify三件套实现代码高亮:静态博客零依赖渲染方案详解

发布时间:2026/9/26 13:26:06来源:尧图网络
prettify三件套实现代码高亮:静态博客零依赖渲染方案详解
简介代码高亮是网页展示源代码时的常见需求Prettify作为轻量级JavaScript库能帮助开发者、博主和文档作者快速实现美观的代码着色。这份RAR压缩包共含3个文件包括2个JavaScript脚本和1个CSS样式表整体仅有14KB。其中prettify.css负责定义关键字、字符串、注释等语法元素的配色与字体样式prettify.js内置多语言识别逻辑可自动格式化并高亮常见编程语言run_prettify.min.js是压缩优化版本在保留完整功能的同时减小文件体积有利于页面加载。这套资源已有841人学习/下载适合需要在个人网站、技术博客或项目文档中嵌入代码块的场景。集成方式简单通过CSS与JS的配合并对代码块添加标记即可自动完成多语言代码着色省去手工配色与逐段处理显著提升代码可读性和页面整体专业度。1. 代码高亮这件事为什么我最终选了 prettify 三件套代码高亮看起来只是给代码块换个底色真正上手做才知道它有多磨人。我第一次给静态博客做代码展示时手动把每段代码拆成 span 再挨个上色换一次主题要改几十处后来换成 prettify 这套三件套——prettify.css、prettify.js、run_prettify.min.js——才把代码渲染从手工作坊变成配置项。prettify 是零依赖的高亮方案核心思路很简单一个 JS 扫描页面上带 prettyprint 类的代码块用正则切出 token再套上 CSS 皮肤。它适合文档站、自建博客、手册这类没有复杂构建链的纯静态页面不适合需要精确到语义着色的重型编辑器场景。这篇笔记把三个文件的职责、部署方式、参数调法和踩过的坑写透照着做基本能一次跑通。2. 三个文件各管一段prettify 为什么拆成加载器、引擎和皮肤很多刚接触 prettify 的人第一反应是「怎么要引三个文件不能合成一个吗」。我一开始也有这个疑问直到动手扒了 run_prettify.min.js 的逻辑才明白这三个文件的分工非常清楚拆开反而是好事——皮肤、引擎、调度各自独立出问题时不至于一换全换。2.1 prettify.css皮肤层决定代码块的底色和 token 颜色prettify.css 是纯样式文件里面定义了两类规则。第一类管代码块容器比如给 .prettyprint 设置背景色、内边距、字体、边框保证代码块在页面上是独立的一块第二类管 token 着色比如 .str 对应字符串、.kwd 对应关键字、.com 对应注释、.lit 对应数字字面量、.pun 对应标点、.pln 对应普通文本。我在实际主题定制时一般不去改这个 css 本身而是写一份覆盖样式放在它后面。原因很简单prettify.css 里的配色是通用的直接改它会让以后升级皮肤时没法回退。覆盖的方式是加一层自己的选择器优先级写到和它同级或更高比如pre.prettyprint { background: #1e1e1e; border: 1px solid #333; padding: 12px 16px; border-radius: 6px; font-size: 14px; }这段样式放在 prettify.css 之后引入就能覆盖默认的白底黑字。注意这里用的是pre.prettyprint而不是.prettyprint选择器更具体不容易被全局样式误伤。prettify.css 本身没有暴露 CSS 变量所以换主题本质是覆盖这些类名对应的属性。2.2 prettify.js引擎层正则切 token 与语言子集的注册方式prettify.js 是真正的核心它做两件事切 token 和按语言子集识别。它的词法分析不是 AST 级别的而是用正则按语言的关键特征去匹配——比如遇到//或/*就当作注释开始遇到引号就当作字符串。这种做法的代价是精度有限但换来的是体积小、加载快、不依赖任何框架。语言子集的注册方式是 prettify 设计里最值得了解的部分。prettify.js 内部维护了一个语言处理器集合默认注册了一组常见语言JavaScript、CSS、HTML/XML、Java、Python、C/C、Ruby、Shell 等。识别方式不是声明的而是根据代码内容推断——它会看第一个有意义的字符、关键字密度、注释风格去猜。这也导致它遇到冷门语言时会误判后面第 4 章会专门讲怎么手动指定。在浏览器里验证引擎有没有工作不是看页面颜色而是打开控制台查看代码块内部的 DOM 结构。高亮成功后代码会被拆成大量带语义类名的 spanpre classprettyprintcodespan classkwddef/span span classplnfoo/spanspan classpun(/spanspan classplnx/spanspan classpun):/span ... /code/pre我在排查问题时第一步永远是检查这个 DOM。如果代码块里干干净净没有 span说明引擎没跑起来跟 CSS 一点关系都没有。这也是 prettify 这类方案的设计特点样式只负责画颜色语义类名是引擎输出的结果两者通过类名解耦。2.3 run_prettify.min.js调度层按需加载与自动执行的机制run_prettify.min.js 是这套方案里最容易被当成黑匣子的文件。它本身几乎不包含高亮逻辑作用是一个自动加载器页面加载完成后它动态创建script标签去加载 prettify.js创建link标签去加载 prettify.css然后调用引擎扫描整个文档。这就是为什么很多接入教程只让你引一个 run_prettify.min.js它会把另外两个文件自动拉进来。它内部大致会做这样一个序列function loadScript(url) { var s document.createElement(script); s.src url; document.body.appendChild(s); } function loadStyle(url) { var l document.createElement(link); l.rel stylesheet; l.href url; document.head.appendChild(l); } loadScript(prettify.js); loadStyle(prettify.css); // 等脚本加载完后调用 window.prettyPrint()这是一个简化的示意真实文件里还会有加载状态判断和错误兜底。理解这层机制对排错很重要如果你把 run_prettify.min.js 放在页面 head 里它不会阻塞渲染而是异步去拉取另外两个文件所以代码块在瞬间可能没有样式这是正常现象不是 bug。三个文件的分工可以概括成一句话css 管皮肤js 管引擎run_prettify 管调度。文件职责部署特点prettify.css容器样式 token 主题可被覆盖独立替换prettify.js正则词法分析 语言子集核心引擎体积最小run_prettify.min.js按需加载 自动执行只需要在页面引这一个对照 highlight.js 或 Prism 这种单文件方案prettify 的优势是接入成本低只要引一个入口文件语言子集全内置劣势是精度上限低遇到复杂 DSL 识别不准。选型时我心里有一条线页面上只有常见语言的代码图省事就用 prettify需要 Tree-sitter 级别的语义分析趁早换重型方案。3. 本地服务器最小部署三件套的目录组织与 HTML 引用顺序这一章直接给可抄作业的步骤。我假设你的环境是任意一台装了 Python 的电脑不依赖 Node 或任何构建工具。这套部署方式同样适用于直接把文件扔到 Nginx 或对象存储里的场景。3.1 建目录、放文件三件套的推荐组织方式先把文件在磁盘上的位置定好后面所有部署都基于这个结构。我习惯把静态资源放到单独的目录里避免页面根目录被各种 JS 和 CSS 堆满。mkdir -p /var/www/demo/src cd /var/www/demo/src # 假设三个文件都在手边复制进来 cp /path/to/prettify.css . cp /path/to/prettify.js . cp /path/to/run_prettify.min.js . ls -la这里把三个文件放在同一个目录下是为了保证 run_prettify.min.js 在动态创建 link 和 script 时能用相对路径找到另外两个文件。如果你把三个文件拆到不同目录必须改 run_prettify.min.js 内部构造的路径否则样式和引擎都会加载失败。实际部署时也可以把它们合并压缩减小请求数但开发阶段不建议分开更容易定位问题。3.2 HTML 页面引用 run_prettify.min.js 的标准写法页面里真正写进 HTML 的只有 run_prettify.min.js 这一个文件。prettify.css 和 prettify.js 不需要手动引用run_prettify 会代劳。问题在于它用什么路径去找这两个文件取决于 run_prettify.min.js 里写死的基准路径所以放在同一目录是最稳的做法。!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleprettify 最小部署示例/title /head body h1代码高亮示例/h1 pre classprettyprint lang-pythoncode def greet(name): # 一段简单的示例代码 print(hello, name) greet(prettify) /code/pre script srcsrc/run_prettify.min.js defer/script /body /html这段 HTML 有三个关键点。第一defer属性让脚本在文档解析完成后执行run_prettify 内部等待 DOM 就绪的逻辑会更稳第二代码块外层用pre内层包codeprettify 对这两种标签都支持但code在内能避免 HTML 渲染把代码里的尖括号吃掉第三lang-python是语言标注类名后面第 4 章详细说。写完这个文件后用浏览器打开页面加载完代码块应该已经有颜色了。3.3 验证用本地 HTTP 服务检查是否真的高亮很多人写完 HTML 直接双击用file://打开结果代码块全是黑的。这不是 prettify 坏了是浏览器安全策略限制本地文件加载子资源。解决方式很简单起一个本地 HTTP 服务。cd /var/www/demo python3 -m http.server 8000然后访问http://localhost:8000/打开页面试试。起服务这一步是最容易被人忽略的我见过不少人卡在 file:// 协议下排查半天最后换成本地服务立刻正常。验证成功后可以看一眼控制台没有报错、DOM 里出现了带 token 类名的 span基本就是部署成功了。4. 控制高亮范围语言标注、行号、以及动态渲染的边界跑通最小部署只是第一步实际页面里代码语言五花八门必须搞清楚 prettify 是怎么决定「用什么语言去解释这段代码」以及怎么把行号、指定语言这类操作做得干净。4.1 lang-* 的自动识别与手动覆盖prettify 默认是自动检测语言靠的是引擎内部的正则特征。很多时候它判断得挺准但遇到极短代码段或者冷门语法就会翻车。比如下面这段代码只有两行自动识别经常把它当纯文本pre classprettyprintcode const ret await client.query(sql); console.log(ret.rows.length); /code/pre解决方式是在类名里显式声明语言prettyprint lang-js。这样引擎直接跳到对应的语言子集不经过猜测步骤。常见语言标注类名对照如下语言类名JavaScriptlang-jsPythonlang-pythonJavalang-javaC/Clang-c / lang-cppSQLlang-sqlHTML/XMLlang-html / lang-xmlBash/Shelllang-bsh / lang-sh手动标注是一个好习惯即使引擎没猜错标注也能让其他接手代码的人直观知道这段代码的语言。注意类名写法是lang-xxx跟在prettyprint后面用空格分隔不是classprettyprint_lang-js这种下划线形式。4.2 linenums 行号与结构类 nocode 的取舍prettify 支持行号只要在 pre 上加一个 linenums 类。行号的实现方式不是真的在代码里填数字而是给代码块生成一个隐藏的有序列表通过 CSS 的list-style显示数字。这是它和很多复制代码插件冲突的根源——人家复制的时候可能把行号也带走了。pre classprettyprint linenumscode def foo(): return 1 def bar(): return 2 /code/pre加了 linenums 后列出的行号默认从 1 开始也可以指定起始行号比如linenums:20适合展示代码片段时标明它在原文件里的位置。但我会提醒你行号和代码高亮的组合会带来额外样式问题第 5 章里有个专门踩坑条目。另外如果某些代码片段不想要任何语义着色可以用nocode类引擎会跳过它保持纯文本适合放命令行输出。4.3 从 IDE 复制到网页为什么不能直接把 pycharm 里的高亮照搬这里要顺带提一个和编辑器相关的对照很多人会问「IDE 里不是有现成的代码高亮插件吗能不能直接把结果导出」。像 pycharm 这类 IDE 的代码高亮是基于完整语法树的编辑器组件内部拿到的是解析后的 AST颜色是渲染引擎按 token 类型映射出来的而 prettify 拿到的是纯文本靠正则去猜结构。所以从 pycharm 复制代码到网页编辑器里看到的颜色不会跟着过来你只能把文本粘进来让 prettify 重新识别。还有一层容易忽略的坑从 IDE 复制的代码里常有缩进和特殊字符粘贴到 HTML 时、、会直接和 HTML 标签冲突。比如复制一段泛型代码ListString粘贴进pre后浏览器会把String当成一个未知标签吃掉。解决办法是手动转义或用模板工具把、、转成 HTML 实体。我一般用 Python 写一个转义脚本处理整篇 Markdown 里的代码块避免手工遗漏。import html src ListMapString, Integer result new ArrayList(); escaped html.escape(src) print(escaped) # Listlt;Maplt;String, Integergt;gt; result new ArrayListlt;gt;();这段代码的html.escape会把转成lt;把转成gt;浏览器渲染时再显示成原来的字符。用它批量处理从 IDE 复制来的代码比人眼逐个找尖括号快得多。注意转义只针对、、不要转义引号否则代码里大量字符串会被改得很难读。5. prettify 避坑笔记五个能让你翻车的真实场景把 prettify 用在正式项目里后我陆续遇到过几个比较典型的问题。它们都不是引擎坏了而是对 prettify 工作方式理解不到位。每条按「现象 → 原因 → 解决」写清楚希望你能绕开我走过的弯路。5.1 代码块整段是黑字忘了 prettyprint 类或 HTML 实体没转义现象页面加载完代码块确实在但一个字都不带颜色。原因最常见的是给 pre 或 code 忘记加prettyprint类引擎扫描时根本不认为它是需要处理的代码块。另一种情况是代码里的被浏览器解析成标签导致 DOM 结构错乱prettify 拿到的内容已经残缺了。解决检查 HTML 里代码块是否有classprettyprint如果有再看源码里是不是直接把写进了代码区尖括号应当转义。加类名和转义是两个独立的问题排错时分开查。5.2 行号偏移或底色丢失CSS 覆盖顺序没有保证现象加了 linenums 后行号歪了或者代码块背景色和页面背景混到一起。原因prettify.css 里行号列表的样式依赖list-style: decimal但很多前端框架会把ul/ol的默认样式重置掉行号数字就没了或错位。底色丢失则是因为全局样式中pre的背景优先级高于 prettify.css。解决自己写一份覆盖样式引入到 prettify.css 之后显式恢复行号样式例如设置li.L0, li.L1的list-style-type: decimal和合理缩进。如果还不行把 prettify.css 的引入顺序挪到全局样式后面保证后者不覆盖它。5.3 动态插入的内容没高亮run_prettify 只在页面加载时执行一次现象AJAX 加载出来的代码块还是黑字页面刷新后某些动态区域的代码始终不上色。原因run_prettify.min.js 的工作流程是「文档加载完 → 扫描一次 → 结束」。它用DOMContentLoaded或等价事件去做触发后续动态插入的节点不在初始扫描范围内所以不会被处理。解决动态代码插入完成后手动调用全局函数window.prettyPrint()再扫一遍。这个函数是幂等的已经处理过的节点会跳过所以重复调用不会把已有高亮搞坏。调用时机要在 DOM 插入之后、渲染到屏幕之前或之后都可以实际区别不大。5.4 引用了 run_prettify 但样式没跟上资源相对路径的坑现象代码被切成了 spanDOM 正确但颜色没有变化控制台提示 prettify.css 加载失败。原因run_prettify.min.js 内部在构造 css 和 js 的资源地址时用的是相对路径拼接。如果页面放在二级目录而 run_prettify.min.js 在三级目录拼出来的路径就指向了不存在的位置样式文件 404。解决把三个文件放在同一个目录下且页面用相对路径引用时保证层次正确例如页面在根目录、资源在src/下引用写script srcsrc/run_prettify.min.jscilinder 文件也在src/下。或者干脆把三个文件用构建工具合并成内联资源彻底绕开路径问题。5.5 大量中文注释把语言识别带偏手动指定 lang 的时机现象一段 Python 代码里注释全是中文prettify 把它识别成无语言纯文本关键字不上色。原因自动识别依靠关键字和注释特征中文字符占得多的时候引擎的语言判断会被干扰尤其短代码段更敏感。这不是 bug是正则识别方案的天然短板。解决给代码块显式加lang-python等类名强制指定语言。写页面时可以在模板上做约定凡是代码片段必须带 lang 类不带的一律走自动识别但没有测试过的语言宁可手动确定。6. 从自动到可控用 prettyPrint / prettyPrintOne 接管高亮时机run_prettify 帮我们做了自动化但项目一复杂自动反而碍事。我最终习惯自己接管调用时机主用两个全局 APIprettyPrint()和prettyPrintOne()。前者扫码整个文档后者只处理传入的字符串并返回高亮后的 HTML。动态页面最稳的做法是每次插入新代码块后手动调一次 prettyPrint而不是依赖初始扫描。// 插入动态内容后手动触发高亮 fetch(/api/snippets/code.js) .then(res res.text()) .then(code { const container document.getElementById(snippet-area); container.innerHTML precode classprettyprint lang-js/code/pre; const target container.querySelector(code); target.textContent code; // 手动触发扫描只处理未高亮节点 window.prettyPrint(); });这段代码里的关键是target.textContent code而不是innerHTML直接赋值 HTML 会把尖括号当成标签导致解析错乱往textContent里塞文本是最安全的方式。最后调用的prettyPrint()会遍历 DOCUMENT 里所有未处理的prettyprint节点把它渲染成带语义类名的 span。如果只需要处理某个片段而不是全页扫描可以用prettyPrintOne(codeHtml, js, false)返回高亮后的 HTML 字符串手动拼进容器。验证高亮有没有成功不需要肉眼看颜色直接在控制台执行一条命令就行document.querySelectorAll(pre.prettyprint span.str, pre.prettyprint span.kwd).length返回大于 0 说明 token 已经切出来了。我做静态站时习惯把 prettify 接进一个简单的 Markdown 渲染流程Markdown 转 HTML 后找到所有pre code节点给它们补上 prettyprint 类再统一调一次 prettyPrint这样博客正文里不用手动写类名。有一点要说明prettyPrint 在处理非常大批量的代码块时会有轻微卡顿几十个代码块没问题上千个就考虑只增量渲染用 prettyPrintOne 处理新节点。调试 prettify 这几年我最深的体会是这类工具的问题大多不是代码错误而是调用时机和路径约定没对齐。看到代码块没高亮先确认 DOM 里有没有 span再确认 css 有没有加载这两条路能排除七成问题。希望这份踩坑记录帮你在代码高亮这件事上少走弯路。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Vibe Coding零基础保姆级教程:用TaoToken统一Key从0到1搭建个人主页与数字分身(第一课) 2026/9/26 15:03:09

Vibe Coding零基础保姆级教程:用TaoToken统一Key从0到1搭建个人主页与数字分身(第一课)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
32位Windows连Oracle:精简客户端部署与避坑指南 2026/9/26 15:03:03

32位Windows连Oracle:精简客户端部署与避坑指南

简介:面向32位Windows平台的Oracle客户端安装包,专供数据库管理员、运维人员与开发者在本地连接Oracle数据库服务器,执行SQL查询、数据导入导出及日常管理任务。包内集成了Oracle Net Services、SQL*Plus、OCI编程接口、JDBC/ODBC驱动以及.NE…

阅读更多 →
JSP+SQLServer网上花店系统毕设指南:库表设计、部署与避坑 2026/9/26 15:03:03

JSP+SQLServer网上花店系统毕设指南:库表设计、部署与避坑

简介:一份以JSP和SQLServer为核心、完整覆盖网上花店系统从需求分析到实现部署的毕业设计资料包,适合正在做电商类Web项目的学生或需要参考JSPServletJDBC开发流程的入门开发者。包体共1140个文件,约8.67MB,其中79个jsp页面与22个…

阅读更多 →
AI提示词工程实战:用执行助理角色30秒生成可执行每日行动计划 2026/9/26 15:02:57

AI提示词工程实战:用执行助理角色30秒生成可执行每日行动计划

1. 为什么“事情太多先做什么”是个真问题你有没有过这种早晨:闹钟响了第三遍才爬起来,手机一解锁,微信未读99,邮件里躺着三封标红的“紧急”,待办清单长得像超市小票,脑子里同时转着“今天要交周报”“下午…

阅读更多 →
Atlas 300V实战:部署YOLO推理模型的关键步骤与避坑指南 2026/9/26 15:02:57

Atlas 300V实战:部署YOLO推理模型的关键步骤与避坑指南

Atlas 300V这块卡,我最早是在一个做边缘视频分析的客户机房里见到的。当时那边工程师一脸无奈地跟我说,显卡跑YOLO太费电,机箱里塞了四块卡,电源和散热都顶不住,才换了Atlas来做推理。结果卡到了之后,他们第…

阅读更多 →
VS Code Python解释器配置本质:路径选择而非自动发现 2026/9/26 15:02:57

VS Code Python解释器配置本质:路径选择而非自动发现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉