Unity WebGL游戏资源逆向提取:从浏览器缓存到AssetStudio实战指南
1. 项目概述从WebGL游戏到本地资源库如果你玩过一些基于Unity引擎开发的网页游戏可能会好奇那些精美的模型、有趣的音效和复杂的UI界面是如何被打包并运行在浏览器里的。更进一步的作为一名开发者、爱好者或者安全研究人员你可能想把这些资源“拆”出来看看用于学习、二次创作或者分析。这正是我们今天要聊的核心如何从Unity WebGL构建的游戏里逆向提取出原始的资产文件。这个过程的核心工具是AssetStudio一个开源且功能强大的Unity资源提取和查看工具。但问题来了WebGL游戏运行在浏览器沙盒中其资源文件如.data、.bundle并不像PC端游戏那样直接躺在你的硬盘文件夹里。它们被浏览器下载并管理在缓存中。因此整个流程就分成了清晰的两步首先从浏览器这里以Chrome为例的缓存中定位并提取出Unity WebGL的游戏资源文件其次使用AssetStudio加载这些文件并导出我们需要的模型、纹理、音频等资源。这不仅仅是简单的“点几下按钮”其中涉及到对浏览器缓存机制的理解、对Unity WebGL构建格式的识别以及在提取过程中可能遇到的各种坑。接下来我会结合我多次实操的经验带你走通这条从网络到本地的资源获取之路。2. 核心思路与工具选型解析2.1 为什么是AssetStudio在Unity资源逆向领域有几个常见的工具如UABE (Unity Assets Bundle Extractor)、DevX Unity Unpacker等。我最终选择并推荐AssetStudio主要基于以下几点考量持续维护与兼容性AssetStudio在GitHub上由Perfare等人积极维护对新版本Unity的适配速度相对较快。Unity的资产包格式如AssetBundle的序列化格式、压缩方式和资源格式如Shader、TextMeshPro字体经常随版本更新而变化一个持续更新的工具至关重要。对WebGL构建的良好支持Unity WebGL的构建输出有其特殊性它会将资源打包成.data、.framework.js、.loader.js等文件。AssetStudio能够直接识别并加载这些.data文件本质上是经过处理的AssetBundle这是完成我们目标的基础。图形化界面与批量操作AssetStudio提供了直观的GUI可以浏览资源树、预览模型纹理、直接导出多种格式如FBX、PNG、WAV等。同时它也支持命令行便于自动化批量处理灵活性很高。资源关系解析它不仅能导出单个资源还能在一定程度上解析资源之间的引用关系这对于希望完整导出某个场景或预制体Prefab及其所有依赖资源非常有帮助。注意AssetStudio并非万能。对于使用了高度定制化加密或混淆的商业游戏它可能无法直接读取。我们的讨论基于未加密或使用通用加密方式的WebGL构建。2.2 Chrome缓存资源的临时仓库浏览器为了提高加载速度和减少网络请求会将访问过的资源图片、脚本、二进制文件等存储在本地磁盘的缓存区域。Unity WebGL游戏在加载时其.data、.bundle等资源文件同样会被下载到缓存中。我们的任务就是找到它们。Chrome的缓存机制有几个特点位置固定但隐蔽缓存目录有默认位置如Windows在%LocalAppData%\Google\Chrome\User Data\Default\Cache但里面的文件没有扩展名且文件名被哈希处理过无法直接辨认。索引管理Chrome通过一个名为index的数据库文件来记录缓存URL、文件位置、元数据等信息。自动清理缓存空间有限旧文件可能被自动清除。因此直接从缓存文件夹复制文件是行不通的。我们需要借助一些方法或工具来“翻译”这个缓存系统按资源原始的URL或内容特征把我们要的文件找出来。2.3 整体流程蓝图整个操作的流程图可以概括如下准备阶段确保目标Unity WebGL游戏在Chrome中完全加载完毕。缓存提取阶段使用特定方法下文详述从Chrome缓存中筛选并导出Unity资源文件主要是.data和.bundle文件。资源解析阶段使用AssetStudio打开导出的资源文件。资源导出阶段在AssetStudio中筛选、预览并导出所需资源模型、纹理、音频、文本等。3. Chrome缓存提取实战技巧这是整个过程中技术含量较高的一步。我将分享三种经过验证的方法从易到难你可以根据实际情况选择。3.1 方法一使用“缓存查看器”类扩展程序最便捷对于大多数用户这是最推荐的方法。原理是使用能够读取Chrome缓存数据库的扩展程序直接按URL或文件类型筛选并保存。操作步骤在Chrome网上应用店搜索并安装如“Cache Viewer”、“ChromeCacheView”或类似功能的扩展。安装后它通常会在开发者工具DevTools中新增一个面板。完全打开并运行目标Unity WebGL游戏确保所有资源加载完成。打开Chrome开发者工具F12找到新增的缓存查看器面板。在面板中你会看到一个列表包含了当前浏览器缓存的所有项目通常有URL、文件类型、大小、最后访问时间等信息。利用筛选功能寻找包含unityweb、.data、.bundle等关键词的URL。Unity WebGL资源通常来自类似xxx/WebGL.data或xxx/assetbundle.bundle的路径。在列表中找到目标文件后扩展通常会提供“Save As”或“导出”按钮将其直接保存到本地硬盘。实操心得关键词筛选是关键除了.data也可以尝试筛选application/octet-stream或application/x-unity等MIME类型因为Unity的二进制资源文件常以此类型传输。注意文件大小Unity的资源.data文件通常体积较大几MB到几百MB可以通过排序快速定位。扩展的局限性某些扩展可能无法处理非常大的缓存文件或在Chrome版本更新后失效。如果此方法无效请尝试下面的方法。3.2 方法二基于Chrome DevTools的Network面板手动保存无需扩展如果你不想安装扩展或者扩展失效了可以利用Chrome自带的开发者工具。操作步骤打开目标游戏页面先打开开发者工具F12切换到Network网络面板然后刷新页面。这能确保记录到所有资源请求。在Network面板中等待所有资源加载完成进度条走满请求列表静止。在筛选框Filter中输入.data或.bundle快速过滤出Unity资源请求。在找到的.data或.bundle文件请求上右键点击选择“Save as…”在新版Chrome中可能是“Copy - Copy as cURL”然后借助其他工具下载但更直接的方法是使用“Save as”。但是这里有一个大坑有时右键菜单里没有“Save as”选项或者点击后保存的是无用的文件。这是因为浏览器可能已经将资源解码或处理过了。解决方案与高级技巧如果直接“Save as”不行可以尝试以下步骤点击那个资源请求在右侧的“Headers标头”选项卡中找到“Response Headers响应标头”里的content-type。确认它是application/octet-stream或application/x-unity等二进制类型。切换到“Preview预览”或“Response响应”选项卡。对于二进制文件这里通常会显示“Binary data二进制数据”。此时在“Response响应”选项卡的空白处右键选择“Save as…”。这样保存下来的才是原始的二进制数据。务必从响应体查看器里保存而不是从请求列表里。3.3 方法三直接挖掘磁盘缓存文件硬核方法当上述方法都失效时例如游戏使用了Service Worker或特殊的缓存策略我们可以直接去磁盘缓存目录里“淘金”。这种方法更底层但成功率也高。操作步骤定位缓存目录Windows:C:\Users\[你的用户名]\AppData\Local\Google\Chrome\User Data\Default\CachemacOS:~/Library/Caches/Google/Chrome/Default/Cache/Linux:~/.cache/google-chrome/Default/Cache/注意Default是默认配置文件目录如果你使用了多用户配置可能是Profile 1,Profile 2等。使用缓存解析工具缓存目录里的文件是乱码名的。我们需要工具来解析。推荐使用开源命令行工具chrome-cache-view或者图形化工具ChromeCacheView独立软件非扩展。以chrome-cache-view为例在命令行中导航到缓存目录运行工具。它会读取index文件并输出一个包含原始URL和对应缓存文件名的列表。在这个输出列表中用grepLinux/macOS或findstrWindows命令搜索.data或unityweb等关键词找到目标条目。记下对应的缓存文件名如f_000abc。提取文件在缓存目录中找到对应的f_000abc文件没有扩展名将其复制出来然后手动为其加上正确的扩展名如.data或.bundle。验证文件尝试用AssetStudio打开这个重命名后的文件。如果文件有效AssetStudio就能识别。注意事项关闭Chrome在进行此操作前务必完全退出Chrome浏览器否则缓存文件可能被锁定无法复制。文件有效性不是所有缓存文件都是完整的资源有些可能是分片或无效数据。需要AssetStudio来最终验证。隐私与法律缓存目录可能包含你的浏览历史等敏感信息操作时请注意隐私。同时提取资源仅用于合法学习与研究请尊重版权。4. 使用AssetStudio解析与导出资源成功获取到.data或.bundle文件后就轮到AssetStudio大显身手了。4.1 AssetStudio的基本使用流程加载文件打开AssetStudio点击“File - Load file”加载单个文件或“Load folder”加载包含多个资源文件的文件夹。对于WebGL的.data文件通常直接加载它即可。等待解析AssetStudio会开始解析文件结构。在底部状态栏可以看到进度。文件越大或越复杂解析时间越长。浏览资源解析完成后左侧是资源树状图可以按资产类型Texture2D, Sprite, AudioClip, Mesh, GameObject等、容器或名称浏览。右侧是预览窗口可以预览图片、播放音频、查看模型需要点击“Model”选项卡并选择Mesh资源。筛选与搜索利用上方的筛选栏可以快速过滤出特定类型的资源。例如输入“Mesh”查找所有模型输入“AudioClip”查找所有音频。导出资源导出单个在资源列表中选择一个或多个资源右键选择“Export selected assets”。导出全部在左侧资源类型列表的顶层如“Asset List”右键选择“Export all assets”。导出选项在导出前建议点击“AssetStudio - Options”设置导出参数。例如模型可以导出为FBX或OBJ格式纹理可以导出为PNG或TGA音频可以导出为WAV。4.2 针对WebGL资源的特殊处理与技巧处理多个.data文件一个复杂的WebGL游戏可能被分割成多个.data文件如WebGL.data,WebGL_1.data。你需要将所有相关的.data文件放在同一个文件夹然后让AssetStudio加载整个文件夹这样它才能正确解析资源之间的引用关系。提取完整场景或预制体如果你想导出某个完整的场景或角色Prefab仅仅导出Mesh和Texture是不够的。你需要找到对应的GameObject或Prefab资源。导出时AssetStudio会尝试将其依赖的资源如Mesh、Material、Texture一起导出但对于复杂的父子结构和脚本引用可能无法完美还原到引擎中通常以FBX文件导出模型结构是可行的。Shader和Material的局限Unity的Shader是高度平台相关的代码从AssetBundle中提取的Shader资源通常无法直接在其他Unity项目中使用。导出的Material可能会丢失Shader信息或呈现为粉色默认错误状态。纹理Texture2D的提取则非常可靠。文本资产的提取游戏内的文本如本地化文件、配置表可能以TextAsset、MonoBehaviour或序列化文件形式存在。在AssetStudio中它们可能显示为十六进制或序列化数据。对于TextAsset可以直接导出为.txt或.bytes文件。对于更复杂的可能需要进一步的逆向分析工具。4.3 一个典型的导出案例提取3D模型及其贴图假设我们想提取一个角色模型。在AssetStudio的资源列表中筛选类型为“Mesh”。你会看到一堆网格资源名称可能是乱码或哈希值。逐个选中Mesh在右侧“Model”预览窗口中查看找到目标角色模型。记下这个Mesh资源的名称或直接选中它。在资源列表中筛选类型为“Texture2D”。你需要找到属于这个角色的贴图。这通常没有直接引用关系需要通过经验判断贴图名称可能包含角色名或部件名如hero_body_diffuse或者贴图的尺寸和内容与模型预览匹配。选中目标Mesh和所有你认为相关的Texture2D。右键导出。在导出设置中为Mesh选择FBX格式为Texture2D选择PNG格式。导出的FBX文件可以在Blender、Maya或Unity中再次导入。贴图文件需要手动在3D软件中重新赋予材质球。5. 常见问题、排查技巧与进阶思路即使按照步骤操作你也可能会遇到各种问题。这里记录了一些常见坑点和解决思路。5.1 缓存提取阶段问题问题1Network面板里找不到.data文件请求。可能原因1游戏资源使用了不同的扩展名或命名方式。尝试筛选unityweb、bundle或bin。或者清除筛选器按大小排序寻找体积异常大的二进制文件请求。可能原因2资源通过WebSocket或fetchAPI动态加载。这种情况下Network面板的“XHR”或“Fetch”标签页下可能也看不到因为它们可能被编码在数据流中。此时方法三磁盘缓存挖掘可能更有效。可能原因3游戏已完全缓存资源来自磁盘缓存未发起网络请求。尝试强制刷新CtrlF5或在开发者工具设置中勾选“Disable cache禁用缓存”然后重新加载页面。问题2从缓存中提取的文件AssetStudio无法识别或报错。可能原因1文件不完整或已损坏。浏览器缓存可能未完全下载或已部分清理。尝试重新运行游戏确保完全加载后立即提取。可能原因2文件是经过压缩或加密的。一些游戏会对AssetBundle进行自定义压缩非Unity标准LZ4/LZMA或简单加密。AssetStudio支持标准压缩。如果是简单XOR加密可以尝试寻找已知的XOR密钥这需要更深入的逆向分析。复杂的加密则基本无解。可能原因3文件头信息丢失。尝试使用方法二从Network面板的Response体直接保存确保获取的是原始数据流。5.2 AssetStudio解析与导出阶段问题问题1AssetStudio打开文件后资源列表是空的或只有少数几个。可能原因1Unity版本过高或不兼容。AssetStudio可能尚未支持该游戏使用的Unity版本。检查游戏加载时JavaScript文件中的Unity版本号并尝试更新到最新版的AssetStudio。可能原因2文件类型不对。确认你加载的是Unity WebGL的.data文件或标准的.bundle文件而不是其他配置文件或脚本。可能原因3资源类型未被识别。尝试在AssetStudio的“Options”中勾选上“Show All Assets”选项有时资源会被归类到不常见的类型下。问题2导出的模型FBX/OBJ在3D软件中打开是破碎的、变形的或没有贴图。模型破碎/变形这可能是由于模型包含非常规的网格数据或AssetStudio导出插件的问题。尝试导出为OBJ格式兼容性更好但信息较少或者尝试使用其他导出选项如不同的FBX版本。没有贴图AssetStudio导出FBX时贴图信息有时不会自动嵌入或链接。你需要手动将导出的PNG等贴图文件在3D软件中重新赋予给材质。确保导出的贴图文件命名清晰便于匹配。问题3如何提取游戏内的字体、UI界面或动画字体查找类型为“Font”或“TMP_FontAsset”的资源。对于TextMeshPro字体导出后通常是一个资产包需要在Unity环境中才能较好还原。UI界面UI元素通常是Sprite图片和GameObject结构的组合。你可以导出所有Sprite即UI图集切片然后根据GameObject的层级信息在图像编辑软件或游戏引擎中手动拼装。更复杂的UI逻辑如按钮状态则无法直接提取。动画动画数据通常存储在AnimationClip资源中。你可以导出这些.anim文件。但要播放它们你需要将其导入到一个拥有对应骨骼和模型的Unity项目或支持Unity动画格式的第三方工具中这是一个复杂的过程。5.3 进阶思路自动化与批量处理如果你需要频繁提取或处理大量游戏资源手动操作效率太低。可以考虑以下方向命令行调用AssetStudioAssetStudio提供了命令行版本AssetStudioCLI。你可以编写脚本自动将缓存目录中提取出的.data文件传递给CLI工具进行解析和导出。整合缓存提取与解析用Python或Node.js脚本结合chrome-cache-view这样的库来读取缓存索引自动筛选出Unity资源文件然后调用AssetStudioCLI进行处理实现一条龙自动化。资源分析与监控使用浏览器自动化工具如Puppeteer控制Chrome加载游戏并监听Network请求自动捕获和下载所有.data文件资源。最后我必须强调所有这些技术都应应用于合法合规的场景例如学习游戏美术风格、研究引擎技术、进行安全评估在授权范围内或提取自己拥有版权的项目资源。尊重开发者的劳动成果和知识产权是每一位技术爱好者的基本准则。

