移动端基础概念
屏幕尺寸
- 指屏幕的对角线的长度,单位是英寸,1英寸 = 2.54厘米
- 常见的屏幕尺寸有2.4、2.8、3.5、3.7、4.2、5.0、5.5、6.0等
- 又称为设备像素,它是屏幕能显示的最小粒度
- 买手机的时候会有一个 n x m 的分辨率, 那是屏幕的 n x m 个呈像的点,一个点(小方格)为一个物理像素
- 设备像素也被称为物理像素,它是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和高度
- 任何设备的物理像素都是固定的,任何一款设备上1物理像素的大小是不会变得
- 不同设备上1物理像素的大小可能是不一样的
- CSS像素是一个抽象的单位,主要使用在浏览器上,用来精确的度量Web页面上的内容
- 它是为Web开发者创造的,在css或者javascript中使用的一个抽象的层
- 一般情况下,css像素被称为与设备无关的像素(device-independent像素),简称"DIPs"
- 在一个标准的显示密度下,一个css像素对应着一个设备像素
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/>
- 从css像素角度出发,由于视觉视口所包含的css像素的个数跟用户的缩放行为有关,我们无法准确的判断视觉视口的尺寸。
- 默认情况下(物理像素:css像素 = 1:1),一个视觉视口包含该设备分辨率的值所代表的css像素个数
- 视觉视口包含了整个布局视口
- 移动端在初始化时,视觉视口会将整个布局视口完整显示出来,所以移动端浏览器在初始化的时候,物理像素与css像素之间的比例不可能是一比一,这个比例与设备分辨率和布局是口的大小有关
- 这个比例的本质上和视口有关,因为移动端浏览器初始化时视觉视口包含的css像素个数等于布局视口包含的css像素个数
- 视觉视口包含的物理像素个数等于设备的分辨率
缩放
- rem适配原理:改变了一个元素在不同设备上占据的css像素的个数
- rem单位:根标签的font-size所代表的值,即根标签的fontsize = 1rem
- rem适配优缺点
- 优点:没有破坏完美视口
- 缺点:px值到rem的转换太复杂
- rem与em的区别
- em
-
子元素字体大小的em是相对于父元素字体大小
-
元素的width/height/padding/margin用em的话是相对于该元素的font-size
-
- rem
-
rem是全部的长度都相对于根元素,即<html>元素
-
- em
- 示例
(function () { var layout = document.documentElement.clientWidth / 16; var styleNode = document.createElement('style'); // 创建style标签 styleNode.innerHTML = "html{font-size : " + layout + "px!important"; // 将根标签的font-size置为布局视口的宽/16 document.head.appendChild(styleNode); //将style标签添加到head中 })()
viewport适配
- viewport适配原理
- 将所有设备布局视口的宽度调整为设计图的宽度
-
修改css像素与布局像素的比例,每一个元素在不同设备上占据的css像素的个数是一样的。但是css像素和物理像素的比例不相同
-
适配比例 = 理想视口宽度 / 设计图尺寸
-
viewport适配方案的优缺点
- 优点:所量即所得
-
缺点:不是完美视口
- 获取理想视口的宽度
-
方法一: screen.width ---- 兼容性差
- 方法二:一开始给HTML标签添加上<meta name="viewport" content="width=device-width"> 。此时,用document.documentElement.clientWidth获取理想视口的宽度
-
- 示例
(function () { var targetW = 640 // 设计图宽度 var scale = document.documentElement.clientWidth / targetW // 理想视口的宽度 / 设计图宽 var meta = document.querySelector("meta[name='viewport']") meta.content = 'initial-scale=' + scale + ',minimum-scale=' + scale + ',maximum-scale='+scale+',user-scalable=no' })()
移动端一物理像素实现
rem+系统缩放
- 主体适配采用rem适配 并放大rem的基值(dpr倍)
- 再通过系统缩放 缩回dpr倍,initial-scale=1/dpr
- 示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no,maximum-scale=1.0,minmul-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>1物理像素</title> <style> * { margin: 0; padding: 0; } #test { width: 16rem; height: 1px; background-color: black; margin-top: 30px; } </style> </head> <body> <div id="test"></div> <script> // rem 适配 // 淘宝的做法,通过适配角度解决1物理像素的问题 window.onload = function () { (function () { var dpr = window.devicePixelRatio || 1 // 像素比 var layout = document.documentElement.clientWidth // 布局视口宽度 var styleNode = document.createElement('style') styleNode.innerHTML = "html { font-size:" + layout * dpr / 16 + "px!important}" document.head.appendChild(styleNode) var scale = 1 / dpr var meta = document.querySelector('meta[name="viewport"]') meta.content = "width=device-width, initial-scale=" + scale + ",user-scalable=no,maximum-scale=" + scale + ",minimum-scale=" + scale })() } </script> </body> </html>
响应式+变换缩放
- 通过媒体查询进行单个元素的缩放
- 示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no,maximum-scale=1.0,minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>1物理像素</title> <style> * { margin: 0; padding: 0; } #test { width: 100%; height: 1px; background-color: black; margin-top: 5rem; } @media only screen and (-webkit-device-pixel-ratio:2) { #test { transform: scaleY(0.5); } } @media only screen and (-webkit-device-pixel-ratio:3) { #test { transform: scaleY(0.33333); } } </style> </head> <body> <div id="test"></div> <script> (function () { var layout = document.documentElement.clientWidth / 16; var styleNode = document.createElement('style'); styleNode.innerHTML = "html{font-size :" + layout + "px!important;}" document.head.appendChild(styleNode) })() </script> </body> </html>
移动端事件基础
触摸事件
- 移动端有两类事件: 触摸事件、 指针事件[←点击可查看MDN文档]
- 本篇暂时只提到触摸事件中的touchstart、touchmove以及touchend
- touchmove与mousemove的区别
- touchmove:不可能单独触发
-
mousemove:可以单独触发
- 需要注意的是:touchstart、touchmove以及touchend最好不要用DOM1的事件绑定 item.ontouchstart = function(){} ,原因在于DOM1的绑定方式在chrome早期版本(56及以下)无法触发,这就给调试带来了困难
-
建议采用DOM2的方式绑定touchstart、touchmove以及touchend事件: addEventListener()
禁止移动端事件默认行为
- 需要全面禁止的系统默认行为有:
-
下拉橡皮泥(阻尼)效果
-
长按选中文字效果
-
- 示例
// 下面这行代码可以禁止手机浏览器所有的默认事件 document.addEventListener("touchstart", function (ev){ ev = ev || window.event // ev.cancelable 可用于查看是否能取消该事件的浏览器默认行为 item.innerHTML = ev.cancelable; ev.preventDefault() })
移动端初始模板
- 移动端必备条件
-
meta标签
-
全面阻止事件的默认行为
- 全面阻止事件的默认行为,有一些设备会有页面上所有的滚动条失效的隐患(可以使用自定义滚动条)
- 适配方案
-
- 示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script> window.onload = function () { // 阻止默认行为 document.addEventListener('touchstart', function (ev) { ev = ev || window.event ev.preventDefault() }) // rem适配方案 !(function (flag) { var w = document.documentElement.clientWidth var styleNode = document.createElement('style') styleNode.innerHTML = "html{font-size: " + w / flag + "px!important}" document.head.appendChild(styleNode) })(16) } </script> </body> </html>
事件穿透
- 事件穿透产生的原因
-
pc端的事件可以在移动端触发
-
pc端事件有300毫秒延迟
-
移动端事件不会有延迟
-
- 示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> * { margin: 0; padding: 0; } body, html { line-height: 0; } .wrapper { width: 200px; height: 200px; background-color: skyblue; opacity: 0.5; position: absolute; top: 0; left: 0; } a { font-size: 12px; line-height: 18px; } </style> </head> <body> <div class="wrapper"></div> <a href="http://www.baidu.com">百度一下</a> <script> window.onload = function () { // 阻止默认行为 document.addEventListener('touchstart', function (ev) { ev = ev || window.event ev.preventDefault() }) // rem适配方案 !(function (flag) { var w = document.documentElement.clientWidth var styleNode = document.createElement('style') styleNode.innerHTML = "html{font-size: " + w / flag + "px!important}" document.head.appendChild(styleNode) })(16) var wrapper = document.querySelector('.wrapper') wrapper.addEventListener('click', function () { wrapper.style.display = "none" }) // 全面禁止事件默认行为会导致手机端a标签无法跳转 // 移动端a标签跳转方案,解决误触 var aNodes = document.querySelectorAll("a") for (var i = 0; i < aNodes.length; i++) { // 该写法使滑动的时候页面不发生跳转 aNodes[i].addEventListener('touchstart', function () { this.isMove = false; }) aNodes[i].addEventListener('touchmove', function () { this.isMove = true; }) aNodes[i].addEventListener('touchend', function () { if (!this.isMove) { window.location = this.href } }) } } </script> </body> </html>
TouchEvent
touchEvent.changedTouches
- 触发事件时改变的触摸点的集合
- 可以通过clientX和clientY属性来获取当前集合中手指在视口中的坐标的坐标
- touchEvent.changedTouches[0].clientX; // 获取当前集合中第一根手指的横坐标
touchEvent.targetTouches
- 绑定事件的那个结点上的触摸点的集合列表
touchEvent.touches
- 触发事件时改变的触摸点的集合
移动端常见问题
禁止电话与邮箱
- iPhone上的Safari和某些webkit android手机浏览器,会自动对看起来像是电话号码的数字串(包括已经加入连字符或括号格式化过的)和邮箱添加链接,导致用户点击该数字后跳转到拨打电话的界面
- 可以通过使用meta标签来 禁止掉电话及 邮箱的跳转 <meta name="format-detection" content="telephone=no,email=no">
- 当禁止电话及邮箱跳转后如果想让用户点击电话或邮箱跳转可以将其写成如下格式
-
<a href="tel:110">13579246801</a> <a href="mailto:123@qq.com">123@qq.com</a>
-
链接高亮
a { text-decoration: none; -webkit-tap-highlight-color: rgba(0,0,0,0); /* 解决链接高亮问题 */ }
圆角过圆
input { width: 50px; height: 50px; border-radius: 5px; -webkit-appearance: none; /* iphone 只要有 border-radius 属性就会变成一个圆 */ }
Font Boosting
- Font Boosting被称为字体提升,也被称为Text Autosizer,Font Inflation.是 Webkit 给移动端浏览器提供的一个特性:当我们在手机上浏览网页时,很可能因为原始页面宽度较大,在手机屏幕上缩小后就看不清其中的文字了。而 Font Boosting 特性在这时会自动将其中的文字字体变大,保证在即不需要左右滑动屏幕,也不需要双击放大屏幕内容的前提下,也可以让人们方便的阅读页面中的文本。
- 解决方法一:给元素指定宽高
- 解决方法二:给元素指定max-height p { max-height: 9999px; }
补充
Web App、Native App、hybrid app
-
web App:即web前端页面,多采用h5开发
- 不需要安装包,节约手机空间
- 量级轻,开发成本低
-
版本迭代快
- 基于浏览器,可以跨平台使用
- 安全性相对较低,页面跳转费力,不稳定感更强。
- native app:又称原生app,基于智能手机本地操作系统android(安卓基于Java) 、ios(基于OC --- Object-C)编写运行的第三方应用程序。
-
性能更好
-
版本迭代需要用户重新打包补丁
- 开发成本高。
- 发布新版本慢,应用商店发布审核周期长,下载由用户控制
-
- hybrid app:即混合app, native app 与 web app的混合。
移动价值链
- 网络运营商
-
中国移动
-
中国联通
-
中国电信
-
-
设备供应商
-
华为
-
小米
-
魅族
-
oppo
-
vivo
-
苹果
- ...
-
-
软件制造商(操作系统)
-
谷歌
- 苹果
- ...
-
-
服务提供商
-
谷歌
-
华为
- 小米
- ...
-
移动端浏览器分类
-
移动端大概有30多种浏览器,其中20多种处于边缘化状态
内置浏览器
-
每部手机都有内置浏览器,这个浏览器属于设备的固件,通常由操作系统厂商开发,而且大多数内置浏览器都被紧密的集成到了底层的操作系统中去了,因此我们没有办法单独升级内置浏览器,只能借助于更新操作系统。总的来说,它的特点如下:
-
更新慢
-
移植在操作系统中
-
-
安卓
-
三星 --- 三星webkit
- 中兴 --- 中兴webkit
- 华为 --- 华为webkit
- 小米 --- 小米webkit
- 索尼 --- 索尼webkit
-
- ios --- safari
- 黑莓 --- 黑莓webkit
-
window phone --- IE
可下载浏览器
-
在实践中,只有安卓才有可下载浏器(uc、猎豹、qq浏览器等)
-
可下载浏览器更新快
- 可下载浏览器独立于操作系统
webview
-
webview是独立程序,是留给原生应用的一个操作系统浏览接口,它用了内置浏览器很多底层的组件(比如渲染引擎)
-
ios的操作系统默认不允许在它身上有多余的渲染引擎,因此其他浏览器想在ios上运行就必须使用ios的webview
代理浏览器(较少)
-
代理浏览器的渲染引擎存在于服务端,因此其js性能及其低下
-
代理浏览器的渲染引擎能够解析和执行 HTML、CSS、Javascript,但并不是运行在设备上,而是在远程服务器上,与代理浏览器相对应的叫完备浏览器
-
完备浏览器
-
它与我们预期的浏览器的运行方式一样,当用户请求一个页面时,浏览器就会通过http请求去抓取HTML CSS Javascript 和其他资源,一旦一切就绪,就会去渲染和显示页面,所有的步骤都是在客户端进行的,会占用内存,处理器的事件,电池寿命
-
-
混合浏览器
- 可以在代理浏览器和完备浏览器间切换的浏览器称为混合浏览器(opera-mini、uc-mini)
-
-
代理浏览器工作流程
-
用户请求一个页面,他不会发送一个普通的http请求,而是发送一个特殊的加密链接到一个特殊的代理服务器
-
代理服务器会发送正常的http请求给用户希望访问的web服务器
-
代理服务器包含一个渲染引擎,能够正常渲染页面
-
代理服务器压缩页面,压缩页面后的文件类似于PDF,它有链接热点
-
代理服务器同样通过加密链接把这个文件发到客户端
-
客户端展示
-