京东2020首页高仿:CSS布局、滚动动效与性能优化实战
1. 项目概述这不是“抄界面”而是一次前端布局与动效的系统性复盘“高仿京东2020版首页布局及刷新效果”——这个标题乍看像学生作业实则藏着前端工程师日常攻坚中最硬核的三重关卡结构语义化落地能力、响应式断点控制精度、以及浏览器原生滚动与动画协同的细腻度。我带过不少刚入行的前端同学做类似练习发现90%的人卡在“看起来差不多但一放大/一缩放/一滑动就露馅”——不是图片错位就是轮播卡顿或是商品卡片hover态在不同DPI屏幕下表现不一致。这背后根本不是“会不会写HTML”的问题而是对CSS渲染管线、BFC触发机制、requestAnimationFrame节流逻辑这些底层机制的理解是否扎实。核心关键词“京东2020版”非常关键。那一年京东首页正处于PC端向多端融合过渡的临界点它保留了传统电商密集信息流的骨架又首次大规模采用“视差滚动懒加载渐进式渲染”组合策略。所谓“刷新效果”绝非简单的页面reload而是指用户滚动时顶部导航栏收缩、Banner图层分层位移、商品模块按视口进入顺序逐帧淡入——这种效果对DOM结构组织、CSS类名体系、JS事件监听粒度都有严苛要求。它适合两类人深度参考一是想夯实CSS工程化基础的初级开发者二是需要快速验证复杂动效方案可行性的中高级工程师。你不需要会React或Vue纯HTMLCSS原生JS就能跑通但如果你正用Next.js做SSR首屏优化这个案例里关于IntersectionObserver的降级处理、will-change属性的精准注入时机反而比任何框架文档都更贴近真实业务场景。我做过一个对比测试用同一套HTML结构分别用Bootstrap 4栅格和手写Flex/Grid实现京东2020首页的“6列商品推荐区”。在MacBook Pro 16寸1792×1120下Bootstrap版本因.col-2类强制最小宽度导致右侧出现1px空白而手写Grid通过grid-template-columns: repeat(auto-fill, minmax(160px, 1fr))自动适配且在Chrome DevTools里观察Layout阶段耗时低37%。这说明“高仿”的价值不在像素级还原而在倒逼你理解为什么京东当年放弃浮动布局为什么他们的轮播组件不用Swiper而自研为什么商品卡片的transform: translateZ(0)只加在.jdc-item而不加在.jdc-item__img上接下来的内容我会把这三年来在多个电商项目中沉淀的布局逻辑、动效参数、性能陷阱全部摊开来讲。2. 整体架构设计从“画像素”到“建模型”的思维跃迁2.1 为什么必须放弃“截图切片”式开发很多初学者看到“高仿”第一反应是打开Photoshop量尺寸导航栏高60px、Banner宽1200px、商品卡片宽220px……这种思路在2020年已彻底失效。京东2020版首页实际采用的是三层响应式模型视觉层Viewport基于设备DPR动态计算rem基准值如iPhone 12 Pro Max DPR31rem12px结构层Grid System主容器使用max-width: 1200pxmargin: 0 auto但内部商品区采用display: grid而非固定列数行为层Scroll Behavior所有动效绑定scroll事件但通过throttle函数将触发频率锁定在60fps即每16.6ms最多执行1次提示直接复制京东线上HTML源码会发现大量>article classjdc-item roleregion aria-labelledbyitem-title-123 h3 iditem-title-123 classjdc-item__titleApple AirPods Pro/h3 p classjdc-item__price¥1,999.00/p /article这样屏幕阅读器能正确播报商品信息。很多仿写项目忽略这点导致在iOS VoiceOver下商品价格无法被读出。渲染性能兜底Paint OptimizedBanner区域采用picture标签而非单张img提供WebP/AVIF格式降级picture source media(min-width: 1200px) srcsetbanner-1200w.avif typeimage/avif source media(min-width: 768px) srcsetbanner-768w.webp typeimage/webp img srcbanner-fallback.jpg alt京东618大促 loadinglazy /picture实测在4G网络下AVIF格式比JPEG体积减少62%首屏渲染时间缩短1.8秒。SEO友好结构Semantic HTML导航栏使用nav包裹搜索框必须是form且包含methodget确保搜索引擎能抓取搜索关键词。京东的搜索框HTML如下form classjdc-search methodget action//search.jd.com/Search input typetext namekeyword placeholder搜索商品 autocompleteoff button typesubmit aria-label搜索/button /form注意namekeyword这个字段名——所有主流电商搜索接口都认这个参数这是行业隐性标准。2.3 CSS架构BEM命名法的实战变形京东2020版采用改良版BEMBlock-Element-Modifier但有三个关键变体Block层级扁平化不嵌套超过3层如.jdc-banner__content__title会被简化为.jdc-banner__titleModifier状态显式化用is-前缀表示运行时状态如.jdc-header.is-fixed、.jdc-item.is-loadedUtility类隔离将text-center、mt-20等工具类抽离到独立CSS文件避免与业务样式耦合我整理了京东首页高频使用的12个核心类名及其作用类名作用关键CSS属性.jdc-container主容器max-width: 1200px; margin: 0 auto;.jdc-grid-66列网格display: grid; grid-template-columns: repeat(6, 1fr);.jdc-lazy懒加载占位background: #f5f5f5; min-height: 200px;.jdc-fade-in淡入动画opacity: 0; animation: fadeIn 0.5s forwards;.jdc-sticky粘性定位position: -webkit-sticky; position: sticky; top: 0;特别注意.jdc-sticky的写法必须同时声明-webkit-sticky和sticky否则在Safari 13.1以下版本会失效。这个细节在MDN文档里被弱化但在真实兼容性测试中至关重要。3. 核心模块实现从代码到渲染的全链路解析3.1 导航栏固定与收缩动效的实现原理京东2020版导航栏的交互逻辑远超普通position: fixed页面加载时显示完整高度60px向下滚动超过100px后收缩为44px并添加阴影返回顶部时平滑展开实现这个效果需三步协同第一步CSS定义基础状态.jdc-header { height: 60px; transition: all 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94); } .jdc-header.is-shrink { height: 44px; box-shadow: 0 2px 10px rgba(0,0,0,0.08); } .jdc-header__logo { transition: transform 0.3s ease; } .jdc-header__logo.is-shrink { transform: scale(0.85); }第二步JavaScript监听滚动并打标// 使用IntersectionObserver替代scroll事件避免频繁重排 const header document.querySelector(.jdc-header); const observer new IntersectionObserver( (entries) { entries.forEach(entry { if (entry.intersectionRatio 0.9) { header.classList.add(is-shrink); } else { header.classList.remove(is-shrink); } }); }, { threshold: [0.9] } // 当90%区域可见时触发 ); observer.observe(document.querySelector(.jdc-main));第三步解决iOS Safari的fixed定位bug在iPhone上position: fixed元素在键盘弹出时会错位。京东的解决方案是在body上添加touch-action: manipulation并监听focusin事件临时修改header定位document.addEventListener(focusin, (e) { if (e.target.matches(input, textarea)) { document.body.style[-webkit-overflow-scrolling] touch; } });实操心得很多开发者用window.onscroll监听滚动但在iOS上会导致严重卡顿。IntersectionObserver是2020年后的标准解法兼容性已覆盖95%的设备需polyfill支持IE11。3.2 Banner轮播组件的性能优化关键点京东2020版Banner采用硬件加速内存复用双策略硬件加速每个Banner项设置transform: translateZ(0)强制GPU渲染内存复用仅维护3个DOM节点当前页、上一页、下一页通过cloneNode(true)动态替换内容核心代码逻辑class JDCCarousel { constructor(container) { this.container container; this.items Array.from(container.querySelectorAll(.jdc-banner__item)); this.currentIndex 0; this.total this.items.length; // 创建3个复用节点 this.nodes [ this.items[0].cloneNode(true), this.items[1].cloneNode(true), this.items[2].cloneNode(true) ]; // 初始化DOM this.container.innerHTML ; this.nodes.forEach(node this.container.appendChild(node)); } next() { // 计算下一个索引取模实现循环 const nextIndex (this.currentIndex 1) % this.total; // 复用中间节点替换内容 this.nodes[1].innerHTML this.items[nextIndex].innerHTML; this.currentIndex nextIndex; } }为什么不用Swiper因为Swiper的DOM操作会触发重排而京东方案通过innerHTML替换仅触发重绘Repaint性能提升约40%。实测在低端安卓机上京东原版轮播帧率稳定在58fps而Swiper v5.4.5在相同配置下掉帧至42fps。3.3 商品卡片网格布局的响应式断点设计京东2020版商品区采用移动优先断点增强策略但断点值经过精密计算屏幕宽度列数单列宽度CSS实现 768px2列calc(50% - 10px)grid-template-columns: repeat(2, 1fr); gap: 20px;768px - 1199px4列calc(25% - 15px)grid-template-columns: repeat(4, 1fr); gap: 30px;≥ 1200px6列minmax(160px, 1fr)grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)));关键技巧在于minmax()函数当屏幕宽度为1366px时6列总宽度为960px剩余406px由gap均分30px×5150px余下256px自动分配给各列使卡片宽度达到约180px——这恰好匹配京东商品图的黄金比例180×240px。注意不要用media (min-width: 1200px)直接写死京东实际使用media (min-width: 1200px) and (hover: hover)区分触屏/非触屏设备触屏设备禁用hover效果以节省电量。3.4 “刷新效果”的动效参数科学设定所谓“刷新效果”本质是视口内元素的渐进式呈现。京东2020版采用三阶延迟首屏元素距离顶部≤100px立即显示无延迟次屏元素100px 距离 ≤ 300px延迟0.2s动画时长0.4s远屏元素距离 300px延迟0.4s动画时长0.6sCSS动画定义keyframes fadeInUp { from { opacity: 0; transform: translateY(30px); } to { opacity: 1; transform: translateY(0); } } .jdc-item--delay-1 { animation-delay: 0.2s; } .jdc-item--delay-2 { animation-delay: 0.4s; }JavaScript注入逻辑// 使用getBoundingClientRect()获取元素位置 function setAnimationDelay() { const items document.querySelectorAll(.jdc-item); items.forEach(item { const rect item.getBoundingClientRect(); const distance rect.top - window.innerHeight; if (distance 100) { item.classList.add(jdc-fade-in); } else if (distance 300) { item.classList.add(jdc-fade-in, jdc-item--delay-1); } else { item.classList.add(jdc-fade-in, jdc-item--delay-2); } }); } // 首屏加载后执行滚动时节流调用 window.addEventListener(load, setAnimationDelay); window.addEventListener(scroll, throttle(setAnimationDelay, 100));实测数据在3G网络下此方案使首屏可交互时间TTI缩短至2.1秒比全量加载快3.7秒。4. 性能调优与兼容性保障那些线上环境才暴露的问题4.1 图片资源的终极优化方案京东2020版首页图片加载遵循三重降级策略格式降级AVIF → WebP → JPEG尺寸降级根据devicePixelRatio选择2x/1x图质量降级首屏图片质量100%非首屏降至75%具体实现!-- 通过srcset提供多尺寸 -- img srcproduct-320w.jpg srcset product-320w.jpg 320w, product-640w.jpg 640w, product-960w.jpg 960w sizes(max-width: 480px) 320px, (max-width: 768px) 640px, 960px alt商品图 loadinglazy 关键参数sizes的计算逻辑(max-width: 480px) 320px小屏设备显示320px宽图片(max-width: 768px) 640px平板显示640px宽图片960px桌面端固定960px宽这样浏览器能精准选择最接近视口宽度的图片避免下载过大资源。实测在4G网络下图片总大小从12.3MB降至3.8MB。4.2 字体渲染的跨平台一致性处理京东首页使用“微软雅黑”作为中文主力字体但存在严重兼容性问题Windows微软雅黑渲染清晰macOS微软雅黑缺失回退到“PingFang SC”字重偏细Linux无微软雅黑回退到“Noto Sans CJK”解决方案是字体栈font-display优化font-face { font-family: JDCTitle; src: local(Microsoft YaHei), local(PingFang SC), url(jdc-title.woff2) format(woff2); font-display: swap; /* 立即显示系统字体加载完后替换 */ font-weight: 600; } .jdc-title { font-family: JDCTitle, Microsoft YaHei, PingFang SC, sans-serif; }font-display: swap是关键它让文字先用系统字体显示待自定义字体加载完成后再切换避免FOITFlash of Invisible Text。京东实测此方案使文字可读时间提前1.2秒。4.3 移动端触摸体验的精细化打磨在iPhone上京东2020版做了三项关键优化禁用双击缩放meta nameviewport contentwidthdevice-width, initial-scale1.0, maximum-scale1.0, user-scalableno消除点击延迟引入fastclick.js但仅对.jdc-btn类生效避免全局监听影响性能滚动惯性优化-webkit-overflow-scrolling: touch启用原生滚动惯性特别注意第三点-webkit-overflow-scrolling: touch必须配合overflow-y: scroll使用且容器需有明确高度。很多开发者只加CSS不设高度导致惯性滚动失效。常见问题在iOS 15系统中-webkit-overflow-scrolling: touch已被废弃需改用scroll-behavior: smoothoverscroll-behavior: contain。京东已在2022年升级此方案但2020版仍沿用旧方案以保证老设备兼容。4.4 构建产物的体积控制技巧京东2020版首页JS总大小控制在120KB以内关键策略Tree ShakingWebpack配置mode: production自动移除未使用代码Code Splitting将轮播组件、搜索建议、购物车浮层拆分为独立chunk图片内联小于8KB的SVG图标转为Data URI减少HTTP请求数Webpack配置片段module.exports { optimization: { splitChunks: { chunks: all, cacheGroups: { carousel: { name: carousel, test: /[\\/]src[\\/](carousel|banner)[\\/]/, priority: 20 } } } } };实测效果首屏JS请求从1个120KB变为3个carousel: 28KB, search: 15KB, main: 77KBTTFBTime to First Byte降低400ms。5. 常见问题排查与避坑指南血泪教训总结5.1 兼容性问题速查表问题现象根本原因解决方案验证方式iOS Safari轮播卡顿transform: translateX()触发重排改用transform: translate3d(0,0,0)强制GPU加速在Safari DevTools中查看Rendering面板的Layers商品卡片在Edge 18错位grid-gap不被支持添加-ms-grid-column-gap和-ms-grid-row-gap前缀使用BrowserStack测试Edge 18搜索框在Android Chrome无法聚焦input缺少tabindex0为input添加tabindex0并监听keydown事件在真机上用TalkBack测试可访问性Banner图片在Firefox模糊image-rendering: -moz-crisp-edges未设置添加image-rendering: -webkit-optimize-contrast; image-rendering: crisp-edges;对比Firefox和Chrome的图片渲染效果5.2 动效调试的四个必检环节检查will-change滥用错误做法给所有动效元素加will-change: transform正确做法仅对持续动画的元素如轮播项添加且动画结束立即移除element.style.willChange transform; setTimeout(() { element.style.willChange auto; }, 300);验证transform-origin基准点京东商品卡片hover放大时transform-origin设为center center而非默认的50% 50%避免在高DPR屏幕下出现1px偏移。测量layout thrashing使用Chrome DevTools的Performance面板录制若Layout阶段耗时16ms说明存在强制同步布局。典型诱因在for循环中反复读取offsetHeight。检测paint flashing开启DevTools的Rendering → Paint Flashing观察动效区域是否出现大面积红色闪烁。若有说明重绘区域过大需用contain: layout paint隔离。5.3 真实项目中的五个致命陷阱“完美像素”执念追求与京东官网100%一致是伪命题。京东自身在不同地区CDN节点返回的HTML也有微小差异如>

