移动WEB开发之rem

折口木木

在2016开年的时候我接到了公司开发微信WEB的任务,老板说会请一个大神来担当带头人,然而并没有。我也只有硬着头皮,摸着石头过河了。

在本文开始之前先推荐一本书,来自PPK大神的《移动WEB手册》,由360齐舞团翻译。这本书没有枯燥的理论,也不是教程或者是指南类书籍。完全是PPK自身的经验,文笔轻松诙谐易于理解,特别适合我这种战五渣的小白。

好了,开始本篇博文的主题:rem

其实网上有很多关于rem的相关文章,我大致搜索看了看,很多是将他与em\px等单位做一个对比,然后粗略的讲讲它该怎么使用。然而具体怎么使用,要不是我看SUI的less源码,讲真我现在都是糊涂的。当然本文也会将它与em\px做一个对比,同时也会将它的具体使用方法列举出来。

px我们不陌生,不过在这里我们特指CSS像素(CSS像素与设备像素以后会说明),以下px和em特点引用至其他网站,因为并不是本文讨论的重点,出处未知。

em和px的主要区别:

1.IE无法调整那些使用px作为单位的字体大小;

2.国外的大部分网站能够调整的原因在于其使用了em作为字体单位;

3.Firefox能够调整px和em,但是96%以上的中国网民使用IE浏览器(或内核)。

px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的。

em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。

任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。为了简化font-size的换算,需要在css中的body选择器中声明 Font-size=62.5%,这就使em值变为 16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了。

em有如下特点:

1.em的值并不是固定的;

2.em会继承父级元素的字体大小。

所以我们在写CSS的时候,需要注意几点:

body选择器中声明Font-size=62.5%;

将你的原来的px数值除以10,然后换上em作为单位;

重新计算那些被放大的字体的em数值。避免字体大小的重复声明。

也就是避免1.2 * 1.2= 1.44的现象。比如说你在#content中声明了字体大小为1.2em,那么在声明p的字体大小时就只能是1em,而不是1.2em, 因为此em非彼em,它因继承#content的字体高而变为了1em=12px。

但是12px汉字例外,就是由以上方法得到的12px(1.2em)大小的汉字在IE中并不等于直接用12px定义的字体大小,而是稍大一点。这个问 题 Jorux已经解决,只需在body选择器中把62.5%换成63%就能正常显示了。原因可能是IE处理汉字时,对于浮点的取值精确度有限。不知道有没有 其他的解释。

移动web开发之rem:

我之所以加上移动web开发之rem,是因为在移动WEB或是WebApp的开发上,rem这个单位真的很好用。它是CSS3新增的一个相对单位,这个单位与em有什么区别呢?

区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。目前,除了IE8及更早版本外,所有浏览器均已支持rem。对于不支持它的浏览器,应对方法也很简单,就是多写一个绝对单位的声明。这些浏览器会忽略用rem设定的字体大小。

我们先写一个固定font-size大小的Demo

CSS:

html {
    font-size: 20px;
}

.div1 {
    width: auto;
    height: 2.2rem;
    line-height: 2.2rem;
    background-color: red;
    text-align: center;
} 

HTML+JS:

 <div class="div1"> 改变宽度查看rem的变化 </div> 
var $div = $('.div1');
$(window).resize(function () {
    $div.html('浏览器宽度:' + $(window).width() + 'px' + ' / ' + 'DIV高度:' + $div.height() + 'px');
});

从以上代码可以看出,在html的font-size设置为20px时,内部元素的1rem=20px。

但大家可能发现这么写其实跟px没什么大的区别,更别说应用到移动端了。那我们该怎么写呢?

我们可以使用JS控制HTML中font-size的大小,这样就可以动态的改变。我们该怎么做呢?判断视口或者浏览器宽度?这是OK的,那我们引用这样一段JS代码:

(function (doc, win) {
    var docEl = doc.documentElement, resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function () {
            var clientWidth = docEl.clientWidth;
            if (!clientWidth) return;
            if (clientWidth > 375 && clientWidth <= 478) {
                //当CSS像素大于IP6(375px)小于478px时,根据设备宽度变换rem 
                docEl.style.fontSize = 20 * (clientWidth / 375) + 'px';
            } else if (clientWidth > 478) {
                //当CSS像素大于478px时固定 
                docEl.style.fontSize = '25.4545455px';
            } else {
                //CSS像素小于设备375px时固定 
                docEl.style.fontSize = '20px';
            }
        };
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

不用自己去设置html标签的font-size大小。我们可以查看这段Demo

可以看出这段代码动态的控制了html标签的font-size大小,这正是我们所需要的。

不过既然是CSS3新增的单位,同样的思想,我们也可以使用@media来做视口宽度的判断,动态的设置html标签的font-size大小。

LESS

// // Rem // -------------------------------------------------- 
// Vertical screen 
// 375屏幕为 20px,以此为基础计算出每一种宽度的字体大小 
// 375以下不变,375以上等比放大 
@baseWidth: 375px;
@baseFont: 20px;
html {
    font-size: @baseFont;
    //默认当做320px宽度的屏幕来处理 
}

@bps: 400px, 414px, 480px;
.loop(@i: 1) when (@i <= length(@bps)) {
    
    //注意less数组是从1开始的 
    @bp: extract(@bps, @i);
    @font: @bp/@baseWidth*@baseFont;
    @media only screen and (min-width: @bp) {
        html {
            font-size: @font !important;
        }
    }
    .loop((@i + 1));
}

;
.loop;

编译后的CSS

html {
    font-size: 20px;
}

@media only screen and (min-width: 400px) {
    html {
        font-size: 21.33333333px !important;
    }
}

@media only screen and (min-width: 414px) {
    html {
        font-size: 22.08px !important;
    }
}

@media only screen and (min-width: 480px) {
    html {
        font-size: 25.6px !important;
    }
}

使用后效果是这样的Demo

我个人是比较喜欢使用CSS来控制html标签font-size的大小。可能也有小伙伴发现了一个问题,就是我都是以20px做为基准,为什么不使用其他的大小。这里没有硬性的要求,只要你用着爽,你可以改成你想要的大小。那有的同学就会想,那我就使用1px=1rem,这样不就方便多了。很遗憾这样是不行的。具体原因我忘了,哈哈哈!

最后安利一个另外的方法calc:

html { font-size: calc(100vw/3.75); }

这个我没使用过,但我总觉得calc在移动设备上兼容性不是太好。

//4月6日白天增加//

在写完这篇文章的今天白天,做设计的都是我始终在思考字体大小该怎么处理才好,之前我一直都是借鉴SUI的思路,就是上面使用CSS控制html中font-size大小的那个。

但是在SUI的解决方法中,屏幕小于CSS像素小于375是不进行缩小处理的,这就让我比较尴尬了,毕竟320px/360px的占有很大部分。

我希望是大于414px的固定,小于375px的缩放。

其实我可以自己来写,但是毕竟涉及移动端未深入,不敢乱来。我就想着时不时可以看看手机腾讯网的方案。

HTML:

html{ font-size:1rem; }

这是腾讯网对html标签的设置。嗯,我当时没看懂,但是看到JS代码时理解了。

JS

(function () {
    var baseFontSize = 100;
    var baseWidth = 320;
    var clientWidth = document.documentElement.clientWidth || window.innerWidth;
    var innerWidth = Math.max(Math.min(clientWidth, 480), 320);
    var rem = 100;
    if (innerWidth > 362 && innerWidth <= 375) {
        rem = Math.floor(innerWidth / baseWidth * baseFontSize * 0.9);
    }
    if (innerWidth > 375) {
        rem = Math.floor(innerWidth / baseWidth * baseFontSize * 0.84);
    }
    window.__baseREM = rem;
    document.querySelector('html').style.fontSize = rem + 'px';
}());

个人更喜欢腾讯网这种方案,也会在目前的项目使用使用!