news 2026/9/29 6:35:22

Android Studio编译报错“No Module”全场景排查与修复指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android Studio编译报错“No Module”全场景排查与修复指南

遇到 “Android Studio 无法编译运行 No Module” 这类报错,我第一反应不是去百度复制报错原文,而是先把 AS 右下角的 Gradle 同步状态栏和 Event Log 打开看一眼。因为这个错误在 Android Studio 里实在太“万金油”了——工程列表里没有模块、Gradle 面板空白、Run 按钮变灰、甚至构建脚本里某个 Python 依赖找不到,都有可能在编译运行时弹出一句和 “No Module” 沾边的话。这篇文章我打算把所有我实际踩过的、以及帮别人排查过的 “No Module” 场景按源码级别拆开,不讲废话,只讲怎么定位、怎么修、怎么防。

1. “No Module”的真实面目:先分清你是哪一种报错

“No Module” 这个词本身不是 Android Studio 官方的异常类名,在不同界面、不同构建阶段出现时,它的真实含义几乎完全不一样。我见过不少新手上来就重装 AS,结果问题原封不动,就是因为没分清自己碰到的是哪一种。

1.1 症状一:Project 面板里 Module 列表直接消失

这种最直观:打开工程后,左侧 Project 视图里的app模块不见了,只剩一个孤零零的工程名,展开后里面没有src、没有build.gradle,甚至连.idea下的文件都看不到。此时你点 Run,AS 会提示 “No module”,或者说 “Nothing to run”。

这个现象的根因和 Gradle 没有直接关系,而是 IDE 层面的工程结构元数据坏了。Android Studio 判断一个模块是否存在的依据是.iml文件以及.idea/modules.xml里的注册记录。一旦这两样东西缺失或者内容对不上,AS 就“不认识”你的 app 模块了。

我之前处理过一个同事的工程,他在合并代码时手动删了.idea目录,然后 AS 重新打开工程,直接白屏加 “No Module”。当时我让他关闭 AS,删掉根目录下所有.iml文件和.idea整个目录,再重新用 Import Project 的方式导入,问题马上消失。这就是典型的 IDE 元数据损坏案例。

1.2 症状二:Gradle 同步时报 “No module named xxx”

这个在混编工程里极其常见。你打开项目,AS 自动触发 Gradle Sync,结果在 Build 窗口里刷出一串:

No module named 'pkg_resources' No module named 'yaml'

如果只看关键词 “No module”,很多人会一头雾水:我明明没写 Python 啊,为什么 Gradle 同步会报 Python 模块缺失?

答案是:你的构建脚本里大概率有一个task在配置阶段执行了 Python 脚本,或者某个 Gradle 插件(比如自动生成版本号、自动打包资源的插件)依赖了本机 Python 环境。Gradle 本身是 JVM 程序,它不会直接要求 Python,但一旦某个exec任务调用了python命令,而当前 Python 环境缺包,整个配置阶段就会失败。配置阶段失败意味着项目无法生成模块模型,AS 自然就显示 “No Module”。

1.3 症状三:构建报错 “failed to load module script”

这种常见于 Flutter 混合工程、H5 套壳工程或者 Debug 包里的 WebView 资源加载。报错信息长这样:

failed to load module script: expected a javascript-or-wasm module script but the server responded with a MIME type of "text/html"

严格来说这不是 Android Studio 编译问题,而是前端资源在本地服务器路径不对。但因为整个构建过程是在 AS 里触发的,很多人误以为是自己工程结构坏了。这个锅不该 Gradle 背,问题通常出在web目录下index.html引用的 JS 路径与本地静态服务器映射不一致,或是开发服务器端口被占用导致资源回退到了 404 页面。

1.4 四种症状的快速对照

报错表现实际根源排查方向
Project 列表无 Module,Run 变灰.iml/.idea元数据损坏删缓存重新导入
Sync 报 No module named xxxGradle 调用了本机 Python/Node 脚本检查 exec task 和脚本依赖
构建成功但运行加载失败Web 资源路径或本地服务器问题检查 index.html 与端口
编译时找不到本地依赖模块Gradle 缓存污染或依赖坐标错误清理缓存重建依赖

