移动端界面的适配


Posted in Javascript onJanuary 11, 2017

阅读目录

  • 适配的要求
  • 适配的方法,3个步骤
  • 适配中背景图片的处理
  • 适配的原理解析

摘要:在进行移动端界面的书写的时候,如果把宽度高度或者字体大小全部写死的话,那么在所有手机上看到的大小都一样,存在的问题就是同样大小的字体,或者一个盒子模型,

在大屏幕手机上看起来会有点偏小。比如iphone6PLUS。如果是做成适配的话,就很好的解决了这个问题,大屏幕显示的内容大一点,小屏幕显示的小一点。

所以今天做一个移动端页面适配的小小总结

适配的要求

1、在不同分辨率的手机上,页面看起来是自适应的。整体效果看起来比较和谐。不会说大屏幕上看起来特别小。小屏幕上看起来特别大

2、主要是关注字体,宽高,间距,图片大小等。

3、所提供的设计图一般是手机分辨率的两倍,才能方便做适配。

4、使用rem做单位,而不是传统的px

适配的方法,3个步骤

步骤1:

设置viewport,也就是平时写移动端页面都要加上的:

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

步骤2:

首先我们在我们的页面引入下面的flexible.js,

这段适配的js代码是拿淘宝的来用的。

适配的js代码的github地址如下:https://github.com/amfe/lib-flexible/blob/master/src/flexible.js。

步骤3:

页面上我们的css代码可以这样写,比如设计图给我们的尺寸是750*1000的。某个容器在设计图的宽度是150px*225px,那我们在css里面

宽度:150px/750px/10=150px/75px=2rem;

高度为:225px/75px=3rem;

一句话:布局的时候,各元素的css尺寸=设计稿标注尺寸/设计稿横向分辨率/10;

div{
 width: 2rem;
 height: 3rem;
}

通过上面的3个步骤,我们就可以将我们的移动端页面做成适配的了。

css换算方法

不过有一点,一直算来算去挺烦的。所以在写css的时候,最好使用css预处理器,比如sass、less来写,这样就方便很多了。

或者在sublimeText3中安装cssREM插件,正常书写px单位,然后编辑器自动帮你换算成rem.

cssREM插件的安装教程:https://github.com/flashlizi/cssrem

注意点:

容器的宽度高度我们用rem为单位,但是字体大小font-size我们还是用px,而不是用rem

原因:

flexible.js的作者winter是这样解释的:考虑到字体的点阵信息,一般文字尺寸多会采用 16px 20px 24px等值,若以rem指定文字尺寸,会产生诸如21px,19px这样的值,会导致字形难看,毛刺,甚至黑块,故大部分文字应该以px设置。

一般标题类文字,可能也有要求随屏幕缩放,且考虑到这类文字一般都比较大,超过30px的话,也可以用rem设置字体。

下面粘贴一下flexible.js的源码:加了注释

flexible.js

