RTSP转HLS视频流网页播放方案:FFmpeg+Nginx+SSM实战
简介本资源面向Java后端初学者与流媒体实时预览爱好者提供一套基于SSM架构整合Nginx与FFmpeg、将RTSP流转换为HLS流并在前端HTML页面播放的完整可运行方案覆盖视频监控、在线教育、直播等实时预览场景。压缩包共52个文件约70.26MB包含FFmpeg与Nginx安装包、SSM架构Java代码、playerJQueryDemo播放器网页以及png截图、css样式、js脚本、html页面、jsp登录页、nginx.conf配置和hosts文件等便于按模块对照搭建环境。资源内附转流命令、调试源与部署必读说明可帮助读者快速跑通从RTSP拉流、FFmpeg转码到Nginx分发HLS、前端播放的完整链路并理解各组件配置要点与常见排错思路。目前已有262人学习下载适合希望亲手实践流媒体服务搭建的小白参考。1. 从 RTSP 到 HLS一套能跑起来的视频流转码与播放方案监控摄像头、工业相机、无人机图传这些设备吐出来的大多是 RTSP 流。RTSP 本身是给实时传输设计的延迟低但浏览器原生不支持——你没法在video标签里直接塞一个rtsp://地址。想让它出现在网页上中间必须有人做协议转换。这套资源包干的就是这件事用 FFmpeg 把 RTSP 拉过来切成 HLS 分片Nginx 负责把分片和播放列表吐给前端SSM 架构做业务层的流管理和接口暴露最后用一个 jQuery 写的播放页把流播出来。包里带了 FFmpeg 安装包、Nginx 安装包、SSM 架构包和一个 playerJQueryDemo 网页基本是开箱即用的组合。适合谁做安防监控平台、做设备远程查看、做工业视觉上位机的后端和全栈同学。如果你正在被「摄像头画面怎么上网页」这个问题卡住这套东西能帮你把链路先跑通再谈优化。2. 链路拆解FFmpeg 转码、Nginx 分发、SSM 调度各管什么2.1 为什么是 HLS 而不是 RTMP 或 WebRTC浏览器能播的视频流方案就那么几种。RTMP 需要 Flash已经死透了WebRTC 延迟最低但服务端要处理 ICE、STUN、DTLS 一堆信令部署复杂度高而且对多路并发的资源消耗不小HLS 基于 HTTP切片传输浏览器原生支持Safari 直接播Chrome 靠 hls.jsNginx 就能当分发服务器不需要额外流媒体服务。代价是延迟——标准 HLS 切片 10 秒一个延迟通常在 15 到 30 秒。如果你的场景是「看实时画面做精确操作」HLS 不合适如果是「远程查看、录像回放、多路轮巡」HLS 的延迟完全可以接受。这套资源选 HLS走的就是兼容性和部署成本优先的路线。FFmpeg 在这里的角色是转码器。它从 RTSP 源拉流解码后重新编码成 H.264再封装成 MPEG-TS 分片同时生成.m3u8索引文件。Nginx 不需要任何流媒体模块只要把 FFmpeg 输出的目录挂到 HTTP 路径下就是一个 HLS 分发服务。SSM 架构负责的是业务层——管理哪些摄像头要转码、转码进程的启停、流地址的生成和鉴权。三层各司其职耦合度低任何一层出问题都好排查。2.2 FFmpeg 转码命令的参数逻辑先看核心命令。这是整个链路里最关键的一行参数不对后面全白搭ffmpeg -rtsp_transport tcp \ -i rtsp://admin:password192.168.1.100:554/stream1 \ -c:v libx264 \ -preset ultrafast \ -tune zerolatency \ -c:a aac \ -ar 44100 \ -b:a 64k \ -f hls \ -hls_time 4 \ -hls_list_size 6 \ -hls_flags delete_segmentsappend_list \ -hls_segment_filename /usr/local/nginx/html/hls/stream_%03d.ts \ /usr/local/nginx/html/hls/stream.m3u8逐段说。-rtsp_transport tcp强制用 TCP 拉流UDP 在丢包网络下会花屏TCP 稳但延迟略高内网环境建议 TCP。-i后面是 RTSP 地址格式通常是rtsp://用户名:密码IP:端口/路径不同厂商的路径不一样海康是/Streaming/Channels/101大华是/cam/realmonitor?channel1subtype0这个要查设备手册。-c:v libx264指定视频编码器-preset ultrafast是编码速度优先画质会降但 CPU 占用低适合多路并发如果路数少、CPU 富裕可以换成veryfast或faster。-tune zerolatency关掉编码器的帧缓冲降低延迟。音频部分-c:a aac转成 AAC-ar 44100采样率-b:a 64k码率——如果摄像头没有音频这两行可以去掉否则 FFmpeg 会因为找不到音频流报错。HLS 参数是重点。-hls_time 4表示每个 TS 分片 4 秒比默认的 10 秒延迟低但分片多了 HTTP 请求也多。-hls_list_size 6表示 m3u8 里保留 6 个分片配合 4 秒切片就是 24 秒的窗口。-hls_flags delete_segmentsappend_list让 FFmpeg 自动删除旧分片并追加列表不加这个磁盘会被写满。-hls_segment_filename指定分片命名规则%03d是三位序号。最后是 m3u8 的输出路径。注意输出目录必须提前创建FFmpeg 不会自动建目录。另外 Nginx 的 worker 进程用户要对这个目录有写权限否则分片写不进去前端一直转圈。2.3 Nginx 配置让 m3u8 和 ts 能被正确访问Nginx 这边配置不复杂但有两个坑MIME 类型和跨域。默认 Nginx 的 mime.types 里没有 m3u8 和 ts 的映射浏览器拿到application/octet-stream可能不认。在http块或server块里加上types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } server { listen 80; server_name localhost; location /hls/ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET, OPTIONS; add_header Cache-Control no-cache; alias /usr/local/nginx/html/hls/; } }application/vnd.apple.mpegurl是 m3u8 的标准 MIMEvideo/mp2t是 TS 分片的。Access-Control-Allow-Origin *解决跨域——如果你的播放页和 HLS 不在同一个域名或端口下不加这行浏览器会拦。Cache-Control no-cache让浏览器每次都拉最新的 m3u8不然直播流会卡在旧列表上。alias指向 FFmpeg 的输出目录注意 alias 和 root 的区别alias 是替换 location 匹配的部分root 是拼接这里用 alias 更直观。2.4 SSM 层怎么管流转码SSM 架构在这套方案里不是必须的但如果你要做多路摄像头管理它就有价值了。核心思路是用 Java 的ProcessBuilder启动 FFmpeg 进程把进程对象存到一个 Map 里key 是摄像头 IDvalue 是 Process。启动转码的 Service 方法大概长这样public boolean startStream(String cameraId, String rtspUrl) { String outputPath /usr/local/nginx/html/hls/ cameraId .m3u8; String segmentPath /usr/local/nginx/html/hls/ cameraId _%03d.ts; ListString cmd Arrays.asList( ffmpeg, -rtsp_transport, tcp, -i, rtspUrl, -c:v, libx264, -preset, ultrafast, -tune, zerolatency, -f, hls, -hls_time, 4, -hls_list_size, 6, -hls_flags, delete_segmentsappend_list, -hls_segment_filename, segmentPath, outputPath ); try { ProcessBuilder pb new ProcessBuilder(cmd); pb.redirectErrorStream(true); Process process pb.start(); processMap.put(cameraId, process); return true; } catch (IOException e) { log.error(启动转码失败: {}, cameraId, e); return false; } }ProcessBuilder把命令和参数拆成 List避免拼接字符串带来的空格转义问题。redirectErrorStream(true)把 stderr 合并到 stdout方便统一读日志。processMap用ConcurrentHashMap存因为可能有多线程并发调用。停止转码就是process.destroy()但要注意 FFmpeg 收到 SIGTERM 后会先写完当前分片再退出不会立刻死。如果你要强制杀用destroyForcibly()但可能留下不完整的 TS 文件。3. 从零跑通安装、配置、启动的完整步骤3.1 FFmpeg 安装与验证资源包里带了 FFmpeg 安装包Windows 下是解压即用的绿色版Linux 下是编译好的二进制。Windows 把bin目录加到 PATH 环境变量Linux 把二进制拷到/usr/local/bin/并chmod x。验证ffmpeg -version能输出版本号和编译配置就说明装好了。重点看编译配置里有没有--enable-libx264没有的话 H.264 编码用不了只能软编或换编码器。如果缺Linux 下用包管理器装libx264-dev后重新编译或者直接下静态编译版。3.2 Nginx 安装与 HLS 目录准备Nginx 安装包同样分 Windows 和 Linux 版本。Linux 下解压后./configure --prefix/usr/local/nginx然后make make install。Windows 下解压到任意目录双击nginx.exe启动。启动前先把 HLS 输出目录建好mkdir -p /usr/local/nginx/html/hls chmod 755 /usr/local/nginx/html/hls权限给 755确保 Nginx 的 worker 用户能读、FFmpeg 能写。如果你用 root 跑 FFmpegNginx 用 nobody 跑那目录权限要设成 777 或者把两者用户统一。生产环境不建议 777统一用户更安全。3.3 SSM 项目部署与接口联调SSM 架构包是标准的 Maven 项目导入 IDE 后改jdbc.properties里的数据库连接执行schema.sql建表然后mvn tomcat7:run或部署到 Tomcat。核心接口就两个/stream/start?cameraIdxxx启动转码/stream/stop?cameraIdxxx停止。启动后访问http://localhost:8080/stream/start?cameraIdcam01然后去 HLS 目录看有没有生成cam01.m3u8和对应的 ts 文件。有文件生成说明 FFmpeg 转码正常没有的话看 SSM 日志里 FFmpeg 的输出。3.4 前端播放页hls.js 还是原生 videoplayerJQueryDemo 网页用的是 hls.js 方案。Safari 原生支持 HLS直接video srcxxx.m3u8就行Chrome 和 Firefox 需要 hls.js 做 MSE 封装。核心代码var video document.getElementById(video); var videoSrc http://localhost/hls/cam01.m3u8; if (Hls.isSupported()) { var hls new Hls({ liveSyncDurationCount: 3, liveMaxLatencyDurationCount: 10 }); hls.loadSource(videoSrc); hls.attachMedia(video); hls.on(Hls.Events.MANIFEST_PARSED, function() { video.play(); }); } else if (video.canPlayType(application/vnd.apple.mpegurl)) { video.src videoSrc; video.addEventListener(loadedmetadata, function() { video.play(); }); }liveSyncDurationCount: 3表示播放器保持落后直播边缘 3 个分片的距离配合 4 秒切片就是 12 秒延迟。liveMaxLatencyDurationCount: 10是最大延迟容忍超过就跳帧追上去。这两个参数是延迟和流畅度的平衡点调小延迟低但容易卡调大流畅但延迟高。MANIFEST_PARSED事件里调play()是因为浏览器自动播放策略——没有用户交互时play()可能被拦实际部署时加个「点击播放」按钮更稳。4. 避坑排查转码失败、播放卡顿、延迟飙高的常见原因4.1 FFmpeg 启动就退出日志报「Connection refused」现象是 SSM 调启动接口后进程秒退日志里 FFmpeg 输出Connection refused或401 Unauthorized。原因通常是 RTSP 地址不对或鉴权失败。先单独在命令行跑一遍 FFmpeg 命令确认地址能拉流。如果命令行能拉、Java 里不行检查ProcessBuilder的参数有没有被 shell 转义——Java 不走 shell、?这些字符不需要转义但空格分隔的参数必须严格按 List 传。另外有些摄像头限制并发连接数同一路流被拉两次会拒绝确认没有残留的 FFmpeg 进程。4.2 前端一直转圈m3u8 请求 404现象是播放页加载后 video 元素一直缓冲F12 看网络请求 m3u8 返回 404。原因通常是 Nginx 的 alias 路径和 FFmpeg 输出路径不一致。检查 Nginx 配置里location /hls/的 alias 是否指向 FFmpeg 的-hls_segment_filename所在目录。另一个可能是 Nginx 没配 m3u8 的 MIME 类型浏览器拿到application/octet-stream不解析。在nginx.conf的http块里确认 types 配置生效改完nginx -s reload。4.3 播放几秒就卡住ts 分片加载失败现象是画面播几秒后卡死控制台报 ts 文件 404 或 403。404 通常是delete_segments把旧分片删了但 m3u8 还没更新播放器请求了已删除的分片。把-hls_list_size调大比如从 6 调到 10给播放器更多缓冲窗口。403 是权限问题Nginx 的 worker 用户对 ts 文件没有读权限检查目录权限和 SELinuxLinux 下getenforce看是否 Enforcing是的话setenforce 0临时关闭测试。4.4 延迟越来越大画面越播越落后现象是刚开始延迟十几秒播了半小时后延迟涨到几分钟。原因是播放器没有追帧机制或者liveMaxLatencyDurationCount设太大。hls.js 默认会在延迟超过阈值时跳帧但如果 m3u8 的EXT-X-MEDIA-SEQUENCE没更新播放器不知道直播边缘在哪。检查 FFmpeg 的-hls_flags有没有加append_list没有的话每次重写 m3u8 会导致序列号重置。另外-hls_time别设太小2 秒以下分片过多HTTP 开销大反而容易堆积。4.5 多路并发时 CPU 跑满画面掉帧现象是同时转 4 路以上时 CPU 100%所有画面都开始卡顿掉帧。原因是libx264软编本身吃 CPUultrafast已经是最低档了。解决方案有三个一是换硬件编码Intel 核显用h264_qsvNVIDIA 显卡用h264_nvenc把-c:v libx264换成对应编码器CPU 占用能降 70% 以上二是降低分辨率和帧率加-vf scale640:360 -r 15三是用摄像头自带的子码流子码流通常是 640x480 或 704x576码率低转码压力小。5. 进阶技巧用硬件编码和分片预热把延迟压到 5 秒以内标准 HLS 的延迟瓶颈在切片时长和播放器缓冲策略。把-hls_time从 4 秒降到 2 秒liveSyncDurationCount从 3 降到 2理论延迟能到 4 到 6 秒。但切片太小会导致 HTTP 请求数翻倍Nginx 的keepalive要开起来不然每次请求都新建 TCP 连接开销比省下的延迟还大。在 Nginx 的location /hls/里加keepalive_timeout 65; keepalive_requests 1000;硬件编码是另一个关键优化。以 Intel 核显为例把 FFmpeg 命令里的-c:v libx264 -preset ultrafast -tune zerolatency换成-c:v h264_qsv -preset veryfast -look_ahead 0h264_qsv是 Intel Quick Sync Video 的编码器-look_ahead 0关掉前瞻缓冲降延迟。NVIDIA 平台换成-c:v h264_nvenc -preset llhq -tune ll。硬件编码的画质在低码率下不如软编但监控场景对画质要求不高流畅度和 CPU 占用更重要。实测同一台机器软编 4 路 1080p 就满载硬编能跑到 12 路以上。还有一个容易被忽略的点FFmpeg 启动后的前几秒是没有分片可播的播放器会一直等第一个 m3u8 生成。如果摄像头出流慢这个等待可能到 10 秒以上。可以在 SSM 层做个预热——启动转码后轮询 HLS 目录等 m3u8 文件出现且包含至少 2 个分片再返回前端播放地址。这样用户点播放时立刻有画面体验上感知的延迟就低了很多。从那以后我每次部署这套链路都会先在命令行单独跑一遍 FFmpeg 确认拉流正常再配 Nginx最后才动 SSM 的代码。顺序反了的话出了问题根本分不清是转码、分发还是业务层的锅。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

NumPy数组升维全攻略:二维拆三维、三维拆四维与常见坑

NumPy数组升维全攻略:二维拆三维、三维拆四维与常见坑

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

2026/10/14 19:46:54 阅读更多 →
KaihongOS开发实战:从环境搭建到分布式应用部署的完整指南

KaihongOS开发实战:从环境搭建到分布式应用部署的完整指南

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

2026/10/14 19:46:54 阅读更多 →
硬件串口原理与实战:从电平标准到STM32调试全链路

硬件串口原理与实战:从电平标准到STM32调试全链路

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

2026/10/14 19:46:54 阅读更多 →

最新新闻

仓颉社区 IDE Team 双周例会机制与议题决策实践:基于 2026-04-21 例会的治理复盘

仓颉社区 IDE Team 双周例会机制与议题决策实践:基于 2026-04-21 例会的治理复盘

文档开源治理研发协作 【免费下载链接】community 包含Cangjie社区治理、开发者贡献指南、开发者贡献协议、社区交流等内容 项目地址: https://gitcode.com/Cangjie/community 点击查看 免费下载 本文以仓颉(Cangjie)社区 IDE Team 第二次例…

2026/10/14 20:22:41 阅读更多 →
Vortex 代码风格规范(CODESTYLE.md)实战指南:从童子军规则到 TypeScript 工程化落地

Vortex 代码风格规范(CODESTYLE.md)实战指南:从童子军规则到 TypeScript 工程化落地

桌面应用 【免费下载链接】Vortex Vortex Development 项目地址: https://gitcode.com/gh_mirrors/vor/Vortex 点击查看 免费下载 Vortex 是 Nexus Mods 出品的开源游戏模组管理工具,其代码库横跨 Electron 主进程、React 渲染进程、共享工具库与数十个…

2026/10/14 20:22:41 阅读更多 →
进销存ERP源码+小程序二次开发实战:库存扣减、单据流与避坑指南

进销存ERP源码+小程序二次开发实战:库存扣减、单据流与避坑指南

简介:这是一套面向中小企业与开发者的完整进销存ERP管理系统源码,采用VS2012 .NET与MsSQL技术栈,标准版功能简洁实用,已有多家企业稳定运行,适合需要快速搭建电商、销售、采购、生产等业务模块的团队参考或二次开发。压…

2026/10/14 20:22:41 阅读更多 →
C#科学计算器核心:递归下降解析器与表达式求值实践

C#科学计算器核心:递归下降解析器与表达式求值实践

简介:C#科学型计算器完整开发资料,面向正在学习WinForms/WPF桌面编程的高校学生,及需要完成课程设计或巩固C#事件驱动开发的读者。项目覆盖四则运算、对数、正弦余弦、百分比和二进制/八进制/十六进制转换,以“界面控件布局—按钮…

2026/10/14 20:22:41 阅读更多 →
OCLP-Mod 后台守护进程机制全解析:自动根补丁监控、更新预缓存与 KDK 管理

OCLP-Mod 后台守护进程机制全解析:自动根补丁监控、更新预缓存与 KDK 管理

桌面应用CLI系统编程 【免费下载链接】OCLP-Mod A mod version for OCLP,with more interesting features. 项目地址: https://gitcode.com/gh_mirrors/oc/OCLP-Mod 点击查看 免费下载 OCLP-Mod 通过一组常驻后台的 launchd 服务(LaunchAgent / LaunchD…

2026/10/14 20:22:41 阅读更多 →
权威测评!2026年最火AI论文工具榜单,免费款也能高效产初稿

权威测评!2026年最火AI论文工具榜单,免费款也能高效产初稿

一、实测方法论:5 大维度量化评估 本次实测覆盖全学科论文场景,重点考察以下维度,结果客观可复现: 表格 评估维度权重测评标准中文适配度25%是否符合 GB/T7714 引用规范,语言逻辑自然度,术语准确性免费功能…

2026/10/14 20:21:39 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/14 3:29: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/13 22:01:27 阅读更多 →
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/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练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/14 7:53:34 阅读更多 →