分清这四种,后面每一步才不会白做。

2. 根源深挖:Android Studio 为什么会“丢模块”

知道症状之后,得搞清楚底层逻辑。Android Studio 的工程模型是分层的:最底层是 Gradle 构建模型,负责解析settings.gradle、build.gradle,生成一个项目树;中间层是 IDE 的 Project Structure 模型,通过 Gradle Sync 拿到这棵树后,再映射成你能在左侧面板看到的模块列表;最外层是运行配置,依赖模块结构生成可执行的 Run Configuration。

这三层里任何一层出了问题,结果都可能表现为 “No Module”。所以修复的核心思路是:从下往上逐层修,而不是只看最上一层。

2.1 Gradle 同步失败会引发连锁反应

Gradle Sync 是 AS 和 Gradle 之间的握手过程。AS 发起 Sync,Gradle 执行settings脚本和项目配置脚本,然后把完整的项目模型返回给 AS。如果settings.gradle里声明的模块路径不存在,或者某个模块的build.gradle在配置阶段抛异常,Sync 就会失败。

Sync 失败的关键后果是:AS 不会更新 IDE 层的工程结构,但也不会立刻清掉旧结构。这时候你会看到两种情况——如果旧的.idea缓存里还有模块记录,面板上可能还残留模块名,但点击编译时报各种奇怪的依赖错误;如果缓存被清过,就直接 “No Module”。所以很多“玄学问题”的真相是:上一次 Sync 失败后,AS 用了一份残缺的模型继续工作。

2.2 .idea 与 .iml 文件的作用

很多新手不知道.iml文件是干嘛的。Idea Module 文件,本质上是 IntelliJ 平台对“模块”的序列化描述。它记录了模块的源码目录、依赖库、编译器输出路径等。Android Studio 的模块树完全由.idea/modules.xml指向的各个.iml文件决定。

如果你用文本编辑器打开一个正常的.iml文件,会看到里面是一个<module>根节点,包含<component name="NewModuleRootManager">、<content url="file://$MODULE_DIR$">等子节点。这个文件一旦被写坏,比如 Git 合并时出现冲突残留(<<<<<<< HEAD直接写进了 XML),AS 解析 XML 失败,就会忽略这个模块,表现就是模块列表丢失。

这里有个容易忽略的细节:.iml文件里的$MODULE_DIR$是相对路径变量,如果工程整体移动过位置,或者模块目录被重命名,旧的.iml里记录的url指向的路径就不存在了。AS 不会自动修正,它只会报 “doesn't exist anymore”,然后谢绝加载。

2.3 settings.gradle 的模块注册逻辑

Gradle 的多模块工程通过settings.gradle的include ':app'声明模块。这个文件是 Gradle 的世界里模块的“户口本”。如果你用的是新版 AGP(Android Gradle Plugin 7.0+),settings.gradle里通常还会加上pluginManagement和dependencyResolutionManagement,结构看起来比老工程复杂,但include的位置仍然决定一切。

我见过一个工程,同事在合并分支时把include ':app'这一行弄丢了,Gradle Sync 直接成功——因为根工程本身是合法的、没有模块的项目也能 Sync。但 AS 里就没有任何模块了,Run 按钮消失,报 “No Module”。这种情况最坑,因为 Gradle 并没有报错,表面上一切正常,只有模块列表是空的。

定位方法很简单:打开settings.gradle,看有没有include语句;再看project(':app').projectDir有没有被手动改成不存在的路径。后者是另一个隐蔽坑:如果设置了项目重定向但目录对不上,Sync 也会失败或忽略。

2.4 AGP、Gradle、JDK 版本匹配问题

版本不匹配不会直接说 “No Module”,但会引发 Sync 失败或配置阶段报错,间接导致模块结构无法生成。常见情况有:

  • Gradle 版本太老,不支持 AGP 要求的 API,Sync 时抛Unsupported class file major version。
  • JDK 版本太新,Gradle 老版本无法运行,报Unsupported major.minor version。
  • AGP 需要的 Build Tools 版本本地没装,Sync 时尝试自动下载失败,卡在Failed to find Build Tools revision x.x.x。

