两个门派
根据屏幕宽度设置 rem
计算方式:
rem 根据屏幕宽度计算:屏幕宽度越大,元素的尺寸越大。
可以把网页想象成一张等比缩放的图片,当你屏幕宽度增大,图片被拉宽,同时高度也会等比例增长。
以iPhone6为例,假设1rem = 100px
, 一个宽度 100px 的 div 在 iPhone6 (750px)下就是 1rem,iPhone6plus (828px)下就是 1rem = 110px;
这个门派细分的话还有两个分支,我们分别以网易和手淘为例
不设置viewpoint
参考网易:
iPhone6(2dpr)和iPhone6plus(3dpr)的宽度下,两者1rem分别为50px和55.2px,两者比例为 750 / 828
,dpr没有参与计算;head中的viewport缩放一直是1。
具体来看 rem 的使用
上图中的图片元素的高度设置为1.4rem,可知其在设计稿中的高度为140px,那为什么实际显示为 70px 呢?其实仔细一看,html 元素的 font-size 被设置成了 50px !那为什么html上的font-size是50px呢?我的理解是:因为设计稿是2倍图,实际高度要除以2才行,高度为140px 的元素,其实要写成 .7rem,但每次计算样式都要除以2,太麻烦了,换个思路,如果直接将 rem 除以 2,那么计算尺寸时,只需要除以 100 即可,一劳永逸,提高了开发效率
设置viewport
参考手淘:
- iPhone6 下,1rem = 75px;
- iPhone6plus 下,1rem = 124.2px。 750 (828 / 750) = 82.8px,再根据dpr缩放,82.8px (3/2) = 124.2px。
为什么82.8px还要乘以1.5呢?因为手淘在viewport上面做了处理,页面整体缩小为i6尺寸的2/3,因此需要在单位尺寸上增加等比例的大小。
在写样式的时候,PS上量出的尺寸除以75
。。。
还有坑爹的地方是,字体大小font-size
一般情况下不适合跟随宽度缩放,可能只能写媒体查询。
网易和淘宝两者共同之处
两者都有一个共同的特点:可以把rem当作类似vw来用,因为他们都把宽度等分了。
- 网易:i6下,1rem = 100px ,7.5rem = 750px; 分了7.5份。
- 手淘:i6下,1rem = 75px,10rem = 750px;分了10份;
字体不适合使用rem计算
不同点:
- 网易的方法比较便于计算,淘宝复杂一些。
- 网易的适配在添加第三方插件的时候,相对方便,淘宝因为全局缩放,会影响第三方插件的样式。
- 淘宝的方法可以轻松实现1px border,而网易需要特殊处理。
整合两者?
目的:方便计算 + viewprot缩放
在网易的基础上改进计算方法:
- i6下,1rem等于100px,viewport缩放0.5;
- 6p下,由于宽度变大:100px 1.104 = 110.4px;又有viewpoint缩放:110.4px 1.5 = 165.6px,1rem = 165.6px;
例子:
根据 DPR 设置 rem
计算方式:
dpr越大,手机的屏幕越大,看到的范围越广,尺寸和dpr相关。
一般情况下dpr和 rem 的关系为:
- dpr1 ==> 50px
- dpr2 ==> 100px
- dpr3 ==> 150px
看例子中的代码来理解
dpr = 3时:
总结
var dpr, rem, scale;
var docEl = document.documentElement;
var fontEl = document.createElement('style');
var metaEl = document.querySelector('meta[name="viewport"]');
dpr = window.devicePixelRatio || 1;
//IP6的设计稿,rem=100px,dpr=2,缩放0.5;
rem = 100 * dpr / 2;
//rem = docEl.clientWidth * dpr / 10;
//rem = docEl.clientWidth / 6.4; //相对于640 100px
scale = 1 / dpr;
// 设置viewport,进行缩放,达到高清效果, iphone6为例 物理像素750 css像素375,将视口宽度设置两倍,在缩小
metaEl.setAttribute('content', 'width=' + dpr * docEl.clientWidth + ',initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale + ',user-scalable=no');
// 设置data-dpr属性,留作的css hack之用
docEl.setAttribute('data-dpr', dpr);
// 动态写入样式
docEl.firstElementChild.appendChild(fontEl);
fontEl.innerHTML = 'html{font-size:' + rem + 'px!important;}';
// 给js调用的,某一dpr下rem和px之间的转换函数
window.rem2px = function (v) {
v = parseFloat(v);
return v * rem;
};
window.px2rem = function (v) {
v = parseFloat(v);
return v / rem;
};
window.dpr = dpr;
window.rem = rem;