在移动端功能、促销活动开发中,经常遇到设计师要求按设备屏幕宽度自动缩放界面元素的需求,比如:
这些需求,在移动设备屏幕宽度不定的情况下,还没有一个简单通用的方法,直接指定一个font-size或者高度,来让齐随设备宽度变化。
可能可行的方案1:
在我们直接使用固定viewport大小的情况下,这些需求处理起来比较简单, 比如设置viewport为:
<meta name="viewport" content="width=640,user-scalable=no">
但是这种方法的缺点也很明显,无法做到响应式了,部分情况还会有其他问题(比如边框丢失)。
另外我们很多项目的viewport设置如下:
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
如果改造成固定宽度方式,改造成本很大。
可能可行的方案2:
在 width=device-width
的情况下, css有单位vw/vh可以使用,但是在Android平台的兼容性还不够好,iOS平台从iOS6就已经支持vw,兼容性参考。现在移动平台的兼容性一般要求iOS6及以上,Android 4.0及以上,所以vw还是不能直接用于项目中。
在研究了其它公司的缩放方案时,发现很多都是基于rem来做缩放的,接下来就开始rem方案的细节。
rem(font size of the root element)是指相对于根元素的字体大小的单位。简单的说它就是一个相对单位。看到rem大家一定会想起em单位,em(font size of the element)是指相对于父元素的字体大小的单位。它们之间其实很相似,只不过一个计算的规则是依赖根元素一个是依赖父元素计算。
基本思路,使REM具有类似vw的功能,比如 1rem = 10vw(参考了淘宝的lib-flexible);
function refreshRem(){
var width = docEl.getBoundingClientRect().width;
if (width > 640) {
width = 640;
}
var rem = width / 10; //设定1rem = viewport width/10 = 10vw
docEl.style.fontSize = rem + 'px';
remCalc.rem = rem;
}
在页面head中执行这个函数,设定根节点的font-size 为 viewport width 的十分之一,这样页面中其它元素就可以使用rem来作为一个与页面宽度有关系的单位使用了。
那么问题来了,为什么不让1rem = 100vw 呢,这样的话在支持vw的设备上直接设置 html节点的font-size 为1vw 就可以搞定了,而且在后续vw的兼容性可以接受时直接去掉计算过程的就是。 之前碰到过问题,chrome在font-size 小于12px时还是会按12px计算,导致不准确(320/100 = 3.2了,就会碰到这种情况)。
现在rem与宽度有了关联,假设我们现在知道一张图片的宽高比为 2/1, 而且图片的宽度占据屏幕100%宽,那我们可以直接设定图片高度为5rem(因为宽度为10rem = 100% width),这样图片加载完成显示出来时,不会因为撑开垂直空间而导致页面出现跳动。
其次在需要页面元素与图片缩放配合的情况下,可以使用rem来进行定位及缩放; 比如如下需求: 视觉稿的为2倍大小, 640px宽;倒计时背景图覆盖整个宽度;
运营可配置的背景图为
倒计时需要开发动态添加,而且文案准确定位到图片的位置,文案字体大小要符合缩放要求, 这里我们可以用rem 或者百分比设置left,top来实现文字位置的定位, 文字的大小假设在2倍视觉稿上是32px,32px换算成rem,视觉稿宽度为640,1rem = 640/10 = 64px; 所以可以设置字体大小为 32/64 = 0.5rem; 这样font-size就会随设备宽度自动变化;
demo: http://codepen.io/satlxq/pen/vGxMmG 可能需要缩放预览窗口到小于等于640px
调研了部分比较热门的网站,rem方案的采用率挺高,电商类的活动开发中运用尤多。
站点 | 使用情况 |
---|---|
jumei.com | 活动页面使用 |
mia.com | 活动页使用 |
xiaohongshu.com | 部分页面使用 |
3g.163.com | 全站使用 |
taobao.com | 全站使用 |
jd.com | 未使用 |
tmall.com | 部分地方用到 |
xiaomi.com | 全站使用 |
weibo.com | 未使用 |
qq.com | 未使用 |
对于上面列出的缺点的分析
已经在公用common.ftl的宏中直接引入,每个页面会自动带上这段js,不需要手动引入; 初始化完成后会在window对象上新增属性, 具有三个方法及一个属性
window.remCalc = {
refreshRem: Function, //重新设置rem信息
rem: Number, //当前1rem等于的px值
rem2px: Function, //从rem换算为px
px2rem: Function //从px换算为rem
}
在公用文件_config.mcss 中引入加入
/*视觉稿px转rem计算函数*/
/*rem640对应宽度640px的2倍视觉稿,$px为视觉稿上的实际长度*/
$rem640 = ($px){
@return $px / 64rem;
}
/*rem750对应宽度750px的2倍视觉稿,$px为视觉稿上的实际长度*/
$rem750 = ($px){
@return $px / 75rem;
}
MCSS 文件需要引入:
@abstract '_config.mcss';
此文件中有两个方法,用于将相应视觉稿上的px值转换为rem值
$rem640
对应宽度640px的2倍屏视觉稿
$rem750
对应宽度750px的2倍屏视觉稿
以640px宽视觉稿为例,如果从视觉稿上量到width长度为400px, 可以如下设置css, 则会在编译的时候自动转换为rem值;
.testclass{
width: $rem640(400);
font-size: $rem640(32); //如果需要字体也按rem缩放,则可以直接按视觉稿上的字体大小传入参数,不需要除dpr值;
}
编译后的输出为:
.testclass{
width: 6.25rem;
font-size: 0.5rem; //如果需要字体也按rem缩放,则可以直接按视觉稿上的字体大小传入参数,不需要除dpr值;
}
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者刘新奇授权发布