news 2026/9/16 6:03:47

WhiteboxTools:ArcGIS外挂级分析后厨,468个命令赋能水文与LiDAR处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
WhiteboxTools:ArcGIS外挂级分析后厨,468个命令赋能水文与LiDAR处理

简介:WhiteboxTools-ArcGIS工具箱是一套面向GIS分析人员、遥感与地理信息处理工程师的ArcGIS扩展工具集,整合468项空间分析功能,兼容ArcGIS 10.6及以上桌面版与Pro平台。工具覆盖成本距离分析、距离缓冲、栅格重分类、影像全色锐化与对比度调整、流域划定、河流网络分析、汇移除、坡度曲率湿度指数等地形分析,以及LiDAR点云查询、分割、插值与地面点分类,能补足ArcGIS原生工具链在水文与激光雷达处理能力上的短板。压缩包共607个文件,以xml功能配置、py脚本、exe可执行程序、tif示例栅格与shp矢量图层为主,整体仅14.2MB,结构精简便于快速配置。包内附Landsat影像边界、CLSA湿地多类型要素及DEM等实测样例,安装后可直接运行验证工具效果。目前已有3157人学习下载,适用于需要在专业GIS生产与研究项目中集成高级地形分析、空间水文建模与点云处理能力的用户。

1. 为什么说 WhiteboxTools 是 ArcGIS 外挂级的分析后厨

在 ArcToolbox 里点习惯了「填洼 → 流向 → 流量累积」三连的人,第一次用 WhiteboxTools 会有种错觉:这不就是把工具换了个壳吗?实际上它是独立于 ArcGIS 引擎之外的一套本地分析后端,整整 468 个命令,覆盖面从水文、地形、LiDAR 一路到图像增强和栅格重分类。和 ArcGIS 自带工具的重叠是有一部分,但它的优势在于那些「ArcGIS 里要做三步、找半天选项」的操作,在这里往往一个命令带参数带走,而且很多算法有专门的速度优化。这套东西对两类人最有用:一类是天天在 ArcGIS 里做栅格批处理、嫌模型构建器太啰嗦的从业者;另一类是手里握着 LiDAR 点云、想在不碰 Python 第三方库的情况下快速出 DEM、强度图或做地面点分类的人。它不是拿来画图的,它是拿来把数据洗到能上图的程度。你把它挂进 ArcGIS 当工具箱用,或者干脆命令行裸跑,两种用法我会在本篇里都拆开讲。

2. WhiteboxTools 的 468 项功能矩阵:从水文指数到 LiDAR 点云,怎么快速对号入座

2.1 工具的归属分类:先弄清这 468 项到底覆盖了哪些域

刚拿到 whitebox_tools.exe 的时候,直接敲--help会刷出一屏工具名,看多了容易眼花。我一般会先按它的官方功能域把它拆成六块来记:地理分析、水文分析、地形分析、LiDAR 分析、图像处理、数据工具。地理分析里最重要的是成本-距离、缓冲区和栅格重分类;水文分析则是一整套从汇到流域的链式工具;地形分析覆盖坡度、曲率、湿度指数、山体阴影以及多尺度地形位置;LiDAR 部分则负责点云查询、分割、插值和地面点滤波;图像处理里有全色锐化、对比度调整、拼接和 k-means 分类;数据工具提供了一些 ArcGIS 里要找半天才能凑齐的转换和矢量化功能。

提示:不是所有工具都在 ArcToolbox 里有对应项。比如多尺度地形位置(Multiscale Topographic Position)和山谷密度(Valley Density)这类偏科研和生态的工具,ArcGIS 原生环境要绕很多路才能做出来,而这里就是一个参数的事。

用一张简表把分布与 ArcToolbox 对应关系拉清楚,方便上手时定位。

