Last active
April 19, 2017 10:19
-
-
Save luckyadam/a79571b66a3044992a41 to your computer and use it in GitHub Desktop.
移动端多屏适配
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
移动端适配方案总结 | |
=== | |
> 移动端开发总是存在很多的挑战,兼容性、性能、更高要求的用户体验,都是前端攻城狮需要一一攻破的壁垒。而大屏、高分辨率的手机的出现,又为攻城狮们立下了一个新的制高点,如何适配不同尺寸,不同分辨率的机器,如何在高清分辨率的屏幕上为用户呈现更精致的作品,是前端攻城狮新的挑战。 | |
### 利用zoom适配 | |
在进行拍拍小店的开发中我们发现页面在高清分辨率的手机如iPhone6 Plus上表现不尽如人意,有些元素还有文案在这些手机上显示得太小,视觉体验非常不好。咋办类?为了快速解决适配更高分辨率手机的问题,我们天马行空地想到,直接将页面按照一定比例缩放不就好啦,这样在更高分辨率的手机上将页面适当放大,不就能达到适配高清分辨率手机的目的。 | |
适配的代码如下 | |
```javascript | |
(function (global) { | |
var width = global.innerWidth; | |
var ratio = (width / 320).toFixed(2); | |
ratio = Math.min(ratio, 2); | |
document.documentElement.style.zoom = ratio; | |
global.zoom = function (ratio) { | |
if (ratio === undefined) { | |
return document.documentElement.style.zoom; | |
} else { | |
document.documentElement.style.zoom = ratio; | |
} | |
} | |
})(window); | |
``` | |
原理就是以宽320这一值作为基准,读取页面大小,计算出比例然后设置给根元素的``zoom``属性,以达到缩放的目的。 | |
这样可以快速暴力地将整个页面进行缩放,并且能适配大部分手机屏,在iPhone6 Plus上看起来效果棒棒哒,问题似乎解决了呢! | |
但是细细想下,这样做对于一些简单的活动页面来说可以满足需求,而对于一个布局比较复杂的网站来说,这样做非常不合适,因为这样将页面所有元素简单缩放,会改变元素原来的**top/height**等值,让已有组件如**lazyload**失效而需要重新计算,而且有些使用背景图的元素可能显示会有问题,可能需要重新切图;同时对于使用圆角边框元素,使用zoom变换后会导致边框的宽度不一致,影响视觉体验,虽然将``border``换成``box-shadow``后能解决这个问题,但是大量地使用``box-shadow``又会是另一个灾难;同时而在一些Android机器上会出现兼容性问题,比如元素被过度放大,这些都需要花时间去解决。 | |
所以,使用``zoom``去暴力缩放是极力不推荐的一种做法。 | |
### 通过动态设置viewport来缩放 | |
看来**zoom**是一次失败的尝试啦,但是缩放页面是达到适配效果的最佳捷径,我们不想放弃,所以我们探索了另一种缩放方式,通过修改viewport来进行缩放。 | |
Viewport是指浏览器用于展示内容的区域,但是在移动端viewport的大小不一定和浏览器的可视区域一样大,因为移动设备相对于PC来说太小,为了能显示那些为PC设计的网站,一般移动设备的浏览器通常会将自己默认的viewport设置为980px或者其他。 | |
我们可以通过meta viewport标签来设置viewport,通过标签的**width**来设置viewport的大小,通过**initial-scale**、**minimum-scale**、**maximum-scale**来设置页面缩放,所以通过要达到我们的目的依然十分简单。 | |
祭出神器: | |
``` | |
<meta name="viewport" content="width=320,maximum-scale=1.3,user-scalable=no"> | |
``` | |
我们目前的设计稿是都是基于320的,所以我们将width设为320,然后在这个基础上进行一定比例的缩放,这个比例是**当前设备宽度/320**计算出来动态修改的。利用这一方式可以非常快捷实现适配的目的,简单粗暴、非常高效。 | |
但是,看起来美好的东西总是存在但是,经测试在某些Android手机上会存在页面元素模糊的问题,这又是一悲剧,不过如果对Android手机的适配要求不高的话,这一方式还是可以考虑的,暂时收为备胎方案吧。 | |
而在这时,搜遍网络资料,发现了网易前端的一个[解决方案](https://github.com/unbug/generator-webappstarter/blob/master/app/templates/app/src/util/MetaHandler.js),通过设置viewport,将width直接设置为UE图的宽度,然后按UE图的尺寸去编写页面,比如UE图的宽度为640,那么针对iOS设备,meta为 | |
``` | |
<meta content="width=640,user-scalable=no" name="viewport"> | |
``` | |
但是对于Android设备,由于只设置宽度它并不会主动进行缩放,所以我们需要通过一些设置来达到缩放的目的,缩放的值是通过**当前设备宽度/设计稿的宽度**来计算 | |
``` | |
<meta content="target-densitydpi=device-dpi,width=640,initial-scale=0.5625,maximum-scale=0.5625" name="viewport"> | |
``` | |
据传这是网易前端实践多年总结出的方案,效果应该还是不错哒! | |
附上[例子](http://c.3g.163.com/CreditMarket/default.html)。 | |
### 基于REM的解决方案 | |
在CSS3中引入了一个新单位``rem``,这是个啥嘞?在[W3C官方文档](http://www.w3.org/TR/css3-values/)中是这样定义的**font size of the root element**,也就是说它是以页面根元素的字号大小作为基准的,我们页面中元素的大小设置将会基于根元素的字号大小。 | |
比如我们给根节点设置``font-size: 20px;``,则``1rem = 20px``,那么页面元素``40px``应该是``2rem``,附上px和rem的换算地址 [https://offroadcode.com/prototypes/rem-calculator/](https://offroadcode.com/prototypes/rem-calculator/)。 | |
不要看这是一个新引入的单位,但是各大浏览器厂商的觉悟还是很高的,这个单位的兼容性非常高,在Android 2.X以上、iOS5以上都支持,大家可以看看来自[caniuse](http://caniuse.com/#search=rem)的统计。 | |
可以说这是一个神奇的单位,如果我们为页面根元素设置一个字号大小,并且随着页面页面窗口大小的变化去重置这个字号大小,那么页面元素的大小也会跟随根元素字号大小的变化而变化,这就是基于REM来布局的妙处,这样在大屏手机上元素会合理放大,而在小屏手机上元素也会调整到合适的大小,几乎可以很好地适配大部分机型。 | |
搬运自网上的自适应脚本 | |
```javascript | |
(function (doc, win) { | |
var docEl = doc.documentElement, | |
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', | |
recalc = function () { | |
var clientWidth = docEl.clientWidth; | |
if (!clientWidth) return; | |
docEl.style.fontSize = 100 * (clientWidth / 320) + 'px'; | |
}; | |
// Abort if browser does not support addEventListener | |
if (!doc.addEventListener) return; | |
win.addEventListener(resizeEvt, recalc, false); | |
doc.addEventListener('DOMContentLoaded', recalc, false); | |
})(document, window); | |
``` | |
但是基于REM的布局也存在缺点,它需要利用JS来做一些类似hack的操作,而且部分浏览器下,计算时,因为数字类型是int,而不是float,所以会进行四舍五入,导致计算偏差,从而当多个模块横向排列时,会出现“放不下,挤下来”等情况。段落文字的字号大小设置不适合使用``rem``来设置,还是应该使用``px``,这样的话还是会有文字在高分辨率手机上显示过小的问题,这时我们可以考虑使用CSS3中提供的``media query``来做一些适配 | |
``` | |
.test { | |
font-size: 12px; | |
} | |
@media all and (min-width: 361px) { | |
.test { | |
font-size: 14px; | |
} | |
} | |
@media all and (min-width: 415px) { | |
.test { | |
font-size: 16px; | |
} | |
} | |
``` | |
[淘宝首页](http://m.taobao.com/)就是使用REM来做布局的,而且它通过给不同dpr的设备上元素设置不同字号大小解决了字号适配的问题 | |
``` | |
div { | |
width: 1rem; | |
height: 0.4rem; | |
font-size: 12px; // 默认写上dpr为1的fontSize | |
} | |
[data-dpr="2"] div { | |
font-size: 24px; | |
} | |
[data-dpr="3"] div { | |
font-size: 36px; | |
} | |
``` | |
同时他们根据设备的dpr动态设置页面的viewport以达到对页面进行一定缩放的目的,来使得页面能按照物理像素来进行渲染,提高页面的清晰度,同时能愉快地写出1px宽的元素。这算是一种组合式适配方案,整体还是非常棒的,而且适配效果非常棒。 | |
附上淘宝解决方案[传送门](https://github.com/amfe/lib-flexible)。 | |
### 总结 | |
使用改变``zoom``粗暴地缩放页面,看起来非常简单高效,但引出的问题不少,所以不推荐使用。 | |
通过改变``viewport``来进行适配,我们所需做的操作非常少,额外引用一段脚本就能实现,而且效果不错,值得尝试。 | |
纯粹的REM布局还是不够完美,字号的适配需要借助响应式来进行操作,略显麻烦,但是兼容性非常好,也是不错的解决方案。 | |
### 参考 | |
- http://www.w3.org/TR/css3-values/ | |
- http://www.quirksmode.org/blog/archives/2010/09/combining_meta.html | |
- http://isux.tencent.com/web-app-rem.html | |
- https://github.com/amfe/lib-flexible | |
- https://github.com/unbug/generator-webappstarter/blob/master/app/templates/app/src/util/MetaHandler.js | |
- http://www.cnblogs.com/2050/p/3877280.html | |
- https://www.icloud.com/keynote/AwBWCAESEJd5uucfBPGt6KPotb3tNfsaKm-Q7fqs2-4ojmPoPJuWZCvjYgKl5jEf1URdRgdgNHe38BTzeF3DK7q1ewMCUCAQEEIJ85mw21ii_AwybOqxoF-V02v51Vdg855ED4qVA_8bXr?redirectReason=notFound#Mobile_Webpage_如何自适应屏幕_2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment