修改CSS变量后元素未重渲染,如何正确获取offsetHeight?
以下JavaScript代码:
document.querySelector(":root").style.setProperty("--image-size", "100px"); console.log(document.querySelector("#item").offsetHeight);
对应的样式表:
:root { --image-size: 10px; } #item { width: var(--image-size); }
执行后输出结果为19,但预期应为190。已知这是元素尚未完成重渲染导致的,尝试用嵌套requestAnimationFrame的方式等待重渲染:
document.querySelector(":root").style.setProperty("--image-size", "100px"); requestAnimationFrame(() => { requestAnimationFrame(() => { console.log(document.querySelector("#item").offsetHeight); }); });
但输出仍为19,请问问题出在哪里?如何正确等待元素完成重渲染?
为什么嵌套requestAnimationFrame没用?
两层requestAnimationFrame的逻辑看似能等两次重绘,但实际问题在于:浏览器不会因为修改了CSS变量就立即触发重排/重绘,它会把样式更新攒到渲染周期的批量处理阶段。如果没有触发强制布局的操作,两层rAF的回调可能都在同一个渲染周期内执行,此时元素布局还未更新,自然读不到正确的高度。
另外要确认:你的#item元素高度是否真的和--image-size关联?比如是不是漏写了height: var(--image-size)或者aspect-ratio规则?毕竟你只给了width属性,默认情况下修改宽度不会影响高度(除非元素内容高度和宽度相关),这也可能是拿不到预期值的原因之一。
正确的等待重渲染方法
1. 强制同步布局(简单直接,注意性能)
修改样式后,主动读取一个需要计算布局的属性,浏览器会立刻同步更新布局:
document.querySelector(":root").style.setProperty("--image-size", "100px"); // 强制浏览器计算最新布局 document.querySelector("#item").offsetHeight; console.log(document.querySelector("#item").offsetHeight);
⚠️ 注意:频繁使用这种方式会导致布局抖动,影响页面性能,尽量少用。
2. 结合requestAnimationFrame与计算样式
requestAnimationFrame的回调会在浏览器重绘前执行,此时样式已更新。如果要确保重绘完成后再读取值,再加一层rAF即可:
document.querySelector(":root").style.setProperty("--image-size", "100px"); requestAnimationFrame(() => { const item = document.querySelector("#item"); // 这里已能拿到更新后的计算样式 console.log('更新后的宽度:', getComputedStyle(item).width); // 等待重绘完成后读取高度 requestAnimationFrame(() => { console.log(item.offsetHeight); }); });
3. 使用requestIdleCallback(非紧急场景)
如果不需要立即获取结果,requestIdleCallback会在浏览器空闲时执行,此时布局肯定已更新完毕:
document.querySelector(":root").style.setProperty("--image-size", "100px"); requestIdleCallback(() => { console.log(document.querySelector("#item").offsetHeight); });
关键提醒
一定要确认#item的高度确实依赖--image-size变量,比如是否设置了height: var(--image-size)或者aspect-ratio: 1/1.9这类规则。如果高度与宽度无关,无论怎么等待,结果都不会是190。
内容的提问来源于stack exchange,提问作者Jomy