;(function(win, lib) {
 var doc = win.document;
 var docEl = doc.documentElement;
 var metaEl = doc.querySelector('meta[name="viewport"]');
 var flexibleEl = doc.querySelector('meta[name="flexible"]');
 var dpr = 0;
 var scale = 0;
 var tid;
 var flexible = lib.flexible || (lib.flexible = {});
 if (metaEl) {
 console.warn('将根据已有的meta标签来设置缩放比例');
 var match = metaEl.getAttribute('content').match(/initial\-scale=([\d\.]+)/);
 if (match) {
  scale = parseFloat(match[1]);
  dpr = parseInt(1 / scale);
 }
 } else if (flexibleEl) {
 var content = flexibleEl.getAttribute('content');
 if (content) {
  var initialDpr = content.match(/initial\-dpr=([\d\.]+)/);
  var maximumDpr = content.match(/maximum\-dpr=([\d\.]+)/);
  if (initialDpr) {
  dpr = parseFloat(initialDpr[1]);
  scale = parseFloat((1 / dpr).toFixed(2)); 
  }
  if (maximumDpr) {
  dpr = parseFloat(maximumDpr[1]);
  scale = parseFloat((1 / dpr).toFixed(2)); 
  }
 }
 }
 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;
 }
 //为html标签添加data-dpr属性
 docEl.setAttribute('data-dpr', dpr);
 if (!metaEl) {
 metaEl = doc.createElement('meta');
 metaEl.setAttribute('name', 'viewport');
 // 动态设置meta 
 metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
 if (docEl.firstElementChild) {
  docEl.firstElementChild.appendChild(metaEl);
 } else {
  var wrap = doc.createElement('div');
  wrap.appendChild(metaEl);
  doc.write(wrap.innerHTML);
 }
 }
 //根据dpr和物理像素设置rem
 function refreshRem(){
 //getBoundingClientRect().width相当于物理像素
 var width = docEl.getBoundingClientRect().width;
 // width / dpr > 540等于独立像素
 if (width / dpr > 540) {
  width = 540 * dpr;
 }
 var rem = width / 10; // 将屏幕宽度分成10份, 1份为1rem. rem转化px计算公式=d*(width/10)
 docEl.style.fontSize = rem + 'px';
 flexible.rem = win.rem = rem;
 }
 // 监听窗口变化,重新设置尺寸
 win.addEventListener('resize', function() {
 clearTimeout(tid);
 tid = setTimeout(refreshRem, 300);
 }, false);
 // 当重新载入页面时,判断是否是缓存,如果是缓存,执行refreshRem()
 win.addEventListener('pageshow', function(e) {
 if (e.persisted) {
  clearTimeout(tid);
  tid = setTimeout(refreshRem, 300);
 }
 }, false);
 if (doc.readyState === 'complete') {
 doc.body.style.fontSize = 12 * dpr + 'px';
 } else {
 doc.addEventListener('DOMContentLoaded', function(e) {
  doc.body.style.fontSize = 12 * dpr + 'px';
 }, false);
 }
 refreshRem();
 flexible.dpr = win.dpr = dpr;
 flexible.refreshRem = refreshRem;
 flexible.rem2px = function(d) {
 var val = parseFloat(d) * this.rem;
 if (typeof d === 'string' && d.match(/rem$/)) {
  val += 'px';
 }
 return val;
 }
 flexible.px2rem = function(d) {
 var val = parseFloat(d) / this.rem;
 if (typeof d === 'string' && d.match(/px$/)) {
  val += 'rem';
 }
 return val;
 }
})(window, window['lib'] || (window['lib'] = {}));

适配中背景图片的处理

1、如何使用background-size

因为是使用了rem来做单位,我们在写移动端的背景图的时候,一般使用background-size来控制大小,那要怎么来换算呢?

换算单位如下:

background-size=背景图的大小/该设计图的宽度*10

打个比方:我的背景图是16*18,设计图是按照640的宽度来设计的。那么我的background-size值为

background-size: 16/640*10rem 16/640*10rem   也就是 background-size:0.25rem 0.28125rem;

通过这样控制之后,我们的背景图也做到了适配的效果

2、雪碧图的适配!!!!

刚开始做适配的时候,有一件事是比较头疼的,那就是雪碧图的适配,主要是background-size和background-position的配置比较烦。那么怎么进行在使用fexible.js的时候适配雪碧图呢,方法如下:

假如我有下面这张雪碧图,设计图给我的是按640的分辨率来做的。

这张雪碧图的大小为200px*458px

移动端界面的适配

假设现在我们要用的那个勋子的背景图。分为以下几步:

1、测量勋字这张背景图的大小,大小为:75px*85px移动端界面的适配

2、测量这个勋字在雪碧图的位置,也就是设置background-position:.经测量,他在雪碧图的位置为 x:-123px,y:-7px

3、对着张雪碧图进行换算:看下面代码:

知道了上面的尺寸,我们就行换算即可,将每个值除以640再乘以10   为什么这么算,可以看看源码

要使用这样雪碧图:

<!-- 长宽为: -->
width: 75/640*10=1.171875rem;
height: 85/640*10=1.328125rem;
<!-- background-size为 -->
<!-- 因为整张雪碧图的宽度为200px, -->
background-size: 200/640*10rem auto;
<!-- background-position为: -->
background-position: -123/640*10rem -7/640*10rem;

html:

<i class="item1"></i>

css:

.item1{
 width: 75/640*10=1.171875rem;
 height: 85/640*10=1.328125rem;
 margin: 20px auto;
 background: url('../images/itemBg.png') no-repeat;
 // 因为整张雪碧图的宽度为200px,
 background-size: 200/640*10rem auto;
 等于
 background-size: 3.125rem auto;
 // 该背景图在雪碧图的位置
 background-position: -123/640*10rem -7/640*10rem;
 等于
 background-position: -1.921875rem -0.109375rem;
 display: block;
}

