关于rem的一些小体会

860 阅读3分钟

关于rem布局详细可以看看大漠这篇

关于像素的概念可以看看这篇

以下是自己rem布局中的一些体会

由于历史原因在pc端的视口默认为980px,注意这里是css像素,也叫逻辑像素,也等于设备独立像素,在移动端下,屏幕物理像素(也叫设备像素)的分辨率提高了,那么pc端显示在移动端下时,1物理像素就可以显示更多的css像素,那么pc端的页面等于被缩小了,为了解决这个不对称,在meta标签加上一个width=device-width,就可以让css像素等于屏幕物理像素。

即使这样,在移动端还是有些问题,假如在750设计稿下盒子的border=1px,那么在iphone6,7,8下,border永远不会等于1,在iphone6,7,8下border会变为2px,在对应的plus下border会变为3px,使用手淘的适配方案,在iphone的二倍屏三倍屏下,

meta的显示如下:

二倍屏<meta content="inital-scale=0.5">
三倍屏<meta content="inital-scale=0.3333">

原理其实就是让rem变大2倍或3倍,在通过meta把页面缩小为0.5倍或0.3333倍,虽然可以解决1px的问题,但会造成其它问题,例如你的页面中有嵌入iframe的第三方课件或者广告,别人不一定按照你的布局方式,那么有可能第三方页面会被你缩小,我觉得适配还是要写成

<meta content="inital-scale=1">

在二倍三倍屏下对border=1px的处理可以通过css3的scale属性处理,当然scale会缩放这个元素,最好把'border=1px'转为伪元素,通过scale缩放伪元素,scale缩小为0.5倍或0.3333倍取决于二倍屏还是三倍屏,通过下面函数给html节点增加对应的 选择器来判断

function retina () { // 二倍三倍分辨率屏幕处理
    var docEl = document.documentElement;//获取html节点
    docEl.className='';//清空选择器
    var class_arr = [];//存放选择器名字
    var pixel_ratio = window.devicePixelRatio || 1;//判断几倍屏
    class_arr.push('pixel-ratio-' + Math.floor(pixel_ratio));//把几倍屏的选择器存放数组里
    if (pixel_ratio >= 2) {//二倍三倍屏幕多存放选择器retina
        class_arr.push('retina');
    }
    class_arr.forEach(function (className) {//循环选择器到html节点
         docEl.classList.add(className);
    });
}

如果是一条边框可以通过以下方式(css简略写,理解就会了)

.pixel-ratio-2 .box{
    position: relative;
}
.pixel-ratio-2 .box::before{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    border-bottom: 1px solid red;
    transform: scale(0.5);
}
pixel-ratio-3 .box{
    position: relative;
}
.pixel-ratio-3 .box::before{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    border-bottom: 1px solid red;
    transform: scale(0.333333);
}

如果是四条边框可以通过以下方式,边框和宽高通过放大原来的几倍,在缩小几倍

.pixel-ratio-2 .box{
    position: relative;
}
.pixel-ratio-2 .box::before{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    width: 200%;
    height: 200%;
    border: 2px solid red;
    transform: scale(0.5);
    transform-origin: 0 0;
}
.pixel-ratio-3 .box{
    position: relative;
}
.pixel-ratio-3 .box::before{
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    width: 300%;
    height: 300%;
    border: 3px solid red;
    transform: scale(0.333333);
    transform-origin: 0 0;
}

关于rem布局参考网上并结合自己的理解修改,如下

;(function(designWidth, maxWidth) {
    var doc = document,
    win = window,
    docEl = doc.documentElement,
    tid;
    
    function refreshRem() {
    	var width = docEl.getBoundingClientRect().width;
    	maxWidth = maxWidth || 540;
    	width>maxWidth && (width=maxWidth);
    	var rem = width * 100 / designWidth;
    	docEl.style.fontSize =rem + 'px';
    	retina();
    }
    //要等 viewport 设置好后才能执行 refreshRem,不然 refreshRem 会执行2次;
    refreshRem();
    
    win.addEventListener("resize", function() {
    	clearTimeout(tid); //防止执行两次
    	tid = setTimeout(refreshRem, 300);
    }, false);
    
    win.addEventListener("pageshow", function(e) {
    	if (e.persisted) { // 浏览器后退的时候重新计算
    		clearTimeout(tid);
    		tid = setTimeout(refreshRem, 300);
    	}
    }, false);
    function retina () { // 二倍三倍分辨率屏幕处理
    	docEl.className='';//清空选择器
        var class_arr = [];//存放选择器名字
        var pixel_ratio = window.devicePixelRatio || 1;//判断几倍屏
        class_arr.push('pixel-ratio-' + Math.floor(pixel_ratio));//把几倍屏的选择器存放数组里
        if (pixel_ratio >= 2) {//二倍三倍屏幕多存放选择器retina
            class_arr.push('retina');
        }
        class_arr.forEach(function (className) {//循环选择器到html节点
            docEl.classList.add(className);
        });
    }
    
    if (doc.readyState === "complete") {
    	doc.body.style.fontSize = "16px";
    } else {
    	doc.addEventListener("DOMContentLoaded", function(e) {
    		doc.body.style.fontSize = "16px";
    	}, false);
    }
})(750, 750);

关于1px的处理有很多种方式,淘宝京东网易苏宁都采用了不同的方式,但每种都有其局限性的一面,了解其实现原理并且结合业务场景,找到适合自己的为佳!