作为一个前端开发人员,我们的任务是将UI设计师的图稿运用计算机语言呈现在用户面前。而现在的设备大小尺寸不一,近年来智能手机的普及更是让网页的用户大部分来源与手机,所以让不同大小的移动端屏幕都能较好的还原设计稿就成了一个前端开发者需要解决的当务之急。我查阅了大量资料和进行了一些实践,下面是我对移动端适配的一些认识。
首先我们来谈谈我们在电脑端用的字体单位px和em
在国内的网站中大多都是使用px作为字体单位,只有百度做了个可调的表率。而在大洋彼岸,几乎所有的主流站点都使用em作为字体单位,也就是可调的。他们为什么要用em作为单位呢,主要有一下几个原因
- IE无法调整那些使用px作为单位的字体大小;
- 国外的大部分网站能够调整的原因在于其使用了em作为字体单位;
Firefox能够调整px和em,但是96%以上的中国网民使用IE浏览器(或内核)。
px和em概念
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的时候,需要注意两点:
1. body选择器中声明Font-size=62.5%;
2. 将你的原来的px数值除以10,然后换上em作为单位;
3. 重新计算那些被放大的字体的em数值。避免字体大小的重复声明。
下面我们来谈谈移动端的适配方案
首先讲讲一个基本概念
视窗 viewport
移动前端中常说的 viewport (视口)就是浏览器显示页面内容的屏幕区域。
移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的visual viewport和布局的layout viewport。
layout viewport(布局视口)
一般移动设备的浏览器都默认设置了一个viewport 元标签,定义一个虚拟的layout viewport(布局视口),用于解决早期的页面在手机上显示的问题。iOS, Android基本都将这个视口分辨率设置为 980px,所以pc上的网页基本能在手机上呈现,只不过元素看上去很小,一般默认可以通过手动缩放网页。
visual viewport(视觉视口)和物理像素
visual viewport(视觉视口)备物理屏幕的可视区域,屏幕显示器的物理像素,同样尺寸的屏幕,像素密度大的设备,硬件像素会更多。例如iPhone的物理像素:
- iPhone5 :640 * 1136
- iPhone6:750 * 1334
iPhone6 Plus:1242 * 2208
ideal viewport(理想视口)和 dip (设备逻辑像素)
ideal viewport(理想视口)通常是我们说的屏幕分辨率。
dip (设备逻辑像素)跟设备的硬件像素无关的。一个 dip 在任意像素密度的设备屏幕上都占据相同的空间。
比如MacBook Pro的 Retina (视网膜)屏显示器硬件像素是:2880 * 1800。当你设置屏幕分辨率为 1920 * 1200 的时候,ideal viewport(理想视口)的宽度值是1920像素, 那么 dip 的宽度值就是1920。设备像素比是1.5(2880/1920)。设备的逻辑像素宽度和物理像素宽度(像素分辨率)的关系满足如下公式:
逻辑像素宽度*倍率 = 物理像素宽度
而移动端手机屏幕通常不可以设置分辨率,一般都是设备厂家默认设置的固定值,换句话说 dip 的值就是 ideal viewport(理想视口)(也就是分辨率)的值,比如,iPhone的屏幕分辨率:
iPhone5 :分辨率 320 * 568,物理像素 640 * 1136,@2x
iPhone6:分辨率 375 * 667,物理像素 750 * 1334,@2x
iPhone6 Plus :分辨率 414 * 736,物理像素1242 * 2208,@3x
所以我们需要使用viewport元标签控制布局
通常用到的适配代码
width
为了是适应布局,我们一般将width设为device-width。
width=device-width 也就是将layout viewport(布局视口)的宽度设置 ideal viewport(理想视口)的宽度。网页缩放比例为100%时,一个CSS像素就对应一个 dip(设备逻辑像素),而layout viewport(布局视口)的宽度,ideal viewport(理想视口)的宽度(通常说的分辨率),dip 的宽度值是相等的。
initial-scale
initial-scale用于指定页面的初始缩放比例:
- initial-scale=1 表示将layout viewport(布局视口)的宽度设置为 ideal viewport(理想视口)的宽度,
- initial-scale=1.5 表示将layout viewport(布局视口)的宽度设置为 ideal viewport(理想视口)的宽度的1.5倍。
因为分辨率和物理像素的关系,所以我们就需要通过js来确定页面的初始缩放比例,下面是控制初始缩放比例的代码。后面会进行解释
var i = e.navigator.appVersion.match(/iphone/gi) ? e.devicePixelRatio :1,
a = 1 / i,
然后我们谈谈rem
rem其实和em非常相似,在w3c中是这样描述rem的
font size of the root element.
它的用法和em差不多,区别是em是针对父元素的font-size做计算,而rem是相对与根元素做计算。我们在移动端使用rem作为所有大小的单位来解决适配的问题。
我们设置根元素font-size的大小,应该是不同屏幕设置不一样的。比如一个740大的屏幕,我们会把它的font-size设为76px;而一个370大的屏幕,我们会把它的font-size设为34px,这要根据屏幕大小而言。
所以,我们需要编写一个js文件来适应不同的屏幕
这是某个网站的移动适配js,这里通过这个文件做一些解释
!function(e) {
function t() {
e.rem = d.getBoundingClientRect().width / 16, d.style.fontSize = e.rem + "px";
}
var n,
i = e.navigator.appVersion.match(/iphone/gi) ? e.devicePixelRatio :1,
a = 1 / i,
d = document.documentElement,
o = document.createElement("meta");
if (e.dpr = i,
e.addEventListener("resize", function() {
clearTimeout(n), n = setTimeout(t, 300);
}, !1),
e.addEventListener("pageshow", function(e) {
e.persisted && (clearTimeout(n), n = setTimeout(t, 300));
}, !1),
d.setAttribute("data-dpr", i), o.setAttribute("name", "viewport"),
o.setAttribute("content", "initial-scale=" + a + ", maximum-scale=" + a + ", minimum-scale=" + a + ", user-scalable=no"), d.firstElementChild)
d.firstElementChild.appendChild(o);
else {
var m = document.createElement("div");
m.appendChild(o), document.write(m.innerHTML);
}
t();
}(window), document.addEventListener("DOMContentLoaded", function() {
var e = document.createElement("input");
e.type = "hidden",
e.value = '{"platform": "qq_qzone_weixin_weibo_copy","title":"","desc": "","image":"","comment": "", "url":"","callback":"shareCallback()"}',
e.id = "app_share_conf", document.getElementsByTagName("body")[0].appendChild(e);
}, !1);
把视觉稿中的px转换成rem
我们在开发过程中拿到的设计稿都是以px作为单位的,那我们在进行移动端编程的时候该怎样对应rem大小呢?
e.rem = d.getBoundingClientRect().width / 16
这段代码的意思是把屏幕分成16份,根元素的font-size就等于屏幕大小/分成份数。当然我们不一定要把屏幕分成16份,比如淘宝的Flexible.js将屏幕分成10份。
缩放比例
前面已经提到,针对不同的设备,屏幕分辨率和物理像素的倍速不同所以我们要通过获取设备来设置缩放比例。
var i = e.navigator.appVersion.match(/iphone/gi) ? e.devicePixelRatio :1,
a = 1 / i,
关于移动适配的meta标签,我们是不用事先编写的,通过这个js文件,将自动创建meta标签。