PC 页面的人聊的最多的就是兼容, 这是因为浏览器之间的差异引起的. 而移动端是基本没有兼容的问题的, 全是 CSS3. 可是适配的问题随之而来.
手机适配, 目前有四种方法:
固定高度, 宽度自适应
固定宽度, viewport 缩放
利用 rem 布局
利用 vw 布局
这四种方法的核心都是视口的确定
1. 固定高度, 宽度自适应
目前拉勾网使用的就是这种方式, 只适合简单的 web App, 单位使用 px
(1)以较小宽度 (如 320px) 的视觉稿作为参照进行布局
(2)固定屏幕为理想视口宽度
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
(3)垂直方向使用定值
(4)水平方向混合使用定值和百分比或者利用
弹性布局(Felx)
最终达到 " 当手机屏幕变化时, 横向拉伸或者填充空白的效果
这是一种典型的弹性布局: 关键元素高宽和位置都不变, 只有容器元素在做伸缩变换. 哪个宽度需要调整的时候使用响应式布局调调就行. 对于这类 App, 记住一个开发原则就好: 文字流式, 控件弹性, 图片等比缩放
Flex 布局语法教程
2. 固定宽度, viewport 缩放
设计图, 布局视口, 视觉视口使用一个宽度, 浏览器帮我们完成缩放, 单位使用 px 即可. 这种方法也很少见, 了解即可
网易金币商城在使用这种方法
原理
这种方法需要根据屏幕宽度来动态生成 viewport, 生成的 viewport 基本是这样:
<meta content="target-densitydpi=device-dpi,width=640,initial-scale=0.5625,maximum-scale=0.5625" name="viewport">
640 是我们根据设计图定下的, 0.5625 是根据屏幕宽度动态生成的.
生成的 viewport 告诉浏览器网页的布局视口使用 640px, 然后把页面缩放成 56%, 这是绝对的等比例缩放. 图片, 文字等等所有元素都被缩放在手机屏幕中.
通过 JS 动态设定 initial-scale
- var fixScreen = function() {
- var metaEl = doc.querySelector('meta[name="viewport"]'),
- metaCtt = metaEl ? metaEl.content : '',
- matchScale = metaCtt.match(/initial\-scale=([\d\.]+)/),
- matchWidth = metaCtt.match(/width=([^,\s]+)/);
- if ( metaEl && !matchScale && ( matchWidth && matchWidth[1] != 'device-width') ) {
- var width = parseInt(matchWidth[1]),
- iw = win.innerWidth || width,
- ow = win.outerWidth || iw,
- sw = win.screen.width || iw,
- saw = win.screen.availWidth || iw,
- ih = win.innerHeight || width,
- oh = win.outerHeight || ih,
- ish = win.screen.height || ih,
- sah = win.screen.availHeight || ih,
- w = Math.min(iw,ow,sw,saw,ih,oh,ish,sah),
- scale = w / width;
- if ( scale <1) {
- metaEl.content += ',initial-scale=' + scale + ',maximum-scale=' + scale + ', minimum-scale=' + scale;
- }
- }
- }
3. 使用 rem 布局
依照某特定宽度设定 rem 值(即 html 的 font-size), 页面任何需要弹性适配的元素, 尺寸均换算为 rem 进行布局; 当页面渲染时, 根据页面有效宽度进行计算, 调整 rem 的大小, 动态缩放以达到适配的效果
最典型的就是网易新闻和手机淘宝 Flexible 方案.
3.1 网易新闻方案
(1) 网易新闻的设计稿应该是基于 iphone6/7/8, 所以它的设计稿竖直放时的横向分辨率为 750px, 为了计算方便, 取 1rem=100px 为参照, 那么 HTML 元素的宽度就可以设置为 width: 7.5rem, 于是 HTML 的 font-size=deviceWidth / 7.5
(2) 媒体查询改变根元素的字体大小
媒体查询参考
- /**
- * view-port list:
- 320x480
- 320x568
- 320x570
- 360x592
- 360x598
- 360x604
- 360x640
- 360x720
- 375x667
- 375x812
- 393x699
- 412x732
- 414x736
- 480x854
- 540x960
- 640x360
- 720x1184
- 720x1280
- 800x600
- 1024x768
- 1080x1812
- 1080x1920
- */
- @media screen and (max-width: 320px) {
- HTML {
- font-size: 42.667px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 321px) and (max-width: 360px) {
- HTML {
- font-size: 48px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 361px) and (max-width: 375px) {
- HTML {
- font-size: 50px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 376px) and (max-width: 393px) {
- HTML {
- font-size: 52.4px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 394px) and (max-width: 412px) {
- HTML {
- font-size: 54.93px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 413px) and (max-width: 414px) {
- HTML {
- font-size: 55.2px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 415px) and (max-width: 480px) {
- HTML {
- font-size: 64px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 481px) and (max-width: 540px) {
- HTML {
- font-size: 72px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 541px) and (max-width: 640px) {
- HTML {
- font-size: 85.33px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 641px) and (max-width: 720px) {
- HTML {
- font-size: 96px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 721px) and (max-width: 768px) {
- HTML {
- font-size: 102.4px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
- @media screen and (min-width: 769px) {
- HTML {
- font-size: 102.4px;
- font-size: -webkit-calc(13.33333333vw);
- font-size: calc(13.33333333vw);
- }
- }
缺点: 媒体查询不能完全枚举, 只能大体覆盖. 如果想要精确覆盖要通过 JS 实现
document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5+ 'px';
(3) 视口设置理想视口
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
(4) 布局时, 设计图标注的尺寸除以 100 得到 CSS 中的尺寸(单位用 rem)
3.2 使用 Flexible 实现手淘 H5 页面的终端适配
lib-flexible
Flexible 要点:
(1) 第一步是根据设备像素比动态设置 viewport 的 scale
- if (!dpr && !scale) {
- var isAndroid = win.navigator.appVersion.match(/Android/gi);
- var isIPhone = win.navigator.appVersion.match(/iPhone/gi);
- var devicePixelRatio = win.devicePixelRatio;
- if (isIPhone) {
- // iOS 下, 对于 2 和 3 的屏, 用 2 倍的方案, 其余的用 1 倍方案
- if (devicePixelRatio>= 3 && (!dpr || dpr>= 3)) {
- dpr = 3;
- } else if (devicePixelRatio>= 2 && (!dpr || dpr>= 2)){
- dpr = 2;
- } else {
- dpr = 1;
- }
- } else {
- // 其他设备下, 仍旧使用 1 倍的方案
- dpr = 1;
- }
- scale = 1 / dpr;
- }
- var metaEl = doc.createElement('meta');
- var scale = isRetina ? 0.5:1;
- metaEl.setAttribute('name', 'viewport');
- metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
- if (docEl.firstElementChild) {
- document.documentElement.firstElementChild.appendChild(metaEl);
- } else {
- var wrap = doc.createElement('div');
- wrap.appendChild(metaEl);
- documen.write(wrap.innerHTML);
- }
适配结果:
- <!-- dpr = 1-->
- <meta name="viewport" content="initial-scale=scale,maximum-scale=scale,minimum-scale=scale,user-scalable=no">
- <!-- dpr = 2-->
- <meta name="viewport" content="initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no">
- <!-- dpr = 3-->
- <meta name="viewport" content="initial-scale=0.3333333333,maximum-scale=0.3333333333,minimum-scale=0.3333333333,user-scalable=no">
(2)第二步, 设置 HTML 元素的 font-size:font-size = deviceWidth / 10, 即
- 1rem=deviceWidth / 10(px)
- document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
(3) 布局的时候, 各元素的 CSS 尺寸(rem)= 设计稿标注尺寸(px)/ 设计稿横向分辨率 / 10
font-size 可能需要额外的媒介查询, 并且 font-size 不使用 rem. 详细看使用 Flexible 实现手淘 H5 页面的终端适配
注意!!!
最新版 (amfe-lexible) 已经不再修改 viewport , 而是统一使用理想视口.
3.3 网易与老版手机淘宝的做法不同点
(1) 淘宝需要动态
设置 viewport 的 scale
, 网易直接
设置为理想视口
.Flexible 中, 只对 iOS 设备进行 dpr 的判断, 对于 Android 系列, 始终认为其 dpr 为 1. 也就是说在安卓下, 淘宝的视口设置和网易新闻是一样的,
(2) 网易的做法, rem 值很好计算, 淘宝的做法肯定得用计算器或者 Sass 和 Less 这样的 CSS 处理器
4. 使用 vw 进行布局
vw: 是 Viewport's width 的简写, 1vw 等于 Windows.innerWidth 的 1%
Flexible 方案是通过 JavaScript 来模拟 vw 的特性. 到今天为止, vw 已经得到了众多浏览器的支持, 也就是说, 我们完全可以考虑将 vw 单位运用于我们的适配布局中, 当然你也可以继续使用 rem
参考
MobileWeb 适配总结
更多阅读
移动端 Web 页面适配方案
使用 Flexible 实现手淘 H5 页面的终端适配
了解真实的『REM』手机屏幕适配
来源: http://www.jianshu.com/p/a4cb417d8ed4