移动端自适应不修改css源码使用js修改所有css单位px到rem

移动端自适应不修改css源码使用js修改所有css单位px到rem

💡 原文中文,约2100字,阅读约需5分钟。
📝

内容提要

文章介绍一种无需修改CSS源码、用JavaScript将px转换为rem的方法:遍历document.styleSheets,修改CSSStyleRule的style.cssText,把px替换为rem;同时动态设置根字号,并监听resize和pageshow事件重新计算,转换前先隐藏根元素以避免闪烁。

🔎

延伸解读

转换范围需手动控制

代码通过检查link标签上的px2rem属性来决定是否转换该样式表,避免影响所有样式。若想全部转换,需注释掉判断逻辑。这种设计让开发者能选择性处理特定CSS文件,但需提前在HTML中标记,否则默认不转换。

根字号动态计算与事件监听

根字号设置为视口宽度的十分之一,即1rem等于屏幕宽度的10%。resize事件在窗口尺寸变化时重新计算,pageshow事件则处理从缓存恢复页面的情况,确保rem基准值始终与当前视口匹配。

隐藏根元素避免布局闪烁

转换前将根元素display设为none,待DOMContentLoaded后完成所有样式替换再恢复显示。这防止了页面先以px渲染再突变为rem导致的布局跳动,但会短暂空白,需权衡体验。

仅处理普通样式规则

循环中通过item.type != 1跳过非CSSStyleRule的规则,如@keyframes或@media内的规则。因此动画关键帧或媒体查询中的px不会被转换,需额外处理或注意兼容性。

❓

Q&A

如何在不修改CSS源码的情况下把px单位批量转换成rem?

可以通过JavaScript遍历document.styleSheets,修改每个CSSStyleRule的style.cssText,用正则将px值替换为rem值。同时动态设置根字号,并监听resize和pageshow事件重新计算。转换前先隐藏根元素以避免页面闪烁。

用JS转换px到rem时,如何避免页面布局闪烁?

在转换开始前将根元素(document.documentElement)的display设为'none',等所有CSS规则转换完成后再设为'initial',这样页面不会在转换过程中被渲染,从而避免布局突然变化造成的闪烁。

动态设置根字号(1rem等于多少px)的代码逻辑是什么?

通过setRemUnit函数,将根元素的fontSize设置为docEl.clientWidth / 10 + 'px',即1rem等于视口宽度的十分之一。初始化时调用一次,并在window的resize事件和pageshow事件(当e.persisted为true时)中重新调用,以适应尺寸变化和页面缓存恢复。

如何只转换特定link标签引入的CSS,而不影响其他样式?

在需要转换的link标签上添加自定义属性,例如px2rem="true",然后在遍历document.styleSheets时,检查sheet.ownerNode.getAttribute('px2rem')是否为null,如果为null则跳过该样式表。这样只处理标记过的样式表。

转换时px到rem的换算比例是如何确定的?

代码中定义了defWidth = 414 / 10,即设计稿宽度414px对应10rem,所以换算比例为1rem = 41.4px。替换时用px值除以defWidth得到rem值,并保留最多5位小数(通过toFixed(5)处理有小数的情况)。

为什么要在DOMContentLoaded事件中执行CSS替换?

因为需要等待styleSheets初始化完成,确保能获取到所有CSS规则。在DOMContentLoaded触发时,样式表通常已加载完毕,此时遍历并修改cssText才能生效。同时配合根元素隐藏,避免在样式未就绪时渲染页面。

🏷️

标签

➡️

继续阅读