这三类错误都会让 Sync 停在配置阶段,AS 无法拿到模块模型。你可能注意到:错误提示里甚至没有 “No Module” 这个词,但最终用户体验就是“编译运行不了,模块也没了”。

我建议的版本对照参考
AGP 版本最低 Gradle 版本推荐 JDK 版本
4.2.x6.7.1JDK 8 或 11
7.0.x7.0.2JDK 11
7.4.x7.5JDK 11 或 17
8.1.x8.0JDK 17
8.5.x8.7JDK 17

这不是官方完整对照表,真实对应关系要查 AGP release notes,但按这个基准排查基本不会跑偏。

2.5 Gradle 缓存损坏和进程被杀

Gradle 在~/.gradle/caches下维护了大量缓存,包括依赖 jar、构建脚本编译结果、模块元数据。如果某个依赖在下载过程中被中断(断电、强制杀进程、网络超时),缓存目录里会留下一个只有几 KB 的残缺 jar 文件。Gradle 默认认为缓存里有的东西就是好的,不会重新下载,于是编译时抛Could not resolve或更诡异的No module类错误。

还有一种情况是:本机同时开了多个 IDE 窗口,或者杀毒软件在后台扫描 Gradle 目录,导致 Gradle daemon 的锁文件异常。Daemon 被强杀之后,~/.gradle/daemon下会有残留的.out日志和状态文件,下次启动可能直接报 “Daemon is not available”,或者 Sync 卡死。Sync 卡死超过一定时间,AS 会放弃本次握手,模块结构不更新,表现依然是 No Module。

3. 修复实操:一套按顺序来的完整排查链路

以下每一步都是我多次验证过的,建议严格按顺序执行,不要跳步。跳步容易引入新变量,最后更难定位。

3.1 第一步:确认 Gradle 本身能跑通

这一步的目标是确认 Gradle 构建环境本身没有坏。打开Terminal(AS 自带或系统终端都行),进到工程根目录,执行:

./gradlew help --stacktrace

如果这个命令能跑到BUILD SUCCESSFUL,说明 Gradle 脚本解析、依赖下载、模块配置都没有大问题,问题大概率出在 IDE 元数据层。如果这个命令就失败了,先看失败原因再往后走。

有些工程没有 Gradle Wrapper,或者gradle-wrapper.properties里distributionUrl被改坏了,下载地址指向一个不存在的版本。检查一下:

distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip

如果本地没有对应版本的 Gradle,AS 会在 Sync 时自动下载,但国内网络经常下载到一半就断。建议手动用下载工具把 zip 下载好,放到~/.gradle/wrapper/dists对应的目录里,或者直接改distributionUrl指向本地文件路径。

3.2 第二步:检查 settings.gradle 的模块注册

打开工程的settings.gradle(新版本是settings.gradle.kts),确认包含include ':app'。如果工程有多个模块,比如:library-base、:library-common,也都要列出来。

如果发现include没问题,再看有没有project(':xxx').projectDir的重定向代码,确认路径正确。举个例子:

include ':app' project(':app').projectDir = file('../MyApp')

如果../MyApp这个目录不存在,Sync 不报错但 app 模块会消失。此时应把路径改回来,或者把模块目录恢复到对应的位置。

这里有个细节:新版 AS 会把settings.gradle里自动生成的pluginManagement和dependencyResolutionManagement块放到最前面,include语句可能在文件后半部分。用搜索功能找include比肉眼扫更快。

3.3 第三步:清理并重新生成 .iml 文件

如果 Gradle 命令执行成功,说明 Gradle 层没问题,接下来处理 IDE 层。

步骤:

  1. 关闭 Android Studio。
  2. 进入工程根目录,删除整个.idea目录。
  3. 删除所有*.iml文件,包括根目录下的和模块目录下的。
  4. 重新打开 Android Studio,选择Open,定位到工程根目录。