相关新闻

CleanMyMac X与macOS Mojave兼容性及安全风险解析

CleanMyMac X与macOS Mojave兼容性及安全风险解析

1. CleanMyMac X与macOS Mojave的兼容性解析 作为一款广受Mac用户欢迎的系统清理工具,CleanMyMac X在不同版本的macOS上表现差异显著。根据官方文档显示,Mojave 10.14属于完全支持版本,这意味着用户可以正常使用所有功能模块而不会遇到兼容性…

2026/10/13 3:22:05 阅读更多 →
Starling框架:让经典Flash游戏重获新生的GPU加速方案

Starling框架:让经典Flash游戏重获新生的GPU加速方案

1. 项目概述:Flash 2D游戏的技术复兴十年前用AS3开发的Flash游戏现在还能跑吗?答案是肯定的,但需要一些"技术魔法"。Starling框架正是让老Flash游戏重获新生的关键工具——它通过GPU加速渲染,让传统AS3代码在现代设备上…

2026/10/12 21:50:05 阅读更多 →
WebAssembly实战指南:前端高性能计算与跨平台开发

WebAssembly实战指南:前端高性能计算与跨平台开发

1. 项目概述:为什么前端开发者现在必须关注WebAssembly?如果你是一名前端开发者,最近几年肯定没少听到WebAssembly(简称Wasm)这个词。它可能出现在某个技术大会的议题里,或者是你关注的某个开源项目的更新日…