因为换算比较麻烦,所以建议使用sass或者less来进行计算。具体效果我放在了github上,可以看看:

https://github.com/xianyulaodi/flexibleDemo

适配的原理解析

先来了解一些概念

在进行分析之前,首先得知道下面这些关键性基本概念(术语)。

物理像素(physical pixel)

物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。一个物理像素是显示器(手机屏幕)上最小的物理显示单元,在操作系统的调度下,每一个设备像素都有自己的颜色值和亮度值。

其实可以类比为分辨率。打个比方,一张图片有n多个很小很小个格子组成。

移动端界面的适配

盗图,哈哈

设备独立像素(density-independent pixel)

设备独立像素(也叫密度无关像素),可以认为是计算机坐标系统中得一个点,这个点代表一个可以由程序使用的虚拟像素(比如: css像素),然后由相关系统转换为物理像素。

所以说,物理像素和设备独立像素之间存在着一定的对应关系,这就是接下来要说的设备像素比。

可以理解为css像素,比如宽度为20px等等。

设备像素比(device pixel ratio ),简称dpr

设备像素比(devicePixelRatio简称dpr)定义了物理像素和设备独立像素的对应关系,它的值可以按如下的公式的得到:

设备像素比 = 物理像素 / 设备独立像素  

在javascript中,可以通过window.devicePixelRatio获取当前设备的dpr

css中的px可以看做是设备的独立像素,所以通过devicePixelRatio,我们可以知道该设备上一个css像素代表多少个物理像素。

例如,在Retina屏的iphone上,devicePixelRatio的值为2,也就是说1个css像素相当于2个物理像素。

再举个例子:iphone6中:

设备宽高为375×667,可以理解为设备独立像素(或css像素)。

dpr为2,根据上面的计算公式,其物理像素就应该×2,为750×1334。

是不是有点头晕了,可以看看这篇文章消化一下:http://div.io/topic/1092

理解了上面的概念,就比较好理解它的实现原理了

理解它的原理有两点:

1、了解利用meta标签对viewport进行控制

我们可以看看我们通常在head里面加的meta标签

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

该meta标签的作用是让当前viewport的宽度等于设备的宽度,同时不允许用户手动缩放。

content="width=device-width,让viewport的宽度等于设备的宽度,如果不这样的设定的话,那就会使用那个比屏幕宽的默认viewport,会出现横向滚动条。

如果改变initial-scale的值,那么就可以让页面达到缩放

meta viewport 有6个属性,可以了解一下

width 设置layout viewport  的宽度,为一个正整数,或字符串"device-width"
initial-scale 设置页面的初始缩放值,为一个数字,可以带小数
minimum-scale 允许用户的最小缩放值,为一个数字,可以带小数
maximum-scale 允许用户的最大缩放值,为一个数字,可以带小数
height 设置layout viewport  的高度,这个属性对我们并不重要,很少使用
user-scalable 是否允许用户进行缩放,值为"no"或"yes", no 代表不允许,yes代表允许

2、淘宝的移动端页面和flexible.js源码解析:

第一个要点:

淘宝触屏版布局的前提就是viewport的scale根据devicePixelRatio(设备像素比) 动态设置:

设备像素比的简单介绍:http://www.zhangxinxu.com/wordpress/2012/08/window-devicepixelratio/

来看一下flexible.js源码:

移动端界面的适配

移动端界面的适配

根据不同的像素设备比,来对页面进行不同的缩放。页面缩放的 scale=1/dpr ;

来看移动端淘宝接下来的三张图:https://m.taobao.com/#index

三星galasy S4 

data-dpr=1, 所以 initial-scale=1  (因为源码上 scale = 1 / dpr;)

移动端界面的适配

iPhone5:

data-drp=2,所以initial-scale=0.5

移动端界面的适配

iphone 6 Plus

移动端界面的适配

第二个要点:

动态设置html的font-size,html元素的font-size的计算公式,font-size = deviceWidth / 10。我们也可以看到上面三张截图的html里面的font-size是不同的

源码如下:

var width = docEl.getBoundingClientRect().width;
 if (width / dpr > 540) {
  width = 540 * dpr;
 }
 var rem = width / 10;
 docEl.style.fontSize = rem + 'px';
 flexible.rem = win.rem = rem;

其实flexible的实质就干了以下几件事

1、动态改写meta标签

2、给元素添加data-dpr属性,并且动态改写data-dpr的值。也就是动态改写dpr

