CSS3 - mobile app 适配方案小结

在我们做手机网页开发的时候,我们在关注文字大小、容器尺寸和间距、图片大小、背景图大小等时,往往需要要适配各个尺寸,各个机型。没有严格统一的解决方案,本文就各个场景如何优雅的实现适配分析分析。

简单页面

简单页面,一般直接宽度铺满整个屏幕,高度固定。在大尺寸屏幕上会有留白。meta 规定如下:

1
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">

这样宽度指定为设备的宽度,缩放比例为1:1,不能缩放。

稍复杂页面

稍复杂页面可以使用 flex 布局来定制宽度。

media query

再复杂一些的响应式页面,需要利用css3的media query属性来进行适配,大致思路是根据屏幕不同大小,来设置对应的css样式。

rem 解决方案

rem 简介

rem是(font size of the root element),意思是根据根元素(<html>)字号大小来设置子元素的大小, E9+,Firefox、Chrome、Safari、Opera ,如果我们不修改相关的字体配置,都是默认显示font-size是16px即:

1
2
3
html {
font-size:16px;
}

那么如果我们想给一个P标签设置12px的字体大小那么用rem来写就是:

1
2
3
p {
font-size: 0.75rem; //12÷16=0.75(rem)
}

基本上使用rem这个单位来设置字体大小基本上是这个套路,好处是假如用户自己修改了浏览器的默认字体大小,那么使用rem时就可以根据用户的调整的大小来显示了。 但是rem不仅可以适用于字体,同样可以用于width height margin这些样式的单位。

先看一个简单的例子,进行 rem 适配:

1
2
3
4
5
6
7
.box {
width: 10rem;
height: 10rem;
background-color: red;
}
<div class="box">
</div>

效果如下:

img1

这是一个div,宽度和高度都用rem来设置了,在浏览器里面是这样显示的, 可以看到,在浏览器里面width和height分别是160px,正好是16px * 10,那么如果将html根元素的默认font-size修改一下呢?

1
2
3
4
5
6
7
8
9
10
11
html {
font-size: 17px;
}

.box {
width: 10rem;
height: 10rem;
background-color: red;
}
<div class="box">
</div>

再来看看结果:

img2

这时width和height都是170px,这就说明了将rem应用与width和height时,同样适用rem的特性,根据根元素的font-size值来改变自身的值,由此我们应该可以联想到我们可以给html设定不同的值,从而达到我们css样式中的适配效果。

利用 sass 进行 rem 数值计算

首先定义计算函数

1
2
3
4
@function px2rem($px){
$rem : 37.5px;
@return ($px/$rem) + rem;
}

当我们具体使用时

1
2
3
4
.box {
width: px2rem(100px);
height: px2rem(100px);
}

设定 rem 基准

可以利用 media query 来设置,既:

1
2
3
4
5
@media (min-device-width : 375px) and (max-device-width : 667px) and (-webkit-min-device-pixel-ratio : 2) {
html {
font-size: 37.5px;
}
}

利用javascript来动态设置 根据我们之前算出的基准值,我们可以利用js动态算出当前屏幕所适配的 font-size 即:

1
document.getElementsByTagName('html')[0].style.fontSize = window.innerWidth / 10 + 'px';

这样就可以使不同尺寸的屏幕 html 使用不同的 font-size

动态设定 meta

我们知道,一般我们获取到的视觉稿大部分是iphone6的,所以我们看到的尺寸一般是双倍大小的,在使用rem之前,我们一般会自觉的将标注/2,其实这也并无道理,但是当我们配合rem使用时,完全可以按照视觉稿上的尺寸来设置。

  • 设计给的稿子双倍的原因是iphone6这种屏幕属于高清屏,也即是设备像素比(device pixel ratio)dpr比较大,所以显示的像素较为清晰。
  • 一般手机的dpr是1,iphone4,iphone5这种高清屏是2,iphone6s plus这种高清屏是3,可以通过js的window.devicePixelRatio获取到当前设备的dpr,所以iphone6给的视觉稿大小是(*2)750×1334了。
  • 拿到了dpr之后,我们就可以在viewport meta头里,取消让浏览器自动缩放页面,而自己去设置viewport的content例如(这里之所以要设置viewport是因为我们要实现border1px的效果,加入我给border设置了1px,在scale的影响下,高清屏中就会显示成0.5px的效果)
1
2
3
4
5
<script>
var drp = window.devicePixelRatio;
var meta = document.querySelector('meta[name="viewport"]');
meta.setAttribute('content', 'initial-scale=' + 1/dpr + ', maximum-scale=' + 1/dpr + ', minimum-scale=' + 1/dpr + ', user-scalable=no');
</script>

设置完之后配合rem,修改

1
2
3
4
@function px2rem($px){
$rem : 75px;
@return ($px/$rem) + rem;
}

双倍75,这样就可以完全按照视觉稿上的尺寸来了。不用在/2了,这样做的好处是:

  • 解决了图片高清问题。
  • 解决了 iphone6 border 1px 问题(我们设置的1px,在iphone上,由于viewport的scale是0.5,所以就自然缩放成0.5px)

尾声

以上4种方案都有它的适用场景,关键看业务场景,复杂页面的话,使用 rem 来做响应式布局是相对优雅的。