2026/10/9 6:17:10 阅读更多 →

最新新闻

股债汇金四杀:买得分散,为什么还会一起亏?

股债汇金四杀:买得分散,为什么还会一起亏?

**分散买了股票、债券、美元和黄金,不等于分散了“急着用钱”的风险。**市场平静时,它们讲的是不同故事;资金紧张时,它们可能面对同一个问题:持有人必须把资产变成现金。 最近“股债汇金四杀”的说法很吓人。但对一个…

2026/10/13 3:21:48 阅读更多 →
就业指南|分析了近百份简历后,我决定写一篇就业指南

就业指南|分析了近百份简历后,我决定写一篇就业指南

本篇文章共 10000字,完全阅读全篇约10分钟 州弟学安全,只学有用的知识 前言 大家好,我是州弟。 大家还记得我上一篇文章吗?网安面试|记2026年8月国内某情报安全厂商面试的一次经历 ,当时分享了我主动投递并完整体验…

2026/10/13 3:21:48 阅读更多 →
[Java] 常用工具类

[Java] 常用工具类

日期相关类Date 类java.util.Date:Java 早期的日期时间类,精确到毫秒,用来表示一个特定的时刻常用成员方法可用方法:1)boolean after(Date when):判断当前日期是否在指定日期之后2)boolean befo…

2026/10/13 3:21:48 阅读更多 →
微信小程序打卡系统源码解析:前后端分离与MySQL表设计实战

微信小程序打卡系统源码解析:前后端分离与MySQL表设计实战

简介:这套基于小程序的互动打卡项目源代码,采用JavaSSM构建后端服务,前端基于uniapp/原生小程序开发,并配套MySQL 5.7数据库脚本,是一套完整可运行的前后端工程,适合Java学习者及毕业设计、课程设计参考。压…

2026/10/13 3:21:48 阅读更多 →
微信小程序互动打卡系统:MySQL表结构设计与前后端完整实现

微信小程序互动打卡系统:MySQL表结构设计与前后端完整实现

简介:这套基于小程序的互动打卡完整前后端源码,采用Java与SSM框架构建后端服务,搭配uniapp与原生小程序前端,适合毕业设计、课程设计或小程序开发学习者参考。资源共1248个文件,压缩包约8.77MB,核心包含Jav…

2026/10/13 3:21:48 阅读更多 →
CS231n KNN作业深度解析:从像素距离到视觉本质

CS231n KNN作业深度解析:从像素距离到视觉本质

1. 这不是“写个KNN”——而是用最朴素的代码照见计算机视觉的底层逻辑你点开CS231n作业1-Q1,看到“写一个K近邻分类器”,第一反应可能是:不就是算距离、排个序、投个票?抄几行numpy就完事了。我当年也是这么想的,直到…

2026/10/13 3:20:47 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/12 18:11:17 阅读更多 →