功能域代表工具关键字日常用途和 ArcToolbox 的关系
水文分析FillDepressions, D8FlowAccumulation, Watershed汇填挖、流向累积、流域分割功能重叠但实现更快,部分算法不同
地形分析Slope, Curvature, TopographicPositionIndex常规地形指数、地貌分类与 Spatial Analyst 重叠,速度明显占优
LiDARLidarInfo, LidarGroundFilter, LidarTiling点云信息、地面滤波、分块ArcGIS 默认不提供,是核心加分项
图像处理Pansharpen, ContrastEnhancement, KMeansClassification影像增强、简单分类相当于把多个工具浓缩成单体命令
数据工具RasterToVector, VectorToRaster, MergeRaster格式互转、拼接部分命令在 ArcGIS 里没直接等价物

2.2 GeoTIFF 与激光雷达点云是该工具箱的「母语格式」

用这套工具之前要转变一个观念:它是设计来和后端栅格数据打交道的,不是和数据库打交道的。项目正体里出现的.dep后缀文件,其实是 Whitebox 自有的 DEM 存储格式,这种格式在读写大范围高程数据时抓得很快,但如果你不习惯,完全可以先用它把任意栅格转成 GeoTIFF 再进 ArcGIS。主流输入它基本都吃:GeoTIFF、TIF、SAGA、AAIGrid、ASCII Grid,以及 LiDAR 点云常见的 LAS/LAZ 格式。

所以拿到一个数据包第一步不是直接分析,而是先用数据信息命令看清楚数据内容。我在任何项目里都会先跑这一句看数据类型和坐标系:

whitebox_tools.exe --run=Info --wd="D:/gis_data" --files="DEM.dep"

这个命令会在控制台打印 DEM.dep 的尺寸、分辨率、投影、数据范围、最小最大高程值和 NoData 设置。为什么要先看这些?因为后面跑填洼、算流向时,NoData 的分布直接决定你需不需要先做一次栅格重分类来屏蔽异常值。工具不会帮你判断数据值合不合理,它只会按参数执行。

参数说明: --wd 指定工作目录,所有相对路径都基于此目录解析。 --files 可以传一个文件或者多个文件,用逗号分隔。 --run 指定工具名,大小写敏感。

2.3 命令行的执行模型:一条命令就是一个流水线单元

这里要刻意区分「命令执行」与「ArcGIS 单步工具」的差异。ArcGIS 的每个工具是状态化的,跑完一步会往内存或磁盘写中间结果,而 WhiteboxTools 默认把所有中间结果显式写为文件。也就是说,你在 ArcGIS 里做分析和在 Whitebox 里做分析,最大的手感差异是:后者每一个工具的输入输出都是磁盘上的硬文件,没有内存图层一说。

这意味着设计处理链时,你得习惯把一个完整流程拆成「文件 → 文件」的管线。我一般在工程目录下建三个子目录:raw/放原始数据、interim/放中间栅格、final/放最终成果。然后用批处理脚本把命令串起来。比如做坡度前先做一个简单的重分类把边界外的值去掉:

whitebox_tools.exe --run=Reclass --wd="D:/gis_data" -i="DEM.dep" -o="interim/DEM_reclass.tif" --reclass_val="0;5000" --assign_val="0;1"

这段比在 ArcGIS 里打开重分类对话框再填两遍阈值表要直接,而且参数就是值域和输出值两段,逻辑一眼就能看懂。如果源数据本身已经是干净的DEM,这一步可以跳过;但你要是不知道要不要跳,就先跑Info看统计值再决定。

3. 手工挂载与命令行双通道:在 ArcGIS 10.6 与 ArcGIS Pro 里跑通第一个工具

3.1 工具箱连接:最简单的接入方式其实不用安装任何东西

很多人看到「ArcGIS 工具箱」五个字,以为要走安装向导,实际上 WhiteboxTools 的 ArcGIS 前端并不需要注册 dll 或配置 Add-In 之类的繁琐操作。你只需要在 ArcGIS 的 Catalog 窗口里右键文件夹连接,指向你解压后的工具箱目录,就会看到一个.tbx格式的工具箱文件,里面按分类列出了对应工具,每个工具的参数面板和 Python 脚本工具一致。无论你是 ArcGIS 10.6 还是 ArcGIS Pro 3.x,都走同一条路。

提示:就算你的 ArcGIS License Server 服务点击启动后没反应,只要 ArcMap 本身能打开,Catalog 的工具箱连接功能就不会受影响。这个工具箱是纯文件型的,不依赖任何服务级组件,启动不了服务的问题多半出现在服务未注册或 27000 端口没监听,和 WhiteboxTools 无关。

ArcGIS Pro 里也是一样的逻辑,只是入口从 Catalog 窗口换成了「目录」窗格。我建议拿到压缩包之后先解压到一个纯英文路径,避免中文路径在部分 ArcGIS 版本的工具对话框里出现编码问题。解压后如果你看到whitebox_tools.exeWhiteboxTools ArcGIS toolbox.tbx在同一级目录,就说明包完整。

3.2 参数面板背后的路径传递逻辑

双击 ArcGIS 工具箱里的任一工具,你会看到类似 ArcToolbox 工具的面板,但底层机制完全不同。这个工具箱本质上是用 Python 包装了命令行调用,界面里的每个参数最终都会拼成一条--run命令。因此你在面板里填输出路径时,和命令行里填-o=的规则是相通的。

我一般会在面板里注意几个坑。一个是工作空间千万别留空格,C:/My Data/这种路径会把部分老版本 ArcGIS 的命令行拼装直接搞崩。另一个是输出的文件后缀一定要在面板里手动写全,比如输出工具要求 GeoTIFF 就写.tif,要求白盒自有格式就写.dep,有些版本不会自动补后缀。第三个是如果同时传多个输入文件,一定用分号分隔,不是逗号,这是 ArcGIS 参数面板的固有习惯,和命令行不同。

比如你要用面板跑一个 FillDepressions:

  • 输入 DEM:选DEM.dep
  • 输出 DEM:填interim/DEM_fill.tif
  • 平坦区增量:默认 0.001
  • 是否只填充单个像元洼地:勾选或留空,看你需求

面板底部会实时生成一段说明文字,说明文字里就是底层命令的预览。这条预览是最有用的排错信息,如果你在运行日志里看到Unable to open file,九成是你填的路径和实际文件对不上。

3.3 命令行的环境变量与参数规范,避开 Windows 下的引号陷阱

命令行模式比面板模式更自由,但 Windows 下引号和反斜杠问题很容易把人卡住。常见做法是:所有路径统一用正斜杠/,这样--wd="D:/gis_data"不会出现转义符错乱。松开引号包裹规则之后再批量执行,在 CMD 里会少很多莫名报错。

命令行的参数结构是--run=工具名配合具体参数,和面板里的 Python 封装有轻微区别,但工具名单词完全一致。写批处理时我习惯每个工具跑完之后紧接着写一行echo %errorlevel%,凡是白盒工具正常运行未报错,这个值会返回 0,返回其它数字就说明工具在运行时崩了。这样就可以在无人值守的批处理里快速抓到是哪一行出了问题。

set WD=D:/gis_data whitebox_tools.exe --run=Slope --wd=%WD% -i="interim/DEM_fill.tif" -o="final/slope.tif" --units=degrees echo %errorlevel%

这段批处理里--units=degrees是坡度单位设置,这里指定角度制输出,后面做地形分类时阈值更容易和常识对应。第一次跑通之后,你就等于拿到了一个不依赖 ArcGIS 界面就能做完整流程的入口,越跑越会发现它比鼠标点面板更可控。

4. 水文分析实战:从 DEM.dep 到流域边界的完整流程与参数陷阱

4.1 数据追溯与预处理:拿到数据包之后该先检查什么

前面提到项目包里出现了和湿地相关的矢量文件,比如CLSA_Wetland_Polylines.dbfCLSA_Wetland_Polygons.dbf,还有一期 Landsat 影像的边界文件LC80320272014265LGN00_Boundary.dbf。这些东西放在一起,说明数据集源头是一个以湿地生态为对象的研究区,白盒工具在这里最合适的切入场景,就是从DEM.dep出发做一套完整的水文分析链,把湿地与水系的拓扑关系提取出来。