3、给元素添加font-size属性,并且动态改写font-size的值

以上就是移动端适配的小小总结,之前只是直接用,没有好好的理解它的原理。发觉整理的时候,资料查下来也还是学到很多概念,学到挺多东西的。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
Mootools 1.2教程 输入过滤第一部分(数字)
Sep 15 Javascript
基于jquery实现拆分姓名的方法(纯JS版)
May 08 Javascript
javascript手工制作悬浮菜单
Feb 12 Javascript
Angular.js中控制器之间的传值详解
Apr 24 Javascript
微信小程序 wx.request方法的异步封装实例详解
May 18 Javascript
js案例之鼠标跟随jquery版(实例讲解)
Jul 21 jQuery
JavaScript引用类型RegExp基本用法详解
Aug 09 Javascript
React中使用UEditor百度富文本的方法
Aug 22 Javascript
微信小程序云开发之使用云存储
May 17 Javascript
实现高性能javascript的注意事项
May 27 Javascript
js实现抽奖的两种方法
Mar 19 Javascript
Vue组件为什么data必须是一个函数
Jun 11 Javascript
bootstrapValidator bootstrap-select验证不可用的解决办法
Jan 11 #Javascript
HTML5 js实现拖拉上传文件功能
Nov 20 #Javascript
Bootstrap表单控件使用方法详解
Jan 11 #Javascript
老生常谈的跨域处理
Jan 11 #Javascript
bootstrap选项卡使用方法解析
Jan 11 #Javascript
常用的javascript设计模式
Jan 11 #Javascript
WebView启动支付宝客户端支付失败的问题小结
Jan 11 #Javascript
You might like
一些关于PHP的知识
2006/11/17 PHP
在任意字符集下正常显示网页的方法一
2007/04/01 PHP
phplist及phpmailer(组合使用)通过gmail发送邮件的配置方法
2016/03/30 PHP
禁止直接访问php文件代码分享
2020/05/05 PHP
js模拟弹出效果代码修正版
2008/08/07 Javascript
javascript中onmouse事件在div中失效问题的解决方法
2012/01/09 Javascript
firefox浏览器不支持innerText的解决方法
2013/08/07 Javascript
jQuery+AJAX实现网页无刷新上传
2015/02/22 Javascript
iScroll中事件点击触发两次解决方案
2015/03/11 Javascript
jQuery检查事件是否触发的方法
2015/06/26 Javascript
基于javascript实现单选及多选的向右和向左移动实例
2015/07/25 Javascript
Jquery1.9.1源码分析系列(十五)动画处理之外篇
2015/12/04 Javascript
图片旋转、鼠标滚轮缩放、镜像、切换图片js代码
2020/12/13 Javascript
全面解析JavaScript中“&amp;&amp;”和“||”操作符(总结篇)
2016/07/18 Javascript
JS实现的简易拖放效果示例
2016/12/29 Javascript
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
2017/03/06 Javascript
完美实现js选项卡切换效果(一)
2017/03/08 Javascript
浅谈JsonObject中的key-value数据解析排序问题
2017/12/06 Javascript
JQuery基于FormData异步提交数据文件
2020/09/01 jQuery
[01:25:33]完美世界DOTA2联赛PWL S3 INK ICE vs Magma 第二场 12.20
2020/12/23 DOTA
编写Python爬虫抓取暴走漫画上gif图片的实例分享
2016/04/20 Python
python 文件查找及内容匹配方法
2018/10/25 Python
Python3.5基础之变量、数据结构、条件和循环语句、break与continue语句实例详解
2019/04/26 Python
Python中正反斜杠(‘/’和‘\’)的意义与用法
2019/08/12 Python
Python实现点云投影到平面显示
2020/01/18 Python
毕业生护理专业个人求职信范文
2014/01/04 职场文书
工厂保安员岗位职责
2014/01/31 职场文书
玲玲的画教学反思
2014/02/04 职场文书
老公给老婆的保证书
2014/04/28 职场文书
大学学风建设方案
2014/05/04 职场文书
环卫工人先进事迹材料
2014/06/02 职场文书
2014年学校国庆主题活动方案
2014/09/16 职场文书
财务整改报告范文
2014/11/05 职场文书
2014年稽查工作总结
2014/12/20 职场文书
防暑降温通知书
2015/04/27 职场文书
2015年女职工工作总结
2015/05/15 职场文书