当我还沉浸在UI样式改版后的喜悦中时,QA同学拿着他的华为Mate X5(折叠屏手机)来找我:"这个字体在展开状态下太大了,影响用户体验"。这才意识到我们的H5页面一直没有在折叠屏设备上进行过充分测试。

1.主流适配方案调研
1.1 PostCSS + Viewport Units (vw) 方案
技术原理:
通过postcss-px-to-vw插件将设计稿中的px单位转换为vw单位,基于视口宽度进行动态缩放;
实现示例:
java
// postcss.config.js
module.exports = {
plugins: {
'postcss-px-to-vw': {
viewportWidth: 375, // 设计稿宽度
viewportUnit: 'vw', // 转换单位
minPixelValue: 1, // 最小转换值
mediaQuery: false // 不转换媒体查询中的px
}
}
}
折叠屏适配实现:
css
/* 基础样式 */
.title {
font-size: 8.5333vw; /* 32/375 * 100 */
}
/* 折叠屏展开状态限制 */
@media (min-width: 540px) and (max-aspect-ratio: 1/1) {
.title {
font-size: clamp(16px, 4vw, 24px); /* 动态限制字体大小 */
}
}
方案优点:
- 原生CSS实现:无需JavaScript依赖,兼容性最佳
- 真正的响应式:基于视口宽度动态缩放,适配效果自然
- 性能优异:无运行时计算开销,渲染性能好
- 维护简单:样式代码直观,易于理解和维护
方案缺点:
- 字体控制复杂:小屏幕下字体可能过小,大屏幕下可能过大,需要额外使用clamp等函数控制
- 历史项目迁移:需要重写所有样式,迁移成本高
1.2 CSS媒体查询方案
技术原理:
通过CSS媒体查询针对不同屏幕尺寸应用差异化样式,是最传统的响应式布局方案。
实现示例:
css
/* 基础布局 */
.product-list {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
/* 折叠屏展开适配 */
@media (min-width: 540px) and (max-aspect-ratio: 1/1) {
.product-list {
grid-template-columns: repeat(4, 1fr);
gap: 2vw;
}
}
方案优点:
- 原生CSS支持:无需任何JavaScript,兼容性最好
- 实现简单直接:通过简单的媒体查询即可实现差异化布局
- 性能最优:无任何运行时开销,渲染效率最高
- 控制精准:可以针对特定屏幕尺寸做精确控制
方案缺点:
- 代码冗余度高:需要编写大量媒体查询规则,代码维护成本高
- 适配粒度粗:只能基于断点做整体布局调整,无法实现精细化的动态缩放
- 维护困难:随着断点增多,CSS代码变得复杂难以维护
- 响应式体验差:布局切换不够平滑,用户体验不如动态缩放方案
1.3 flexible.js + postcss-px-to-rem现有适配方案
技术原理:通过flexible.js + postcss-px-to-rem插件将设计稿中的px单位转换为rem单位,基于视口宽度进行动态计算;
方案优势
1、高效开发流程
- 自动单位转换 :直接按设计稿写px ,通过postcss-px-to-rem自动转换为rem。
css
/* 输入(设计稿 750px) */
.box { width: 200px; }
/* 输出(rootValue: 75) */
.box { width: 2.6667rem; } /* 200/75 ≈ 2.6667 */
- 设计稿1:1映射 :UI设计稿统一宽度是750px ,那么在postcss-px-to-rem设置rootValue: 75即可直观转换。
2、动态响应能力
- 实时调整布局 :flexible.js内部会监听resize 事件,浏览器窗口大小变化时会自动重新计算根字体大小。
javascript
// 计算根字体大小
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
// 监听resize事件
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
3、灵活覆盖与调试
- 可选择性禁用转换 :通过selectorBlackList排除指定元素。
javascript
// postcss 配置
selectorBlackList: ['.no-rem'], // 不转换 .no-rem 类下的样式
- 可手动覆盖REM值 :必要时可直接写rem单位,优先级会高于插件转换。
4、性能优化
- 构建时完成单位转换:postcss-px-to-rem在代码编译阶段处理,最终生成的CSS文件中已经是rem单位,无运行时计算开销。
- 相比纯JavaScript方案更高效 :比实时计算vw 或动态rem的方案(如某些CSS-in-JS库)性能更好。
1.4 各方案对比分析
对比维度 | flexible.js+postcss-px-to-rem | postcss-px-to-vw | CSS媒体查询 |
---|---|---|---|
性能表现 | 有JS运行时开销 | 无运行时开销✅ | 无运行时开销 ✅ |
折叠屏适配 | 一处适配,无需大范围代码改动✅ | 自动适配,但字体难控 | 需要手动适配 |
历史项目迁移 | 无需迁移,直接优化✅ | 需要重写所有样式 | 需要大量重构 |
字体控制精度 | 精确控制,符合设计✅ | 需要额外限制方案 | 精确控制 |
基于以上多维度综合考量,团队最终选择优化现有方案(flexible.js+postcss-px-to-rem)作为最优解;
2. 具体实施与优化
现有方案限制了最大计算宽度540*dpr,导致折叠屏展开时字体过大,信息展示效率低。

这是一个商品详情页,折叠屏展开后首屏区域只有三个商品照片、商品标题、商品价格这三部分信息,而且字体放大,用户浏览效率低!
所以要解决的第一个问题,就是在flexible.js现有的540宽度基础上新增折叠屏的判断逻辑,目标是希望折叠屏展开后 ,字体和折叠起来的屏幕字体保持一致 ,可视区域内能展示更多的内容。
2.1 新增折叠屏展开状态判断,解决屏幕展示效率低的问题
那如何判断折叠屏是展开状态呢?经过查询市面上目前的折叠屏屏幕参数:
📱 横向展开式折叠屏屏幕参数(2024主流机型)
品牌/型号 | 显示宽度(px) | 显示高度(px) | 宽高比(宽/高) |
---|---|---|---|
三星 Galaxy Z Fold5 | 804 | 967 | 0.83 |
华为 Mate X3 | 740 | 832 | 0.89 |
OPPO Find N3 | 896 | 960 | 0.93 |
小米 Mix Fold 3 | 957 | 1080 | 0.89 |
荣耀 Magic V2 | 719 | 780 | 0.92 |
vivo X Fold2 | 958 | 1080 | 0.89 |
📌 从上述数据中得出一些折叠屏的关键特征:
- 宽高比 :集中在0.8~1.0之间(接近方形)
所以,在现有flexible.js的refreshRem 函数内增加宽高比的判断逻辑,当宽高比在0.8~1.0之间,就认为是折叠屏展开状态。
目的是展开状态后,字体大小和折叠状态下保持一致(非放大),首先需要了解折叠状态时,手机的屏幕宽度数据。
2.3 限制展开状态下计算尺寸
📱 折叠屏展开/折叠状态屏幕宽度(CSS像素)
品牌/型号 | 展开状态宽度(px) | 折叠状态宽度(px) |
---|---|---|
三星 Galaxy Z Fold5 | 804 | 316 |
华为 Mate X3 | 740 | 360 |
OPPO Find N3 | 896 | 430 |
小米 Mix Fold 3 | 957 | 417 |
荣耀 Magic V2 | 719 | 301 |
vivo X Fold2 | 958 | 441 |
从数据得出折叠态宽度范围:300-450px (CSS像素),为了兼顾这个范围内的屏幕都能有比较好的体验,且简化计算逻辑,所以取中间值370作为基准,避免为每个机型单独适配。
代码实现逻辑如下:
javascript
// 计算根字体大小
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width / dpr > 540) {
width = 540 * dpr;
}
// 折叠屏展开判断
var screenWidth = win.screen.width;
var screenHeight = win.screen.height;
if (screenWidth / screenHeight >= 0.8 && screenWidth / screenHeight < 1) {
width = 370;
}
var rem = width / 10;
docEl.style.fontSize = rem + 'px';
flexible.rem = win.rem = rem;
}
// 监听resize事件
win.addEventListener('resize', function() {
clearTimeout(tid);
tid = setTimeout(refreshRem, 300);
}, false);
增加完这个逻辑后,就能在展开后,可视区域内的字体不放大,用户可预览更多的内容。


