焊接缺陷检测数据集实战:6类2684张YOLO+VOC双格式训练与避坑指南
简介这份资源面向从事工业质检、焊接工艺检测及计算机视觉方向的研究者与开发者提供一套可直接用于目标检测模型训练的焊接缺陷数据集帮助解决焊接缺陷样本稀缺、标注成本高的问题。压缩包共约2000个文件以1999个xml标注文件和1个说明txt为主整体约48.35MB内含JPEGImages图片、Annotations标注与labels标签三类目录图片与标注一一对应便于直接接入YOLO或VOC训练流程。数据集覆盖烧穿、污染、良好焊缝、未完全融合、渗透不足、错位共6类标签总框数2685个各类别框数分布较为均衡图片分辨率清晰且未做数据增强适合作为基线训练或对比实验的原始素材。目前已有314人学习下载读者可据此快速搭建焊接缺陷检测实验环境理解多类别缺陷的标注规范与类别分布为模型选型、数据增强策略及精度评估提供参考。1. 焊接缺陷检测数据集6类2684张的YOLOVOC双格式到底怎么用拿到一个标注好的焊接缺陷数据集第一反应往往不是兴奋而是怀疑——2684张够不够训一个能上产线的模型6个类别是不是分得太粗YOLO和VOC两套格式同时给是省事还是埋坑我最初接触焊接缺陷检测这个方向时踩过的最大一个坑就是直接拿COCO预训练权重硬套结果气孔和夹渣两类在验证集上几乎分不开。焊接缺陷检测属于典型的工业小目标检测场景缺陷区域在整张焊缝图像里占比很小背景纹理又高度重复这跟车辆检测数据集bdd100那种大目标、强语义的场景完全不是一回事。这个数据集的价值在于它把6类常见焊接缺陷——气孔、夹渣、裂纹、未熔合、未焊透、咬边——做了统一标注并且同时提供YOLO格式和VOC格式意味着你不需要自己写格式转换脚本就能直接对接YOLOv5/v8系列和Faster R-CNN这类两阶段检测器。适合谁用如果你正在做工业质检方向的落地或者想找一个真实缺陷样本来验证自己的目标检测pipeline这个规模的数据集刚好够你做完整的训练、验证、调参和导出onnx模型的全流程。2684张不算大但焊接缺陷的类间差异本身就比自然图像小关键看你怎么用增强和损失函数把边界撑开。2. 先搞清楚6类缺陷的标注逻辑和格式差异2.1 焊接缺陷的6个类别在实际标注中长什么样气孔在图像里通常表现为圆形或椭圆形的暗斑边缘相对清晰但尺寸变化极大小的可能只有十几个像素大的能占到焊缝宽度的三分之一。夹渣则是不规则形状的暗色区域经常沿着焊缝走向呈条带状分布和背景的对比度比气孔更低。裂纹是最难标的一类细长、分叉、走向随机标注时很容易漏掉细小分支。未熔合和未焊透在视觉上非常接近前者是焊缝与母材之间没融合后者是根部没焊透两者的区别往往需要结合焊接工艺参数才能判断纯靠图像标注时边界模糊。咬边是焊缝边缘的凹槽通常沿着焊缝两侧呈线状分布。这6类在VOC格式里用name标签区分在YOLO格式里用类别索引0到5对应。实际标注时最容易出问题的是夹渣和未熔合的混淆以及裂纹的漏标。我见过不少公开数据集把这两类合并成“其他缺陷”但这个数据集坚持分6类说明标注时是有工艺背景的人参与的。你拿到数据后第一件事应该是统计每类的实例数量和平均bbox面积如果某一类实例数少于200训练时就要考虑过采样或者focal loss加大该类权重。2.2 YOLO格式和VOC格式的目录结构差异VOC格式的标准结构是Annotations放XML、JPEGImages放原图、ImageSets/Main放训练验证划分文件。每个XML里包含图像的宽高、每个目标的bndbox坐标xmin、ymin、xmax、ymax和类别名。YOLO格式则是每张图对应一个.txt文件每行是class_id x_center y_center width height全部归一化到0到1之间。两种格式的坐标体系不同VOC是绝对像素坐标YOLO是归一化中心点坐标转换时最容易翻车的地方是归一化时的除零问题和坐标越界。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, class_map): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: continue cls_id class_map[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 裁剪到图像边界内防止标注越界导致归一化后坐标异常 xmin max(0, min(xmin, img_w - 1)) xmax max(0, min(xmax, img_w - 1)) ymin max(0, min(ymin, img_h - 1)) ymax max(0, min(ymax, img_h - 1)) if xmax xmin or ymax ymin: continue # 跳过无效框 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) return lines这段代码的关键点有三个一是坐标裁剪工业图像里标注人员偶尔会把框拉到图像外面不裁剪的话归一化后会出现负数或大于1的值YOLO训练时直接报错二是无效框过滤xmax小于等于xmin的框要丢掉否则w为负三是保留6位小数YOLO官方实现里对精度不敏感但保留6位能避免小目标归一化后的精度损失。class_map需要你自己定义比如{气孔:0, 夹渣:1, 裂纹:2, 未熔合:3, 未焊透:4, 咬边:5}顺序要和训练时的data.yaml里names列表一致。2.3 用脚本一键校验两种格式的一致性拿到数据集后不要急着开训先写个校验脚本确认YOLO的txt和VOC的XML描述的是同一批标注。常见的问题是转换脚本跑了两遍或者部分图像只有VOC没有YOLO。校验逻辑很简单遍历所有图像检查对应的txt和xml是否都存在然后随机抽100张对比转换后的坐标是否一致。import os, random def validate_consistency(img_dir, yolo_dir, voc_dir, class_map, sample100): imgs [f for f in os.listdir(img_dir) if f.endswith((.jpg,.png))] missing [] for img in imgs: stem os.path.splitext(img)[0] if not os.path.exists(os.path.join(yolo_dir, stem.txt)): missing.append(stem) if not os.path.exists(os.path.join(voc_dir, stem.xml)): missing.append(stem) print(f缺失标注的文件数: {len(missing)}) # 随机抽样对比坐标 for stem in random.sample([os.path.splitext(f)[0] for f in imgs], min(sample, len(imgs))): xml_path os.path.join(voc_dir, stem.xml) txt_path os.path.join(yolo_dir, stem.txt) # 这里调用前面的voc_to_yolo再和txt逐行对比 # 实际使用时建议把差异超过1e-4的行打印出来校验通过后再做训练集、验证集、测试集的划分。我一般按7:2:1切但如果某类缺陷实例数少于300会在划分时做分层抽样保证每个子集里都有该类样本。焊接缺陷数据集的6类分布往往不均衡气孔和咬边的实例数通常远多于裂纹和未焊透划分时不做分层的话验证集里可能一个裂纹都没有mAP曲线会非常难看。3. 用YOLOv8跑通焊接缺陷检测的最小训练流程3.1 环境配置和data.yaml的写法YOLOv8的环境配置比v5干净很多pip install ultralytics基本能搞定但要注意PyTorch版本和CUDA的匹配。如果你在AGX Orin上搭建YOLO环境需要装JetPack对应的torch轮子不能直接pip install torch。普通x86机器上pip install ultralytics会自动拉取合适的torch版本。装完后yolo checks能看环境是否正常。data.yaml是训练的核心配置文件焊接缺陷检测的写法如下path: /data/weld_defect train: images/train val: images/val test: images/test nc: 6 names: [porosity, slag, crack, lack_of_fusion, incomplete_penetration, undercut]path是数据集根目录train/val/test是相对路径。nc必须等于6names的顺序必须和YOLO txt里的class_id严格对应。我见过有人把names写成中文导致训练时标签乱掉YOLOv8虽然支持中文路径但names建议用英文或拼音避免编码问题。另外path不要用相对路径训练时工作目录一变就找不到数据。3.2 训练命令和6个必调参数最小训练命令就一行yolo detect train data/data/weld_defect/data.yaml modelyolov8s.pt epochs200 imgsz640 batch16 workers4但直接跑这个命令大概率效果一般焊接缺陷检测有6个参数必须根据数据特点调参数建议值理由imgsz640或960裂纹和未焊透目标小640以下会丢细节960显存不够就640batch8到162684张图batch太大容易过拟合太小BN不稳定lr00.001到0.01小数据集用0.001配合cosine调度mosaic0.5到1.0焊接缺陷背景重复mosaic能增加场景多样性但裂纹拼接后可能不连续建议0.5fl_gamma1.0到2.0类别不均衡时开focal loss气孔和咬边多的数据集建议1.5patience30到50小数据集收敛快patience太大浪费时间imgsz的选择要看你显卡显存8G显存跑640的yolov8s大概占6G跑960会OOM。如果裂纹在640下标注框小于8x8像素那必须上960否则下采样32倍后特征图上一个点都占不到。mosaic对焊接缺陷是把双刃剑增强后气孔和夹渣的形态更丰富但裂纹被拼接到不同背景后可能断裂成几段标注框还是原来的模型会学到错误的连续性。我的血泪经验是裂纹类占比高时mosaic降到0.3甚至关掉。3.3 训练过程中的关键监控指标YOLOv8训练时会输出box_loss、cls_loss、dfl_loss和mAP50、mAP50-95。焊接缺陷检测最需要盯的是每个类别的AP而不是总体mAP。如果气孔AP到0.9但裂纹只有0.3说明模型在裂纹上欠拟合。这时候不要急着加epoch先看验证集的预测可视化大概率是裂纹的标注框太细模型在anchor匹配阶段就丢了。另一个关键指标是cls_loss的下降曲线。如果cls_loss震荡不降通常是类别不平衡导致的气孔和咬边的梯度淹没了裂纹和未焊透。解决办法是在data.yaml里加cls_pw或者用fl_gamma。YOLOv8默认的分类损失是BCE对不平衡数据不如focal loss友好。我一般会在训练到50epoch时看一次混淆矩阵如果裂纹被大量预测成夹渣说明这两类的特征在浅层就混了需要加更深的主干或者用更高分辨率。4. 焊接缺陷检测的避坑与排查记录4.1 现象mAP50很高但实际推理全是误检原因验证集和训练集的背景分布太接近模型学到了背景捷径。焊接缺陷数据集的图像往往来自同一批焊缝背景纹理高度一致模型只要记住“这个纹理区域有缺陷”就能在验证集上拿高分但换一批焊缝就崩。解决划分验证集时按焊缝编号或拍摄批次切分不要随机切。如果数据集没有批次信息用图像哈希做聚类把相似背景的图分到同一子集。另外训练时开mixup和copy_paste增强强迫模型关注缺陷本身而不是背景。4.2 现象裂纹类AP始终低于0.4原因裂纹的标注框长宽比极端YOLO的anchor匹配策略对细长目标不友好。默认anchor是正方形为主裂纹的宽高比可能到1:20匹配不到合适的anchor。解决用yolo detect train ... anchor_t4.0放宽anchor匹配阈值或者改用YOLOv8的anchor-free分支。更彻底的办法是把裂纹单独切patch训练一个二分类模型再和主检测器做级联。我试过在640输入下裂纹AP只有0.35切到960后涨到0.52说明分辨率是瓶颈。4.3 现象训练loss正常但导出onnx后推理结果全乱原因YOLOv8导出onnx时默认不包含后处理输出是原始特征图需要自己写decode。很多人直接拿onnx输出当检测框用坐标全是乱的。解决导出时加nmsTrue让onnx包含NMS或者用yolo export modelbest.pt formatonnx opset12 simplifyTrue。推理时确认输入图像的预处理和训练一致特别是归一化和letterbox的padding值。焊接缺陷图像如果是灰度图训练时YOLO会复制成3通道导出后推理也要做同样处理。4.4 现象VOC格式的XML里类别名有空格或大小写不一致原因标注人员手写XML时把“气孔”写成“气孔 ”或者“Lack_of_fusion”写成“lack_of_fusion”转换脚本按字符串匹配时漏掉这些类。解决转换前先统计所有XML里的name文本做strip和lower处理建立映射表。不要直接信任原始标注的类别名工业数据集里这种不一致非常常见。我一般会写个脚本把所有类别名打印出来人工确认一遍再写死class_map。4.5 现象训练到后期验证集mAP突然掉点原因小数据集过拟合模型开始记忆训练样本。2684张图训200epoch后50epoch大概率在过拟合。解决开patience30早停或者用cos_lr让学习率在后半程降下来。另外weight_decay从默认的0.0005加到0.001dropout在分类头加0.2。如果掉点发生在mosaic关闭的那个epoch是正常的分布偏移等几个epoch会恢复。5. 把2684张用到极致小数据集下的增强策略和验证技巧2684张对于6类目标检测来说偏少但焊接缺陷的特殊性在于类内差异小模型需要学的特征维度比自然图像低。我的经验是把增强做狠一点但要有针对性。几何增强里degrees开到10到15焊接缺陷的走向在真实场景里有角度变化但不要开到90裂纹的走向是有工艺意义的。translate开到0.2scale开到0.5shear开到5。颜色增强里hsv_h开到0.015hsv_s和hsv_v开到0.7焊接图像在不同光照下灰度变化大颜色增强能提升鲁棒性。但有两类增强要慎用flipud垂直翻转对焊接缺陷是危险的咬边和未熔合在焊缝的上下位置有工艺含义翻转后语义变了。mosaic前面说过裂纹多的时候降到0.3。copy_paste对气孔和夹渣很有效可以把缺陷实例复制到不同背景上但裂纹复制后容易和背景纹理冲突建议只对气孔、夹渣、咬边开。验证阶段不要只看mAP焊接缺陷检测的落地指标是漏检率和误检率。漏检一个裂纹的代价远大于误检一个气孔。我一般会在验证后单独统计每类的召回率裂纹和未焊透的召回率低于0.85就不发版。测试时用yolo detect val ... conf0.1把置信度阈值调低看模型在低阈值下的召回上限如果conf0.1时裂纹还有漏检说明模型本身没学到不是阈值问题。最后一个技巧是关于模型导出的。焊接缺陷检测最终要上产线产线相机可能是灰度、可能是高分辨率、可能帧率要求30fps。导出onnx后用onnxruntime测一下单张推理时间如果超过33ms考虑用TensorRT或者换yolov8n。我习惯在训练完先导出onnx用onnxsim简化后再测简化前后推理速度能差20%。另外记得把预处理和后处理都写进推理脚本别依赖ultralytics的python接口产线上不一定能装。这个方向值不值得做如果你手上有真实的焊接缺陷数据哪怕只有几百张用这个数据集的6类定义和标注逻辑做迁移比从零标起省至少两周。2684张训一个基线模型够用但要上产线至少还要补2000张不同批次、不同光照的图。我踩过最大的坑是拿一个批次的图训完直接上线结果换了一批焊丝气孔的对比度变了模型召回掉了30%。后来养成的习惯是每批新数据先跑一遍验证集看每类AP的波动超过5个点就重新微调。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

2026年学生必备AI编程工具,强烈建议收藏:从Trae到TaoToken的实战配置清单

2026年学生必备AI编程工具,强烈建议收藏:从Trae到TaoToken的实战配置清单

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

2026/10/10 14:47:51 阅读更多 →
微信小程序开发框架怎么选?从原生到uni-app、Taro的选型指南

微信小程序开发框架怎么选?从原生到uni-app、Taro的选型指南

这几年做小程序,后台代码写腻了,半夜还在帮朋友调包体积的,十个里面八个都在纠结同一件事:框架到底怎么选。我做过原生,用 uni-app 趟过混合开发,也帮人维护过 Taro 的老项目,三种风格都摸过一遍…

2026/10/10 14:46:50 阅读更多 →
【全网最全】Windows 版 Open Claw v2.7.5 纯净版搭建教程:把 settings 改到 TaoToken

【全网最全】Windows 版 Open Claw v2.7.5 纯净版搭建教程:把 settings 改到 TaoToken

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

2026/10/10 14:46:50 阅读更多 →

最新新闻

编译原理课程实验全流程解析:从词法分析到目标代码优化

编译原理课程实验全流程解析:从词法分析到目标代码优化

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

2026/10/10 15:43:22 阅读更多 →
TM4C1294低功耗供电方案:基于PCA9422 PMIC的完整设计

TM4C1294低功耗供电方案:基于PCA9422 PMIC的完整设计

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

2026/10/10 15:43:22 阅读更多 →
Coze API 封装实战:单例模式、流式与轮询双模式解析

Coze API 封装实战:单例模式、流式与轮询双模式解析

简介:这是一份面向JavaScript开发者、尤其是需要为Web应用集成智能对话能力的研发人员所准备的Coze扣子API聊天机器人封装文档,重点解决API调用繁琐、会话状态难以维护、流式与轮询模式切换不便等问题。资源包内含1个docx文件,整体约18KB&…

2026/10/10 15:43:22 阅读更多 →
别让 fsearch 扫全盘:选择性索引三招,索引更快内存更省

别让 fsearch 扫全盘:选择性索引三招,索引更快内存更省

别让 fsearch 扫全盘:选择性索引三招,索引更快内存更省 【免费下载链接】fsearch Whole-disk file search for macOS: fuzzy names, typo tolerance, indexed content grep. ~1 ms over 8M files. 项目地址: https://gitcode.com/gh_mirrors/fsea/fsea…

2026/10/10 15:43:22 阅读更多 →
二叉树递归三板斧:翻转、对称、最小深度一次讲透

二叉树递归三板斧:翻转、对称、最小深度一次讲透

训练营第12天,三道题摆在一块儿的时候,我明显感觉到递归法在二叉树题目里那种“绕不开”的存在感:226.翻转二叉树、101.对称二叉树、111.二叉树的最小深度,题目看起来一个比一个短,但每一道都在逼你想清楚递归的终止条…

2026/10/10 15:43:22 阅读更多 →
基于Python+FaceNet的课堂签到系统:原理、实现与避坑指南

基于Python+FaceNet的课堂签到系统:原理、实现与避坑指南

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

2026/10/10 15:42:20 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

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

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

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

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

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

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 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/10 5:23:50 阅读更多 →
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/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练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/10 10:38:42 阅读更多 →