开始之前先跑一次Info重述一遍:看 DEM 的投影是否是投影坐标系,如果它还是经纬度的地理坐标系,流向和坡度的计算距离会有形变。这个包里的 DEM 一般已经是 UTM 投影,但拿到手还是先确认下比较好。另外需要看最小高程和最大高程,如果最小值低于 -9999,那就说明这个数据量的 NoData 用了一个特殊值编码,填洼前必须先做ReclassSetNoData把它屏蔽掉。

对比边界线时常用到一个技巧:用CLSA_Wetland_Polylines.dbf里的 shapefile 文件做一个栅格化掩膜,然后把掩膜套在 DEM 上只保留湿地范围内的地形。这一招可以用白盒工具的VectorToRaster一步完成,然后再用Mask命令套上去。比起在 ArcGIS 里先转要素、再设掩膜、再提取,至少少点五个右键菜单。

4.2 无坑水文链:平缓地形区更要关心平坦区增量参数

湿地区域的地形特点是坡度极低,DEM 里经常有大片完全平坦的像元,这些地方是水文分析的天然陷阱。D8 流向算法遇到平坦区会算出无意义的流向,所以第一步必须是填洼。白盒的 FillDepressions 和 ArcGIS 的填洼在算法实现上有本质区别:ArcGIS 的 Fill 是基于 Planchon-Darboux 算法的一种实现,而白盒默认方法更加保守,它对平坦区的处理保留了海拔差,更利于后续做深度和体积计算。

我常用的流程是三步连跑:填洼 → D8 流向 → 汇流累积。

whitebox_tools.exe --run=FillDepressions --wd="D:/gis_data" -i="DEM.dep" -o="interim/DEM_fill.tif" --fix_flats=true whitebox_tools.exe --run=D8Pointer --wd="D:/gis_data" -i="interim/DEM_fill.tif" -o="interim/D8p.tif" --esri_pntr=true whitebox_tools.exe --run=D8FlowAccumulation --wd="D:/gis_data" -i="interim/DEM_fill.tif" -o="interim/accum.tif" --pntr="interim/D8p.tif" --esri_pntr=true

这里有个值得说的参数:--esri_pntr=true。这个参数会把白盒输出的流向编码改成 ESRI 风格(1 表示东,2 表示东南,顺时针顺推)。如果你后面要把流向结果拿回 ArcGIS 里做符号化,或者直接接 ArcGIS 的水文工具继续运行,这个参数必须打开,否则你会看到流向栅格的值域完全对不上。

--fix_flats=true是平坦区修整开关。湿地DEM跑完填洼后往往依旧有大片高程一致的像元,不开这个选项,D8 流向在这片区域会输出 NoData,后续累积量就断了一截。开了之后算法会在平坦区内强制生成一条微渐变路径,保证流向连续。

注意:--fix_flats=true只对 FillDepressions 有意义,不是填洼工具请勿传入否则会报错。

汇流累积结果accum.tif里每个像元值代表上游汇入的像元数量,这个值直接作为河网提取阈值依据。一般用StreamDefinition工具,阈值设在 1000 或 5000,看研究区尺度和像元分辨率。10 米分辨率下湿地周边的一个小型集水区,用 1000 会比较碎,用 5000 会丢掉一级沟渠,这个没有绝对正确,只能试跑后对照影像检查。

4.3 从河网到流域:矢量化的边界要回 ArcGIS 里和湿地多边形对表

一旦河网栅格生成,下一步自然就是流域分割。白盒的Watershed工具接收两个输入:流向栅格和出水口栅格。出水口可以是点状栅格,也可以直接从河网栅格里自动提取交汇点。比较省事的做法是先对河网做一次JensonSappingtonStrahlerOrder分级,把 2 级或 3 级以上的河段提取出来当汇水点。

whitebox_tools.exe --run=StrahlerOrder --wd="D:/gis_data" -i="interim/stream.tif" -o="interim/order.tif" whitebox_tools.exe --run=ExtractStreams --wd="D:/gis_data" -i="interim/order.tif" --mask=2 -o="interim/streams_mask2.tif" whitebox_tools.exe --run=Watershed --wd="D:/gis_data" -i="interim/D8p.tif" -o="final/watersheds.tif" --pour="interim/streams_mask2.tif" --esri_pntr=true