注意这里不要双击工程目录直接打开,要使用Open按钮。AS 会重新解析settings.gradle,生成新的.idea和.iml文件,触发 Gradle Sync。

为什么不建议手动改.iml?因为 IntelliJ 的.iml格式在不同版本间有差异,手改容易漏字段,而且模块的依赖关系是 Gradle Sync 时动态生成的,手写一个缺依赖的.iml照样跑不起来。删掉让 AS 重新生成,是最干净的方式。

3.4 第四步:重建 Gradle 缓存

如果重新打开还是老样子,或者gradlew help就报错,就得动 Gradle 缓存了。先试温和的方式:

./gradlew clean

如果这个命令本身就失败,说明本地缓存可能已经被污染。把~/.gradle/caches目录改名备份:

mv ~/.gradle/caches ~/.gradle/caches.bak

然后重新 Sync。注意:改目录名会让 Gradle 重新下载所有依赖,第一次会很慢,别因为这个就否掉这个方案。依赖下载完成后,新缓存是干净的,很多莫名其妙的问题会消失。

如果~/.gradle/caches太大不想全删,也可以用--refresh-dependencies参数精确刷新依赖:

./gradlew --refresh-dependencies assembleDebug

这个命令会对比远程仓库和本地缓存的校验值,把不完整的缓存文件标记为过期并重新下载。但说实话,在已经出现 No Module 的故障现场,我更推荐直接移走整个 caches 目录,干净利落。

3.5 第五步:核对 SDK 位置与 JDK 版本

打开File > Project Structure > SDK Location,确认 Android SDK 路径存在。最常见的坑是:换了电脑之后,SDK 路径还指向旧电脑的目录(比如旧用户名的路径),AS 找不到 SDK,Sync 直接失败。

JDK 设置一般在File > Settings > Build, Execution, Deployment > Build Tools > Gradle页面,Gradle JDK下拉框选择与 AGP 匹配的版本。如果你用 JDK 17 跑老工程(AGP 4.x),大概率报错;如果你用 JDK 8 跑新工程(AGP 8.x),也会失败。按前面表格对照调整即可。

顺便检查一下ANDROID_HOME和JAVA_HOME环境变量,虽然新版 AS 不再强制要求,但很多构建插件和命令行脚本依然会读取这两个环境变量。不一致时,IDE 里能编译但命令行构建失败,反过来也有。

3.6 第六步:直接用 Import Project 重置工程结构

前面所有步骤都试了还不行,最后的大招是:用File > New > Import Project重新导入工程目录。这个方式和直接 Open 的区别在于,Import 会强制 AS 把所有 Gradle 设置、模块映射、运行配置全部重新生成,相当于“重装”了工程结构。

导入之后,等 Gradle Sync 跑完,一般都能恢复正常。如果连这样都不行,那基本可以确定是工程文件本身的问题——比如某个build.gradle.kts里有大量语法错误。先用gradlew help的报错信息定位具体脚本文件。

4. 高频 “No Module” 变种:不止是工程结构问题

前面说过,“No Module” 在不同语境下含义不同。这里单独开一章,把几个我实际处理过的高频变种讲透,帮你避免在错误的方向上浪费几小时。

4.1 构建脚本里调用 Python 报 No module named

这种问题在工程里嵌入了自动化脚本之后非常常见。比如你为了生成版本号,在app/build.gradle里写了:

task generateVersion { doLast { def result = ['python', 'scripts/gen_version.py'].execute() // ... } }

如果当前机器 Python 环境缺包(pkg_resources属于setuptools,yaml属于PyYAML),Gradle 执行到这一步直接抛异常。但报错信息里可能只有一行No module named 'pkg_resources',很多人想不到这居然是 Python 的问题。

解决方案:

  1. 在终端执行python --version,确认默认 Python 是 2 还是 3。
  2. 执行pip list,看缺不缺对应的包。
  3. 缺哪个装哪个:pip install setuptools pyyaml。

如果你的构建脚本里用的是python3而系统默认python指向 Python 2,也会出现装了包还是找不到的情况。建议在 Gradle 脚本里显式指定解释器路径,比如/usr/bin/python3或C:\Python39\python.exe,避免踩系统的 PATH 坑。

另外提醒一下:pkg_resources这个模块在 Python 3.12 之后被移出了标准库,如果你用的是最后几个版本的 Python 而 setuptools 不是最新版,哪怕装了也可能报破损。直接升级:

pip install --upgrade setuptools

4.2 C/C++ 原生模块加载失败

如果你的工程包含 NDK 代码,编译时报 “unknown module(s) in qt: serialport” 或者类似的 FFI 模块加载失败,那就是另一条线了。虽然报错里也带 “module”,但本质是 CMake 或工具链的问题。

排查思路:

  1. Local.properties里有没有配置ndk.dir,或build.gradle里有没有指定ndkVersion。
  2. CMake 版本和 NDK 版本是否匹配 AGP 要求。
  3. 64 位与 32 位 ABI 是否都被正确声明。

在实际开发中,这个错误的常见场景是:把工程从旧电脑迁到新电脑后,NDK 路径失效。AS 会在 Sync 时尝试自动下载指定版本的 NDK,但下载速度极慢,超时后 Sync 失败,模块结构没有生成,表现为 “No Module”。

4.3 WebView 加载时报 MIME 类型错误

这个我今天特地拿出来说,因为它在 debug 构建里非常容易误判为编译失败。报错长这样:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html"

通俗解释:你的网页代码里用了<script type="module" src="xxx.js">,浏览器要求服务器返回的Content-Type必须是application/javascript之类合法的 JS MIME 类型,结果服务器返回的是text/html——通常意味着这个 JS 文件不存在,服务器返回了 404 页面。

在 Android Studio 的工程里,这种问题一般出现在:

  • Flutter 工程跑 Web 版时,web/index.html引用了不存在的 JS 文件。
  • H5 套壳工程里,assets目录的本地资源路径和加载代码不一致。
  • DevTools(vConsole 或 Chrome DevTools)注入脚本时被本地静态服务器拦截。

解决方案就是去确认资源路径,而不是重装 Android Studio。检查index.html里<script>的src指向,确认对应文件真的存在于服务器根路径下。如果本地开发服务器端口被占用导致资源回退 404,杀掉占用端口的进程重启即可。

4.4 Qt 工程报 unknown module(s)

这个虽然不完全是 Android Studio 的场景,但相关热词里反复出现 “unknown module(s) in qt: serialport”,我顺手讲一下。在 Qt 工程里缺少模块,通常是开发包里没装对应的 Qt 组件。在安装 Qt 时,Serial Port 模块不是默认组件,需要勾选。如果你收到这个错误,重跑 Qt 安装程序,在组件列表里勾上 “Qt Serial Port”,加载对应 msvc/mingw 套件即可。

这个错误和 Android Studio 的 No Module 逻辑上是一类:都是构建系统找不到它需要的模块,但生态完全不同,解决方式五花八门。所以看到 “No Module” 第一件事永远是看日志上下文,而不是记忆对应某个固定解法。

5. 防复发经验:几件值得养成习惯的小事

排错排了这么多次,我总结出几条能大幅度减少 “No Module” 类问题的经验,都是实际操作中花了代价换来的。

5.1 不要手动删 build 目录和 .idea 目录

很多网上教程会告诉你 “删掉 build 目录再重新编译”,这招确实有效,但前提是用./gradlew clean来做,而不是手动进文件管理器里删。手动删除容易漏掉一些文件,而且如果你正在运行 emulator 或真机调试,window 上.dll文件可能被占用,删不干净反而留下半损坏目录。另外.idea目录不要提交到 Git,也不要随便手动改里面的文件。

如果.idea目录已经提交到 Git 仓库且经常发生冲突,建议从版本控制里移除并加入.gitignore。每个开发者本地生成自己的.idea,能少很多扯皮。

5.2 Gradle 与 AGP 版本升级前先读文档

我见过最多的问题不是版本太低,而是版本 “混合怪癖”:Gradle 用了 8.7,AGP 用了 7.4,JDK 用了 21。三者单独看都是主流版本,互相搭配却直接不兼容。Android 官方把兼容矩阵写在文档里,升级前花五分钟核对一眼,能省一整天的排错时间。

真出问题也别慌,先在gradle-wrapper.properties里换 Gradle 版本,再在build.gradle里换 AGP 版本,逐项降低,总能回到一个能编译的稳定态。

5.3 用 Wrapper 固定 Gradle 版本

手动安装的全局 Gradle 版本和工程 Wrapper 指定的版本不一致,是另一个隐性坑。有些命令如gradle build用的是全局版本,而 AS 用的是 Wrapper 版本。两边结果不一致时,你会看到命令行编译成功,AS 却失败。

我现在所有工程都强制使用./gradlew,不碰全局gradle命令。团队新成员用git clone拉下代码后,第一次执行也强制走 Wrapper 下载对应版本,保证大家构建环境一致。

5.4 看日志优先于搜帖

遇到 “No Module”,先做两件事:

  1. 打开Help > Show Log in Explorer(macOS 是Show Log in Finder),看idea.log最后几百行。
  2. 打开~/.gradle/daemon/8.7/daemon-8.7.out.log看 Gradle daemon 的日志。

这两个日志文件会把真正的异常堆栈打出来。搜帖子只能碰运气,看日志才能定位问题。大部分 “No Module” 在日志里都能找到一条更具体的Caused by,顺着它排查,路径会清晰得多。

6. 实战收尾:一次完整的修复过程示范

最后分享一个近期处理的案例,完整走一遍排查流程,希望能帮你建立整体的直觉。

一个老工程,AGP 7.0.4,Gradle 7.5,JDK 11,同事电脑上编译得好好的,换到新电脑后打开工程,AS 提示 “No Module”。我没有直接重装,而是按上面流程执行:

  1. ./gradlew help执行成功,说明 Gradle 层正常。
  2. 打开settings.gradle,include ':app'正常。
  3. 关闭 AS,删除.idea和所有.iml,重新 Open。
  4. Sync 之后依然没模块。
  5. 看idea.log,发现一条SDK location not found的错误。
  6. 打开Project Structure > SDK Location,原来存的 SDK 路径是旧电脑的C:\Users\old_user\AppData\Local\Android\Sdk,而新电脑用户名不同,路径自然不存在。
  7. 改成新电脑的 SDK 路径,Sync 完成,模块恢复。

整个过程不到十分钟。如果一开始就重装 AS,大概率没用,因为问题在 SDK 路径配置,和 AS 本体无关。

这个案例最能说明一件事:No Module 是现象,不是原因。现象背后可能是 SDK 路径、模块注册、Gradle 代码、脚本环境、缓存损坏,甚至端口占用。先把现象描述清楚,再一层层往底层排查,才能高效解决。希望这五千字的排查手册能帮你在下次遇到 “No Module” 时少走点弯路,也希望你和我一样,最后修好之后发现——其实真凶往往就藏在一行意想不到的配置里。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 6:33:06

文生图模型盘点:设计师必备 AI 生图工具推荐(2026 版)——TaoToken 统一 Key 接入 Midjourney 与 Stable Diffusion 的配置骨架

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

作者头像 李华
网站建设 2026/9/29 6:32:43

AI智能分析在Robin中的应用:如何让机器理解暗网数据

AI智能分析在Robin中的应用&#xff1a;如何让机器理解暗网数据 在当今数字化时代&#xff0c;暗网已经成为网络安全威胁的重要来源。Robin作为一款AI驱动的暗网OSINT工具&#xff0c;通过智能分析技术让机器能够深度理解暗网数据。本文将带您了解Robin如何运用AI技术解析暗网…

作者头像 李华
网站建设 2026/9/29 6:32:08

VS Code 使用 Skills 实战:用 TaoToken 统一 Key 打通 AI 编程工作流

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

作者头像 李华
网站建设 2026/9/29 6:30:48

智谱GLM-4.5开源炸场,TaoToken统一API接入实测

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

作者头像 李华