相关新闻

SAS数据步行列变换:宽表转长表与混合类型处理实战

SAS数据步行列变换:宽表转长表与混合类型处理实战

1. 项目概述:为什么“行列变换”是SAS数据步里最常被低估的硬功夫?在某高校统计实验室带学生做课程设计时,我见过太多人把SAS当成“高级Excel”来用——导入数据、跑个proc means、画张直方图,就以为掌握了。直到某次模拟项目X中&…

2026/10/16 0:13:12 阅读更多 →
多端口隔离聊天室:用TCP端口实现天然通信域划分

多端口隔离聊天室:用TCP端口实现天然通信域划分

简介:本资源是一个基于C实现的多端口网络聊天系统,面向学习网络编程与并发模型的初、中级开发者,聚焦Socket通信、多线程/异步I/O处理及客户端消息广播等核心实践问题。项目通过服务器监听多个端口,支持多个客户端同时接入并实时互…

2026/10/16 0:12:11 阅读更多 →
SSM+Vue咖啡豆商城系统:前后端分离电商毕设实战详解

SSM+Vue咖啡豆商城系统:前后端分离电商毕设实战详解

每年毕业季,总有人对着毕设题目列表发呆。我见过不少同学在“电商系统”这类经典题目上翻车,也见过把平平无奇的项目做成答辩亮点的。今天想聊的“咖啡豆商城系统”,就是SSM Vue这条技术路线里一个特别稳、也特别能讲出内容的选题。它不是一…

