1. 为什么“量个尺寸”这件事值得单独拎出来讲前端开发干久了你会发现真正让人抓狂的往往不是那些花哨的框架和算法而是“我明明想拿一个元素的宽度结果拿到的数字跟肉眼看到的完全对不上”。这个问题的根源在于浏览器里同时存在好几套坐标系和尺寸体系它们各自服务于不同的目的混用就会出错。offsetWidth、clientWidth、getBoundingClientRect()、window.innerWidth、document.documentElement.clientWidth、visualViewport.width——这些名字看起来都跟“宽”有关但它们在复杂环境下给出的答案可能相差几十甚至上百像素。所谓“复杂环境”我指的是这几种典型场景页面存在滚动条、元素被 CSS 变换transform缩放或旋转过、设备像素比不是 1 的高清屏、移动端浏览器地址栏会动态收起展开、页面嵌在 iframe 里、以及浏览器缩放级别被用户调整过。这些条件任意叠加两个就足以让一套在简单页面上跑得好好的尺寸计算逻辑彻底失效。我自己就踩过这样的坑一个居中弹窗的定位逻辑在桌面端测试完美上了移动端之后偏了半个屏幕排查半天才发现是visualViewport和innerHeight在地址栏收起时产生了差异。这篇内容适合谁看如果你写过拖拽、缩放、懒加载、虚拟滚动、自定义滚动条、画布编辑器、图表自适应这类功能那你一定绕不开元素尺寸的精确测量。哪怕你只是想让一个 tooltip 精准地贴在按钮旁边也需要搞清楚getBoundingClientRect和offsetLeft的区别。我会从几套尺寸体系的本质讲起把每个 API 背后的盒模型含义、坐标系基准、受哪些因素影响都拆开说清楚然后给出可以直接抄用的测量方案和排查表。全程按我实际做项目时的思路走不讲空话只讲能落地的。2. 先把几套尺寸体系的地基打牢2.1 盒模型决定了每个 width 到底在量什么聊尺寸之前必须先把盒模型摆正因为所有尺寸 API 的差异本质上都是“量的是盒模型的哪一层”。一个元素从内到外依次是 content内容区、padding内边距、border边框、margin外边距。width这个 CSS 属性在默认的box-sizing: content-box下只代表内容区宽度而一旦你设了box-sizing: border-box它就变成了 content padding border 的总和。这个差别直接传导到了 JS 的测量 API 上。offsetWidth量的是 border-box 的宽度也就是 content padding border但不含 margin而且它返回的是取整后的整数。clientWidth量的是 content padding不含 border 和 margin同样取整。getBoundingClientRect().width返回的是精确的浮点数量的是 border-box但它会受到 transform 的影响——这一点极其关键后面会专门展开。至于scrollWidth它量的是内容实际占用的宽度包括溢出不可见的部分用来判断是否发生了横向溢出。我习惯用一个类比来记把元素想象成一个带相框的画。clientWidth是画心加内衬content paddingoffsetWidth是连相框边框一起算再加 bordergetBoundingClientRect是这幅画挂在墙上之后你从外面看到的实际占位含 transform 缩放而scrollWidth是画心里面那张纸如果比画框还大、被裁掉的那部分也算进去的总宽度。搞清楚这个层次后面所有 API 的选择就有了依据。2.2 视口的三层结构布局视口、视觉视口、理想视口移动端尺寸混乱的罪魁祸首是视口被拆成了好几层。布局视口layout viewport是 CSS 布局所依据的那个坐标系document.documentElement.clientWidth拿到的就是它。视觉视口visual viewport是用户当前实际能看到的那块区域会随着双指缩放和地址栏收展而变化对应window.visualViewport对象。理想视口ideal viewport则是通过meta nameviewport声明出来的那个逻辑宽度决定了布局视口的基准。在桌面端这三者基本重合所以很多人感知不到差异。但一到移动端用户双指放大页面时布局视口不变、视觉视口缩小此时window.innerWidth和visualViewport.width就会分道扬镳。如果你的弹窗定位用的是innerWidth做居中计算用户一缩放就会偏。我在一个移动端图片查看器项目里就吃过这个亏后来统一改成监听visualViewport的resize和scroll事件来重算位置才彻底稳住。2.3 设备像素比与浏览器缩放如何污染测量结果window.devicePixelRatio简称 DPR表示一个 CSS 像素对应多少个物理像素。高清屏上 DPR 可能是 2 或 3这意味着你写的1px边框在物理层面占了 2 到 3 个像素。这个值本身不影响 CSS 尺寸的测量但它会影响 canvas 绘制、图片清晰度以及getBoundingClientRect返回值的精度感知。比如你在 DPR 为 2 的屏幕上量到一个元素宽 100.5px这个 0.5 是真实存在的 CSS 像素小数不是误差。更麻烦的是浏览器缩放。用户按 Ctrl 加号放大页面时devicePixelRatio会跟着变比如从 1 变成 1.25、1.5而getBoundingClientRect返回的仍然是 CSS 像素值不受缩放影响。但如果你用offsetWidth这种取整 API在缩放比例非整数时取整误差会被放大。我实测过一个案例在 125% 缩放下一个实际 33.6px 宽的元素offsetWidth返回 34而getBoundingClientRect().width返回 33.59375两者差了 0.4px。单看不大但在做像素级对齐的拖拽吸附时这个误差会累积成肉眼可见的偏移。3. 核心 API 逐个拆解与选型逻辑3.1 offset 家族快但粗糙适合粗判不适合精算offsetWidth、offsetHeight、offsetTop、offsetLeft这一组的特点是返回整数、相对offsetParent定位、包含 border。它们的优势是性能好、读取快适合做“是否溢出”“大概在什么位置”这类粗判断。但有两个坑必须记住。第一个坑是offsetParent的判定规则很微妙。它不一定是父元素而是最近的“定位祖先”position 不为 static或者 table、body 等特殊元素。如果中间某层祖先设了position: relativeoffsetTop的基准就变了。我曾经写过一个拖拽组件元素外面套了一层position: relative的容器做动画结果offsetTop突然从相对页面变成了相对容器拖拽位置整体偏移。后来改用getBoundingClientRect配合滚动偏移才解决。第二个坑是取整。offsetWidth会对getBoundingClientRect().width做四舍五入不同浏览器实现略有差异有的是 round 有的是 floor。在需要亚像素精度的场景下这个取整就是灾难。所以我的选型原则很简单只要涉及精确布局计算一律用getBoundingClientRectoffset家族只用来做布尔判断或性能敏感的大批量粗筛。3.2 client 家族与 scroll 家族的分工clientWidth/clientHeight的典型用途是判断元素内部可用空间因为它不含 border 和滚动条。注意在标准模式下如果元素有垂直滚动条clientWidth是不含滚动条宽度的而offsetWidth是含的。这个差值恰好就是滚动条宽度很多人用它来动态计算滚动条尺寸虽然现在有scrollbar-gutter等新特性但这个技巧在老项目里依然常见。scrollWidth/scrollHeight用来检测内容溢出判断条件是scrollWidth clientWidth。但这里有个经典陷阱在元素设置了overflow: hidden且内容被 transform 放大时scrollWidth不一定能反映 transform 后的实际尺寸因为 transform 不改变布局尺寸。这时候必须用getBoundingClientRect去量子元素的实际占位。我在做一个可缩放画布时判断画布内容是否超出容器一开始用scrollWidth缩放后就失灵了最后改成遍历子元素的getBoundingClientRect求并集才准确。3.3 getBoundingClientRect精确测量的主力但要懂它的坐标系getBoundingClientRect()返回一个DOMRect包含x、y、width、height、top、right、bottom、left。它的坐标系基准是视口左上角也就是说top是元素上边缘到视口顶部的距离会随页面滚动而变化。这一点和offsetTop相对定位祖先完全不同务必分清。它的返回值是浮点数精度高而且会反映 transform 之后的实际渲染尺寸。一个元素如果被scale(0.5)缩放getBoundingClientRect().width返回的是缩放后的一半宽度而offsetWidth返回的仍是原始布局宽度。这个特性在做缩放编辑器时是救命的但也是陷阱——如果你想要的是布局尺寸而非渲染尺寸就得手动除以缩放比例还原。还有一个细节getBoundingClientRect在元素处于display: none时返回全 0在元素被visibility: hidden时仍返回真实尺寸。这个差异可以用来做“隐藏但可测量”的技巧需要测量一个暂时不可见的元素尺寸时用visibility: hidden加绝对定位移出视口而不是display: none。3.4 视口尺寸的多个来源与优先级拿视口尺寸有好几个入口我整理成一张表方便对照API含义是否含滚动条受缩放影响典型用途window.innerWidth视口宽度含滚动条含否快速取视口宽document.documentElement.clientWidth布局视口宽度不含否布局计算首选window.outerWidth浏览器窗口外框宽度含否少用含浏览器 UIvisualViewport.width视觉视口宽度不含是移动端缩放定位screen.width屏幕物理宽度CSS 像素无关否屏幕信息非视口选型逻辑做布局计算用documentElement.clientWidth因为它不含滚动条、语义明确做移动端缩放相关定位用visualViewportinnerWidth只在需要含滚动条的粗略场景用。outerWidth和screen.width基本不参与布局别拿它们算元素位置。4. 复杂环境下的实操方案与参数推演4.1 滚动条宽度到底占多少一次实测推演滚动条宽度不是一个固定值它取决于操作系统、浏览器主题和用户设置。在 Windows 默认主题下常见是 17pxmacOS 覆盖式滚动条则是 0不占布局空间。要动态获取最稳的办法是用两个 div 做差function getScrollbarWidth() { const outer document.createElement(div); outer.style.cssText position:absolute;top:-9999px;width:100px;height:100px;overflow:scroll;; document.body.appendChild(outer); const inner document.createElement(div); inner.style.width 100%; outer.appendChild(inner); const width outer.offsetWidth - inner.offsetWidth; document.body.removeChild(outer); return width; }推演一下外层 100px 宽且强制出现滚动条内层撑满 100% 但被滚动条挤占所以outer.offsetWidth是 100inner.offsetWidth是 100 减去滚动条宽度两者相减就是滚动条宽度。这个值在 macOS 上通常返回 0在 Windows 上返回 15 到 17 不等。拿到它之后计算“可用内容宽度”时就要从视口宽度里减掉否则在 Windows 上会多算十几像素导致横向溢出。注意这个函数每次调用都会创建并销毁 DOM不要在滚动或 resize 回调里高频调用应该在初始化时算一次缓存起来。另外在 iframe 内部调用时量到的是 iframe 所在环境的滚动条宽度不一定和顶层一致。4.2 元素相对页面绝对坐标的精确计算getBoundingClientRect给的是相对视口的坐标要转成相对文档的绝对坐标需要加上滚动偏移function getAbsoluteRect(el) { const rect el.getBoundingClientRect(); const scrollX window.pageXOffset || document.documentElement.scrollLeft; const scrollY window.pageYOffset || document.documentElement.scrollTop; return { top: rect.top scrollY, left: rect.left scrollX, width: rect.width, height: rect.height, bottom: rect.bottom scrollY, right: rect.right scrollX }; }这里为什么用pageXOffset而不是scrollX两者在现代浏览器里等价但pageXOffset兼容性更老更稳我习惯用它。为什么不用document.body.scrollTop因为在标准模式下滚动发生在documentElement上body.scrollTop常常是 0这是个经典坑。判断标准模式看document.compatMode CSS1Compat但现代页面基本都是标准模式直接用documentElement即可。如果元素在 iframe 里还要逐层累加父级 iframe 的偏移这个逻辑复杂且容易出错我的建议是尽量避免跨 iframe 做坐标计算改用postMessage传递相对坐标由各层自己换算。4.3 transform 缩放下的尺寸还原与命中检测元素被scale缩放后getBoundingClientRect返回的是缩放后的渲染尺寸。如果你需要原始布局尺寸得除以缩放系数。但缩放系数怎么拿如果缩放是已知的比如你自己设的scale(0.8)直接除即可。如果是继承来的或不确定的可以用getBoundingClientRect().width除以offsetWidth反推近似比例但offsetWidth取整会带来误差更精确的做法是读取计算样式里的 transform 矩阵function getScale(el) { const st window.getComputedStyle(el); const tr st.transform; if (!tr || tr none) return 1; const m tr.match(/matrix\(([^)])\)/); if (m) { const parts m[1].split(,).map(Number); return Math.sqrt(parts[0] * parts[0] parts[1] * parts[1]); } return 1; }matrix(a, b, c, d, e, f)里a和b分别是 x 轴基向量的两个分量缩放系数就是它们的模长。这个算法对旋转也成立因为旋转不改变模长。拿到缩放系数后原始宽度等于rect.width / scale。做命中检测时则相反要把鼠标坐标转换到元素的局部坐标系里再判断否则缩放后点击区域会错位。我在一个可缩放流程图项目里就是靠这套换算把连线端点的吸附做准的。4.4 移动端地址栏收展引发的视口抖动处理移动端浏览器地址栏收起时window.innerHeight会突然变大触发resize事件导致依赖视口高度的布局比如全屏弹窗、底部固定栏跳动。visualViewport的resize事件能更精细地反映这个变化而且它区分了“布局视口变化”和“视觉视口变化”。处理思路是用visualViewport.height而不是innerHeight来设置全屏元素高度并监听visualViewport的resize和scroll事件做防抖更新。if (window.visualViewport) { const vv window.visualViewport; const sync () { document.documentElement.style.setProperty(--vh, vv.height * 0.01 px); }; vv.addEventListener(resize, sync); vv.addEventListener(scroll, sync); sync(); }然后在 CSS 里用calc(var(--vh) * 100)代替100vh。这个方案比单纯监听resize稳得多因为地址栏收展过程中visualViewport会连续触发能跟上动画节奏。实测在主流移动浏览器上这个做法能把全屏元素的抖动控制在 1px 以内。5. 常见问题排查与避坑速查5.1 尺寸对不上的排查顺序遇到“量出来的尺寸和预期不符”我有一套固定的排查顺序按这个走基本能定位到根因先确认盒模型目标元素是不是border-box有没有 padding 和 border 被算进去了用getComputedStyle看boxSizing、padding、borderWidth。再确认 transform祖先链上有没有scale、rotate、translate有的话getBoundingClientRect的值是变换后的需要还原。检查滚动条clientWidth和offsetWidth的差值是不是滚动条宽度容器是不是overflow: scroll强制出了滚动条检查缩放级别devicePixelRatio是不是非整数浏览器缩放是不是 125% 之类取整 API 在这种环境下误差明显。检查 iframe元素是不是在 iframe 里坐标系基准是不是顶层视口检查 display 状态元素是不是display: none那样所有尺寸都是 0。5.2 高频问题速查表现象可能原因解决方向getBoundingClientRect全为 0元素display: none或未挂载改用visibility: hidden测量宽度比预期大十几像素滚动条被算入offsetWidth用clientWidth或减去滚动条宽缩放后点击位置偏移坐标未转换到局部坐标系用逆矩阵换算鼠标坐标移动端全屏高度跳动地址栏收展改变innerHeight改用visualViewport.heightoffsetTop突然变化祖先新增了定位元素改用getBoundingClientRect加滚动偏移亚像素对齐出现缝隙offsetWidth取整误差改用getBoundingClientRect浮点值iframe 内坐标错位坐标系基准是 iframe 视口逐层累加偏移或改用消息传递5.3 几条用血换来的实操心得第一条测量和布局要分离。不要在同一个渲染帧里反复“读尺寸、改样式、再读尺寸”这会触发强制同步布局layout thrashing性能急剧下降。正确做法是先批量读、再批量写。我习惯用requestAnimationFrame把读操作集中到帧开始写操作放到后面。第二条缓存静态尺寸。视口尺寸、滚动条宽度这类不常变的值在初始化时算一次存起来只在resize时更新别在滚动回调里反复读clientWidth。第三条优先用 ResizeObserver 而不是 resize 事件。监听单个元素尺寸变化ResizeObserver比全局resize精准得多而且能捕获内容变化导致的尺寸改变。注意它的回调里读尺寸是安全的不会造成循环。第四条浮点数比较要留容差。getBoundingClientRect返回的是浮点判断“是否相等”时用Math.abs(a - b) 0.5这种容差比较别用否则在缩放环境下永远不相等。第五条在 iframe 里量视口要小心。iframe 内部的window.innerWidth是 iframe 自己的视口不是父页面的。如果要做跨层布局明确每一层用的是哪个坐标系别混着算。6. 一套可直接复用的尺寸测量工具封装把上面这些零散的知识点收拢成一个工具模块是我每次开新项目都会做的事。下面这个封装覆盖了最常用的几个场景你可以直接拿去改const SizeUtil { // 视口尺寸不含滚动条布局计算首选 viewport() { const de document.documentElement; return { width: de.clientWidth, height: de.clientHeight }; }, // 视觉视口移动端缩放场景 visualViewport() { const vv window.visualViewport; if (!vv) return this.viewport(); return { width: vv.width, height: vv.height, scale: vv.scale, offsetTop: vv.offsetTop }; }, // 元素精确尺寸含 transform 还原 rect(el, { restoreScale false } {}) { const r el.getBoundingClientRect(); let scale 1; if (restoreScale) { const st getComputedStyle(el); const m st.transform.match(/matrix\(([^)])\)/); if (m) { const p m[1].split(,).map(Number); scale Math.sqrt(p[0] * p[0] p[1] * p[1]) || 1; } } return { width: r.width / scale, height: r.height / scale, top: r.top, left: r.left, raw: r }; }, // 元素相对文档的绝对坐标 absolute(el) { const r el.getBoundingClientRect(); const sx window.pageXOffset || document.documentElement.scrollLeft; const sy window.pageYOffset || document.documentElement.scrollTop; return { top: r.top sy, left: r.left sx, width: r.width, height: r.height }; }, // 滚动条宽度缓存 _sbw: null, scrollbarWidth() { if (this._sbw ! null) return this._sbw; const o document.createElement(div); o.style.cssText position:absolute;top:-9999px;width:100px;height:100px;overflow:scroll;; document.body.appendChild(o); const i document.createElement(div); i.style.width 100%; o.appendChild(i); this._sbw o.offsetWidth - i.offsetWidth; document.body.removeChild(o); return this._sbw; } };用的时候注意几点rect的restoreScale选项默认关闭因为大多数场景你要的就是渲染尺寸只有做布局还原时才需要开。scrollbarWidth做了缓存但如果你在页面生命周期中动态改变了滚动条样式比如切换主题记得手动把_sbw置空重算。absolute方法在 iframe 内部调用时返回的是相对 iframe 文档的坐标跨层使用要自己加偏移。这套封装我在好几个项目里用过从桌面端管理后台到移动端 H5 都跑得通。真正让它稳的不是代码本身而是背后那套“先分清坐标系、再选对 API、最后处理缩放和滚动条”的思路。尺寸测量这件事没有银弹只有把每个 API 的边界条件摸清楚才能在复杂环境里不翻车。我个人的习惯是每接一个新项目先花十分钟把视口、滚动条、DPR 这几个基础值打印出来看一眼心里有底了再动手写布局逻辑能省掉后面大量的调试时间。
企业数字化 ERP 产品动态
相关推荐
LCD12864点阵屏驱动详解:UC1601显存组织与时序排查 简介:信利TRULY TSE1G0193液晶屏规格书面向嵌入式硬件工程师、LCD驱动开发人员及工业控制产品选型者,解决12864点阵单色模块在选型、接口设计与可靠性评估中的参数核对问题。文档给出FSTN正显半透、6点钟视角、外形78.0050.802.78mm、可视区72.0040.80mm… · 2026/11/3 15:10:33
Zotero文献管理工具:从安装到论文写作全指南 1. 为什么你需要Zotero? 作为一名长期与文献打交道的科研狗,我深知文献管理的痛苦。还记得读研时,我的电脑桌面上堆满了各种PDF文件,文件名都是"重要文献1"、"必看论文2"这种毫无意义的标签。直到遇见了Zoter… · 2026/11/3 15:10:33
Paperclip:AI工程中的胶水层设计与实践 1. “Paperclip”不是回形针:一个被严重误读的AI工程代号 最近在多个技术社区和开发者群聊里,频繁看到有人问:“Paperclip 是什么?是不是某个新出的 AI 框架?”“Paperclip 和 OpenClaw、Claude 有什么关系?… · 2026/11/3 15:10:33
具身智能落地核心:ROS2与URDF物理映射实战 1. 这门课到底在教什么?不是“具身智能”四个字堆砌出来的幻觉“具身智能”这个词最近两年火得有点烫手,从学术会议到招聘JD,再到地方政府产业规划文件里,几乎无处不在。但翻遍市面上打着这个旗号的课程,90%以上只是把… · 2026/11/3 16:00:05
从加法器到五级流水线:FPGA CPU设计与体系结构实验 简介:这份《CPU设计与体系结构实验指导手册(教师版)》面向高校计算机专业教师及高年级学生,围绕龙芯教学实验平台LS-CPU-EXB-002,服务于《数字逻辑》《计算机组成原理》《计算机体系结构》等课程实验教学与指导。内容从… · 2026/11/3 16:00:05
具身智能导航实战:连续环境与语义理解的端到端落地 1. 这不是“教机器人走路”,而是让机器真正理解空间——具身智能导航到底在解决什么问题?“具身智能导航”这六个字,最近半年在机器人、自动驾驶、服务型硬件团队的周会上出现频率,已经超过了“模型微调”和“数据清洗”。但很多人… · 2026/11/3 16:00:05
动态规划算法精讲:从背包问题到状态压缩技巧 1. 动态规划基础概念回顾 动态规划(Dynamic Programming)作为算法设计中的经典方法论,在解决最优化问题时展现出独特优势。其核心思想是将复杂问题分解为相互重叠的子问题,通过记忆化存储子问题的解来避免重复计算。这种方法特别适… · 2026/11/3 16:00:05
@RequestMapping与@Path注解本质区别及Spring路由原理 1. 项目概述:从一个被反复问爆的注解说起你有没有在翻看某段 Spring Boot 接口代码时,突然卡住——明明只写了Path,接口却死活不生效?或者更常见的是:RequestMapping和GetMapping到底谁管路径、谁管方法、谁又在底层悄… · 2026/11/3 16:00:05
Android 2048小游戏源码拆解:自定义View、手势与合并算法 简介:这份资源是面向计算机相关专业本科生、尤其是准备撰写毕业设计的同学的一份完整学位论文文档,选题为基于 Android 平台的 2048 小游戏设计与实现,适合处于选题开题、结构搭建、内容填充与答辩准备阶段的读者参考,也可作为软件… · 2026/11/3 15:59:03
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46