ExtractStreams里的--mask=2表示只保留 Strahler 等级为 2 及以上的像元,等级低于 2 的那些细碎沟道不会成为流域出水口。生成watersheds.tif之后,可以再用RasterToVectorPolygons把它转成矢量面,在 ArcGIS 里与CLSA_Wetland_Polygons.dbf叠加查看流域边界与湿地斑块的重合关系。

这里我特别要多说一句:白盒的RasterToVectorPolygons输出结果不携带属性表里的专题属性,它只保留一个栅格值字段。所以在 ArcGIS 里叠加时,如果你想按流域编号关联原始湿地数据,要先用ZonalHistogramZonalStatistics这类工具重新统计,而不是想当然以为矢量化之后属性会跟着走。

4.4 参数陷阱汇总:填洼顺序、NoData 编码、投影三座大山

水文分析这条链最大的排错成本通常不在工具本身,而在前处理。第一个陷阱是填洼顺序:必须先跑Reclass把 NoData 边界值洗掉,再跑FillDepressions。如果直接填洼,算法会对 NoData 区域做外推插补,边缘会出现一圈巨大洼地,流向后继工具在边界处全部指向研究区内部。这个问题出现时,输出高程的最小值会明显低于合法值,用Info一查就能发现。

第二个陷阱是 NoData 编码。有些 DEM 把 -32768 当 NoData,有些把 -9999 当 NoData,白盒工具识别的默认是nodata标志,但遇到特殊编码值时它会当成真实高程参与计算。处理手段是先用Reclass把小于等于 -9999 的值重分类为 NoData,再输入后续工具。

第三个陷阱最常见也最隐蔽:投影坐标系的单位。白盒的坡度默认单位是度,但汇流累积和距离计算全部按栅格分辨率来推算,如果你的 DEM 是地理坐标系,每个像元在实际地面的尺寸是不一样的,算出来的累积单位只能当作无纲量指数,不能换算成实际面积。凡是涉及流域面积、缓冲区距离的场景,务必提前投影到合适的 UTM 或 Albers 坐标系。

5. 把批处理加速做成常态:多核调度、列表文件与可视化前处理的边界

5.1 利用多核:白盒工具默认全核运行的适用与例外

WhiteboxTools 的大部分栅格工具在编译时就启用了 OpenMP 多线程,你不用额外开任何开关就能吃满多核。实测在八核处理器上做 10000×10000 的 DEM 填洼,时间通常在一分钟以内,同样的数据量 Spatial Analyst 里可能要等三到五分钟。这个速度优势在需要反复调阈值时非常珍贵,我通常会把填洼、流向、累积三步合成一个批处理,然后在一个命令窗里反复换阈值跑,阈值用循环变量传入:

for %%t in (500 1000 2000 5000) do ( whitebox_tools.exe --run=ExtractStreams --wd="D:/gis_data" -i="interim/order.tif" --mask=%%t -o="final/stream_%%t.tif" )

%%t是 CMD 批处理里的循环变量,前面多出的%是批处理文件的转义要求,直接在命令行里写单%t即可。这个循环会在final/下生成四个不同阈值的河网结果,你可以在 ArcGIS 里一次性叠加四个文件,对比哪个阈值和影像上的实际沟道最贴合。

5.2 用列表文件管理成百上千个输入文件

当面对一个子区域特别多的数据集,比如项目包里带了很多按行政区或图幅编号的矢量、栅格文件,手动在命令行里列举输入路径几乎不可行。白盒支持用一个列表文件(arguments file)来接收参数,把每个工具参数放在一个.txt里,用--args传进去。常见做法是:

--run=LidarGroundFilter --wd=D:/gis_data/las -i=block_01.las -i=block_02.las --output=block_01_filtered.las --output=block_02_filtered.las --radius=2.0 --slope_threshold=8.0

执行时写:whitebox_tools.exe --args=params.txt。这种方式比在命令行里堆一长串参数更稳,尤其当路径里有空格、或者输出文件名要对应多个输入文件时,能避免引号嵌套导致的解析错乱。列表文件里的--run仍不能省,它决定本次调用运行哪个工具,文件里可以带多个-i-o,工具会自动做多文件映射。