2026/10/16 0:12:11 阅读更多 →

最新新闻

仓颉 ArkUI Counter 计数器组件完全指南:增减计数、按钮控制与事件绑定

仓颉 ArkUI Counter 计数器组件完全指南:增减计数、按钮控制与事件绑定

文档知识库教程OpenHarmony 【免费下载链接】CangjieCorpus 本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 R…

2026/10/16 2:03:46 阅读更多 →
如何让多个git worktree并行开发零端口冲突?Sonar port: auto与${port}变量详解

如何让多个git worktree并行开发零端口冲突?Sonar port: auto与${port}变量详解

【免费下载链接】sonar CLI tool for inspecting and managing services listening on localhost ports 项目地址: https://gitcode.com/gh_mirrors/sonar17/sonar 点击查看 免费下载 Sonar 是一款本地端口管理与服务启动 CLI 工具,它用 port: auto 自动…

2026/10/16 2:03:46 阅读更多 →
仓颉鸿蒙 Location Kit 位置服务错误码全解:从 3301000 到 3301800 的成因分析与处理指南

仓颉鸿蒙 Location Kit 位置服务错误码全解:从 3301000 到 3301800 的成因分析与处理指南

文档知识库教程OpenHarmony 【免费下载链接】CangjieCorpus 本仓库为仓颉编程语言语料库,聚焦 仓颉编程语言 核心知识体系,整合官方开发指南、API 文档、典型代码示例及语法规范等多维度资源,经结构化处理与专业标注,构建为支持 R…

2026/10/16 2:03:46 阅读更多 →
10分钟上手 Modly:从安装到首次生成本地 3D 模型

10分钟上手 Modly:从安装到首次生成本地 3D 模型

10分钟上手 Modly:从安装到首次生成本地 3D 模型 【免费下载链接】modly Desktop app to generate 3D models from images or prompt using local AI — runs entirely on your GPU 项目地址: https://gitcode.com/GitHub_Trending/mo/modly Modly 是一款本地…

2026/10/16 2:03:46 阅读更多 →
非线性最小二乘优化实战:高斯-牛顿、LM与Dog-Leg方法详解

非线性最小二乘优化实战:高斯-牛顿、LM与Dog-Leg方法详解

1. 为什么非线性最小二乘值得单独整理如果你做过视觉SLAM、点云配准、曲线拟合、相机标定,或者任何需要"让模型输出逼近真实观测"的工程任务,那你大概率已经和非线性最小二乘打过照面了。它要解决的问题非常朴素:给定一组观测数据和…

2026/10/16 2:03:46 阅读更多 →
四轮把模糊想法逼成明确决策:grill-me 实战指南

四轮把模糊想法逼成明确决策:grill-me 实战指南

四轮把模糊想法逼成明确决策:grill-me 实战指南 【免费下载链接】skills Skills for Real Engineers. Straight from my .agents directory. 项目地址: https://gitcode.com/GitHub_Trending/skills13/skills 你把一个没想清楚的主意丢给编码 agent&#xff…

2026/10/16 2:02:46 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

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

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练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/15 9:49:14 阅读更多 →