效果:可视区域内可浏览模块更多。
由于一些历史代码开发规范问题,会有模块内容宽度固定写死的问题存在,针对这类问题,整理成以下几类解决方案。
3. 其他场景优化方案
3.1 商品列表布局
商品列表可使用媒体查询实现展开后一行2列 布局,展示更多商品,提高商品曝光量(这些实现可和设计同学进行讨论,不同的场景可采用不同的布局方案)。
示例代码:
css
/* 默认1列布局 */
.product-list {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
}
/* 当宽度≥540px时切换为2列(覆盖折叠屏展开态) */
/* 早期折叠屏(如Galaxy Fold)展开后浏览器视口约为540px,所以采用540进行处理 */
@media (min-width: 540px) {
.product-list {
grid-template-columns: repeat(2, 1fr);
}
}

3.2 图片内容高度处理
固定图片内容
可设置图片宽度、高度不固定,根据图片实际宽高比进行缩放:
css
.product-card img {
width: 100%;
aspect-ratio: 1/1; /* 明确设置宽高比 */
object-fit: cover;
}
非固定图片内容
如需求内需要针对不同的屏幕尺寸,展示不同的图片内容时,可使用以下两种方式进行实现:
方案1:HTML的<picture>
标签
html
<picture>
<!-- 折叠屏展开时加载 wide.jpg -->
<source media="(min-width: 540px) and (max-aspect-ratio: 1/1)" srcset="wide.jpg">
<!-- 默认加载 square.jpg -->
<img src="square.jpg" alt="商品" class="product-img">
</picture>
方案2:JS动态替换(根据屏幕状态)
javascript
function updateProductImages() {
const ratio = window.innerWidth / window.innerHeight;
// 是否折叠屏展开判断
const isFoldableExpanded = ratio >= 0.8 && ratio < 1;
document.querySelectorAll('.product-img').forEach(img => {
img.src = isFoldableExpanded ? 'wide.jpg' : 'square.jpg';
});
}
window.addEventListener('resize', updateProductImages);
个人更推荐优先使用CSS控制(不换图)。可减少HTTP请求,降低代码复杂度和特殊处理。
多行多列布局
可使用与商品列表处理的方式一样,一行2列变一行4列。

5. 总结与展望
5.1 技术方案总结
核心解决思路 通过分析现有flexible.js+postcss-px-to-rem方案的优势,我们采用了渐进式优化 而非推倒重来的策略。在保持团队开发习惯和项目稳定性的前提下,通过增加折叠屏检测逻辑,实现了对新型设备的适配。
关键技术要点
- 折叠屏状态检测:基于宽高比(0.8~1.0)判断展开状态
- 动态字体控制:展开状态下限制计算宽度为370px,保持字体一致性
- 响应式布局优化:通过媒体查询实现多列布局,提升信息密度
- 图片内容适配:支持不同屏幕状态下的图片展示策略
适配效果数据
- 信息展示效率:折叠屏展开后可视内容增加约40%
- 用户体验提升:字体大小保持一致,避免阅读疲劳
- 开发维护成本:在现有方案基础上优化,迁移成本几乎为零
5.2 结语
H5页面在折叠屏上的适配需要综合考虑现有技术方案、业务需求和团队基建。通过优化现有的flexible.js+postcss-px-to-rem方案,成功兼容了折叠屏,提升了用户体验。
同时,我们也看到了其他方案的优势,为未来的技术优化和基建升级提供了方向。
转转研发中心及业界小伙伴们的技术学习交流平台,定期分享一线的实战经验及业界前沿的技术话题。 关注公众号「转转技术」(综合性)、「大转转FE」(专注于FE)、「转转QA」(专注于QA),更多干货实践,欢迎交流分享~