5.3 它不负责的部分:制图渲染与在线底图叠加应该交给 ArcGIS Pro

最后要强调一个使用边界:白盒工具不是绘图工具,它的输出风格完全不适合直接出图。你要把生成的湿度指数、流域边界、坡度图叠加到天地图或影像底图上,正确的姿势是在 ArcGIS Pro 里先加载在线底图,再导入白盒输出的 GeoTIFF。很多人折腾怎么在 ArcGIS 里调用天地图,其实核心要点就是两点:一是通过 WMTS 服务地址添加底图,二是确保分析栅格已经经过了符号化拉伸。

我一般会把白盒处理完的结果导出为 Cloud Optimized GeoTIFF(COG),这样在 ArcGIS Pro 里加载时只传输可视范围内的数据块,不再等待全图读入。生成 COG 的方式可以用白盒的ExportGeoTIFF--compress=deflate参数,也可以先输出普通 tif 到 ArcGIS Pro 里再用栅格导出功能生成。如果后续涉及 Web 发布,这些 COG 文件还能直接被arcgis api for js部署的地图服务加载,省去中间转缓存的一层。

说到 LiDAR 点云,这是很多 ArcGIS 从业者不会专门去学 Lastools 或 PDAL 时的替代路径。多个 LAS 文件需要批处理时,先写一个循环:

for %%f in (D:/lidar/*.las) do ( whitebox_tools.exe --run=LidarInfo --wd="D:/lidar" -i="%%f" )

这样能把每个文件的所有分类、点密度、覆盖范围一次性打到日志里,做完数据体检后,再根据点云分类情况决定要不要用LidarGroundFilter做地面点分离。这里提醒一点:白盒的 LiDAR 工具是完整可用的,但内存管理上不如纯 C++ 的商业软件那么激进,处理单文件超过 5000 万点的点云时,建议先用LidarTileFootprint分块或者用LidarTile切瓦片之后再做滤波,否则内存占用会顶满。

等这一套习惯成自然之后,你会发现做 GIS 分析时你开始先想「哪个工具命令能一条解决」,而不是先想「ArcGIS 里点在哪个菜单下面」。这也是 WhiteboxTools 这类工具集最大价值的地方:它逼你用管线思维去组织数据,而不是用鼠标去组织步骤。

本文还有配套的精品资源,点击获取

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

YuE2混合架构实战:AR-NAR Transformer环境搭建与推理

1. “YuE”不是拼写错误,而是当前生成式AI领域一个正在快速演进的技术代号最近在Hugging Face模型库、arXiv论文评论区和几个核心AI开发者的Discord频道里,“YuE”这个词出现的频率明显升高——它既不是某个新出的Python包名,也不是某款字体渲…

作者头像 李华
网站建设 2026/9/16 6:01:46

MATLAB自适应变步长龙格库塔法:原理、实现与ode45对比

简介:自适应变步长的龙格库塔法是数值积分与常微分方程求解中的常用算法,这份MATLAB代码包将核心思路整理为可直接运行的脚本和说明,适合正在学习数值分析、需要将理论转换为程序实现的开发者参考。包体非常小巧,共4个文件&#x…

作者头像 李华
网站建设 2026/9/16 6:01:31

黑白调P2全系横测:标准版/Pro/Max/轻享版怎么选?

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

作者头像 李华
网站建设 2026/9/16 6:00:46

AI专著写作大揭秘:用AI工具快速打造20万字高质量专著!

写一部学术专著,难度不仅仅是把文字写出来,更关键的是能不能顺利出版和被认可。现在出版学术专著的市场比较小,出版社对选题的学术价值和作者的学术背景都很重视。很多稿子即使写好了初稿,也会因为“缺少新意”或者“市场需求不大…

作者头像 李华
网站建设 2026/9/16 5:59:36

企业级智能体效能管理:可度量、可治理的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/16 5:57:20

ZeroClaw代码执行机制:具身智能的轻量级动作沙盒设计

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

作者头像 李华