1.移动端基础
1)网络运营商
2)设备供应商 (手机厂商)
3)操作系统提供商
谷歌 Android
苹果 IOS
微软 WindowsPhone
4)App提供商
2.移动端浏览器分类
1)内置浏览器
每部手机都有内置浏览器,这个浏览器属于设备的固件,通常由操作系统厂商开发。
而且大多数内置浏览器都被紧密的集成到了底层的操作系统中去了,
换句话说,我们没有办法单独升级内置浏览器,只能借助于更新操作系统
安卓 ==>安卓webkit
安卓 ==>安卓chrome(4.4及以上)
ios ==>safari
安卓出厂自带浏览器:安卓webkit浏览器
最新的安卓webkit版本只是到4.3版本(存在于安卓4.3之前的系统),后续谷歌不再对安卓webkit进行更新
4.4及以上的安卓版本使用chrome浏览器作为内置浏览器 chrome浏览器内核是Blink
2)可下载浏览器
他们都是基于开源内核Webkit进行二次开发的,并不是完全的自主内核
在实践中,只有安卓才有可下载的浏览器,因为在IOS上不允许安装其他的渲染引擎
所以,所有的第三方浏览器都不过是换了个图标的Safari。
!! 3)webview
webview是独立程序,是留给原生应用的一个操作系统浏览接口,用了内置浏览器很多底层的组件(例如渲染引擎)。
它的作用是用来展示一个web页面。它使用的内核是webkit引擎,4.4版本之后,直接使用Chrome作为内置网页浏览器
4)代理浏览器
代理浏览器的渲染引擎能够解析和执行HTML CSS 还有JavaScript,但并不是运行在设备上,而是在远程服务器上,与代理浏览器相对应的叫完备浏览器。
5)混合浏览器
可以选择代理 也可以选择完备的浏览器 被称作混合浏览器
3.三种App
1) NativeApp 原生App
原生APP就是利用Android、iOS平台官方的开发语言、开发类库、工具进行开发,在操作系统上直接运行的App。
2) WebApp
以Web开发语言(HTML、CSS、JavaScript)开发的,在浏览器上运行的App。其本质是浏览器功能的叠加。
!! 3) HybridApp 混合App
即利用了原生APP的开发技术还应用了HTML5开发技术,是原生和HTML5技术的混合应用。混合比例不限。性能介于WebApp和原生App之间。
`hybridapp`是一个半原生程序,伪造了一个浏览器的`apk/ipa`原生程序,把地址写死了,然后里面运行了一个`webapp`。里面是`WebView UI` 。但是还是运行在机器的操作系统上。
HybridApp应用就是包了个客户端的壳,其实里面是`HTML5`的网页
4.屏幕
1) 屏幕尺寸
指屏幕的对角线的长度,单位是英寸,1英寸=2.54厘米。
!! 2) 像素
1.设备像素(Device Pixel)
设备像素也被称为物理像素,他是显示设备中一个最微小的物理部件。
每个像素可以根据操作系统设置自己的颜色和亮度。
任何设备的物理像素的数量都是固定的。
2.CSS像素(CSS Pixel)
CSS像素也被称为逻辑像素,CSS像素是一个抽象的单位,主要使用在浏览器上,用来精确的度量(确定)Web页面上的内容。
在一个标准的显示密度下(普通屏),一个CSS像素对应着一个设备像素,
用户把页面放大(手指向外滑动,看到元素变大)一倍,那么css中1px所代表的物理像素也会增加一倍。
3.设备独立像素
设备独立像素(Device Independent Pixel),CSS中使用的像素是设备独立像素。
4.位图像素
一个位图像素是栅格图像(如:png, jpg, gif等)最小的数据单元
1 个位图像素对应于1个物理像素,图片才能得到完美清晰的展示
3) 设备像素比
设备像素比 (devicePixelRatio) 简称 DPR , 它的官方的定义为:设备物理像素和设备独立像素的比例。
DPR = 物理像素 /独立像素,JavaScript中获取屏幕的DPR:window.devicePixelRatio
4) 屏幕像素密度
屏幕上每英寸可以显示的像素点的数量,单位是ppi
5.视口 viewport
视口 (viewport)是用户网页的可视区域。
1)PC端视口
window.innerWidth; //浏览器视口(viewport)宽度(单位:像素),如果存在垂直滚动条则包括它。
window.innerHeight; //浏览器窗口的视口(viewport)高度(以像素为单位);如果有水平滚动条,也包括滚动条高度。
document.documentElement.clientWidth; //浏览器视口(viewport)宽度(单位:像素),不包含垂直滚动条
document.documentElement.clientHeight //浏览器视口(viewport)高度(单位:像素),不包含水平滚动条
window.screen.width; // 屏幕的宽度 (设备独立像素)
window.screen.height; // 屏幕的高度 (设备独立像素)
2)移动端视口
布局视口 Layout Viewport:
document.documentElement.clientWidth;
document.documentElement.clientHeiht;
默认980
视觉视口 Visual Viewport:
window.innerWidth;
window.inenrHeight;
默认980
理想视口 Ideal Viewport:
也就是当布局视口的宽度 等于 设备独立像素的宽度时就是理想视口
<meta name="viewport" content="width=device-width">
!! 完美视口:
解决元素太大问题,浏览器的布局视口会尽量的包裹住元素导致width=device-width失效(系统自动调整initial-scale)
<meta name="viewport" content="width=device-width,initial-scale=1.0">
`initial-scale` 如果设置为 2.0, 布局视口会变为屏幕宽度的 1/2, 视觉视口也会变为屏幕宽度的 1/2,相对于理想视口比较
布局视口在 width 与 inital-scale 产生分歧时会选择他们中视觉视口比较大的那一个。
6.缩放
!! 1)用户缩放
PC:
缩放会改变视觉视口和布局视口的尺寸,会影响布局
放大,视觉视口和布局视口的尺寸都变小
缩小,视觉视口和布局视口的尺寸都变大
移动端:
缩放会改变视觉视口的尺寸,不会改变布局视口的尺寸,不影响布局。
放大,布局视口不变,视觉视口变小
缩小,布局视口不变,视觉视口变大
!! 2)系统缩放
只有移动端才可以进行系统缩放,通过 meta 设置 initial-scale 可以设置系统缩放系数,
<meta name="viewport" content="initial-scale=2.0" />
系统缩放 改变视觉视口的同时也会改变布局视口的宽度。
`initial-scale` 如果设置为 2.0, 布局视口会变为屏幕宽度的 1/2, 视觉视口也会变为屏幕宽度的 1/2,相对于理想视口比较
7.ViewPort 相关属性
| 属性名 | 取值 | 描述 |
| ------------- | --------------------- | --------------------------------------------------- |
| width | 正整数或device-width | 定义视口的宽度,单位为像素 |
| height | 正整数或device-height | 定义视口的高度,单位为像素,一般不用 |
| initial-scale | [0.0-10.0] | 定义初始缩放值 |
| maximum-scale | [1.0-10.0] | 定义放大最大比例,它必须小于或等于maximum-scale设置 |
| minimum-scale | [0.0-1.0] | 定义缩小最小比例,它必须大于或等于minimum-scale设置 |
| user-scalable | yes / no | 定义是否允许用户手动缩放页面,默认值 yes |
| viewport-fit | auto/contain/cover | 全面屏(刘海屏)设置 |
!! 注意事项:
viewport 标签只对移动端浏览器有效,对 PC 端浏览器是无效的
即使设置了 user-scalable = no,在 Android Chrome 浏览器中也可以强制启用手动缩放;ios上的Safari浏览器也是无效的
8.移动端适配
em单位相对于自身的font-size大小,rem单位相对于html元素的font-size大小
1) 百分比与固定高度布局方案
可以选择的布局方案有(文字大小可以选用媒体查询来设置):
横向百分比 + 纵向高度固定
弹性盒子+高度固定布局
2)rem适配方案1
长度单位都是用 rem 来设置
当屏幕尺寸改变,只有修改 html 元素的 `font-size` 即可实现等比适配
我们在制作页面的时候,只考虑跟设计稿相同的屏幕尺寸即可,其他尺寸屏幕自动适配
(function () {
var styleNode=document.createElement("style");
var Ww=document.documentElement.clientWidth;//让根元素的字号大小等于屏幕的宽度,那么屏幕的总宽度就是1rem
styleNode.innerHTML="html{font-size:"+Ww+"px !important}"
document.head.appendChild(styleNode)
})();//让根元素的字号大小等于屏幕的宽度,那么屏幕的总宽度就是1rem
使用less优化calc计算:
@picWidth:640;
.rem(@name,@num){
@{name}: @num / @picWidth * 16rem;
}
!! 3)rem适配方案2
样式固定设置html的font-size 为100px
然后样式所有的大小全部按照设计图来计算,比如640的设计图,6.4rem就是全屏
但是手机的大小和640有差异,所以根据比例计算html的font-size的值
;~function(doc){
let picWidth = 640;
let docEle = doc.documentElement;
let Ww = docEle.clientWidth;
//以下两个判断是可选
//只要屏幕宽度小于320 那么不再考虑缩放 最小设置为320 小于320的屏幕生成滚动条
Ww = Ww < 320 ? 320 : Ww;
//只要屏幕宽度大于640 那么不再考虑放大 最大设置640 所以屏幕可能会留白
Ww = Ww > 640 ? 640 : Ww;
docEle.style.fontSize = Ww * 100 / picWidth + "px";
}(document);
4)viewport适配
开发的时候根据设计搞完全还原像素,原理核心就是修改页面mate标签的缩放。
通过设置 `initial-scale` , 将所有设备布局视口的宽度调整为设计图的宽度
(function(){
// 设置设计稿的宽度
var targetW = 640;
// 计算当前视口与设计稿的比值
var scale = document.documentElement.clientWidth / targetW;
// 获取 meta[name='viewport'] 元素
var meta = document.querySelector("meta[name='viewport']");
// 设置meta元素 content的值,重点是设置 initial-scale 的值为前面计算的比例
meta.content="initial-scale="+scale+",minimum-scale="+scale+",maximum-scale="+scale+",user-scalable=no";
})()
5) zoom(火狐不兼容)和transform(scale)不推荐
9.其它适配
1)1px物理像素一边边框适配
方法一(整体缩小,在放大rem):
(function () {
let dpr = window.devicePixelRatio || 1;
var styleNode=document.createElement("style");
!! var Ww=document.documentElement.clientWidth*dpr/16;
styleNode.innerHTML="html{font-size:"+Ww+"px !important}"
document.head.appendChild(styleNode)
let scale = 1 / dpr;
let meta=document.querySelector("meta[name='viewport']");
!! meta.content="width=device-width,initial-scale="+scale;
})();
方法二:(还可使用伪元素的方式)
.test{
width: 100%;
height: 1px;
position:absolute;
left:0;
bottom:0;
background-color: black;
}
@media only screen and (-webkit-device-pixel-ratio: 2){
.test{
transform-origin: 0 bottom;
transform: scaleY(.5);
}
}
@media only screen and (-webkit-device-pixel-ratio: 3){
.test{
transform-origin: 0 bottom;
transform: scaleY(.33333333333333333333333333);
}
}
2) 1像素的圆角边框
.test{
width: 100%;
height: 100%;
border: 1px solid #000;
border-radius: 10px;
box-sizing:border-box;
position: relative;
}
@media only screen and (-webkit-device-pixel-ratio: 2){
.test:after {
content: '';
width: 200%;
height: 200%;
position: absolute;
top: 0;
left: 0;
border-radius: 20px;
transform: scale(0.5,0.5);
transform-origin: top left;
}
}
@media only screen and (-webkit-device-pixel-ratio: 3){
.test:after {
content: '';
width: 300%;
height: 300%;
position: absolute;
top: 0;
left: 0;
border-radius: 30px;
transform: scale(0.3333333,0.3333333);
transform-origin: top left;
}
}
3)图片的适配
1.背景图适配2X,3X图
//媒体查询根据设备像素比引入不同图片
div{
width: (32 / 640) * 16rem;
height: (32 / 640) * 16rem;
.bg-image('star');
}
.bg-image(@url) {
!! background-image: url("../images/@{url}@2x.png");
background-position: center center;
background-repeat: no-repeat;
!! background-size: contain;
@media (-webkit-device-pixel-ratio: 3) {
background-image: url("../images/@{url}@3x.png");
}
}
2.img标签的适配2X,3X图
<img srcset="../images/star@2x.png 2x,../images/star@3x.png 3x"
src="./images/star@1x.png"
alt="图片适配">
10.触屏(touch) 事件
- touchstart: 手指触摸屏幕时触发,即使已经有手指在屏幕上也会触发(相当于click事件,click事件有延迟200到300毫秒)
- touchmove: 手指在屏幕滑动时触发
- touchend: 手指从屏幕时移开时触发
- touchcancel: 当触控点被特定的实现方式打乱时触发(例如,弹框),一般不用
事件绑定方式:DMO0和DOM2都可以,建议DOM2
11.事件对象TouchEvent
TouchEvent.changedTouches: 一个 TouchList对象,包含了代表所有从上一次触摸事件到此次事件过程中,状态发生了改变的触点的 Touch 对象(即手拿开和移动的对象)。
TouchEvent.targetTouches: 一个 TouchList 对象,是包含了如下触点的 Touch 对象:触摸起始于当前事件的目标 element 上,并且仍然没有离开触摸平面的触点
TouchEvent.touches: 一 个 TouchList 对象,包含了所有当前接触触摸平面的触点的 Touch 对象,无论它们的起始于哪个 element 上
TouchList详解:
只读属性:`length`
方法:`item(index)`
| 属性 | 含义 |
| ------------- | ------------------------------------------------------------ |
| identifier | `此 Touch 对象的唯一标识符`. 一次触摸动作(我们指的是手指的触摸)在平面上移动的整个过程中, 该标识符不变. 可以根据它来判断跟踪的是否是同一次触摸过程. **只读属性.** |
| screenX | 触点相对于屏幕左边沿的的X坐标. **只读属性.** |
| screenY | 触点相对于屏幕上边沿的的Y坐标. **只读属性.** |
| clientX | 触点相对于可见视口(visual viewport) 左边沿的的X坐标. 不包括任何滚动偏移. **只读属性.** |
| clientY | 触点相对于可见视口(visual viewport) 上边沿的的X坐标. 不包括任何滚动偏移. **只读属性.** |
| pageX | 触点相对于HTML文档左边沿的的X坐标. `当存在水平``滚动的``偏移时, 这个值包含了水平滚动的偏移`. **只读属性.** |
| pageY | 触点相对于HTML文档上边沿的的Y坐标. `当存在垂直滚动的偏移时, 这个值包含了垂直滚动的偏移`. **只读属性. |
| force | 手指挤压触摸平面的压力大小, 从0.0(没有压力)到1.0(最大压力)的浮点数. **只读属性** |
| target | 当这个触点最开始被跟踪时(在 `touchstart` 事件中), 触点位于的HTML元素. 哪怕在触点移动过程中, 触点的位置已经离开了这个元素的有效交互区域, 或者这个元素已经被从文档中移除. 需要注意的是, 如果这个元素在触摸过程中被移除, 这个事件仍然会指向它, 但是不会再冒泡这个事件到 `window` 或 `document` 对象. 因此, 如果有元素在触摸过程中可能被移除, 最佳实践是将触摸事件的监听器绑定到这个元素本身, 防止元素被移除后, 无法再从它的上一级元素上侦测到从该元素冒泡的事件. **只读属性.** |
12.阻止默认事件(上下滑动时空白,长按选中文字和图片)
//为提高性能,chrome5、6之后, window docuemnt body 触屏事件默认无法取消默认事件,
//需要给 addEventListener() 指定第三个参数 passive:false DOM0级事件不可以使用
document.addEventListener("touchstart",function(ev){
ev.preventDefault();
},{passive:false});
13.阻止默认事件的隐患
阻止默认事件的功能:
- 上下滑动时无空白
- 长按不选中文字和图片(可能是隐患)
- 解决了点击穿透问题
- IOS上的Safari浏览器禁止用户缩放(可能是隐患)
- 滚动条失效(隐患)
- 超链接失效(隐患)
- 会让 input 无法获取焦点(隐患)
```js
//如果说针对某一个标签 想要能够滑动,能够选中文字,只需要让它阻止传播即可
document.addEventListener("touchstart",function(ev){
ev.preventDefault();
},{passive:false});
oP.addEventListener("touchstart",function(ev){
ev.stopPropagation();
});
//超链接失效的问题
let links = document.querySelectorAll('a[href]');
links.forEach(function(link){
link.addEventListener('touchend', function(event) {
location.href = link.href;
// event.stopPropagation();//阻止默认事件不管用
},{passive:false});
})
//解决会让 input 无法获取焦点
let ip = document.querySelector("input");
ip.addEventListener("touchstart",function(ev){
ev.stopPropagation();
},{passive:false});
//解决滚动条失效
let oCon = document.querySelector(".con")
let oWrap = document.querySelector(".wrap")
oCon.addEventListener("touchstart",function(ev){
//当前的触摸手指
let touch = ev.changedTouches[0];
//当前位置
let startPosition = oCon.offsetTop;
//手指初始位置
let startPoint = touch.clientY;
oCon.addEventListener("touchmove",function(ev){
//每次移动都需要再获取一次手指
let touch = ev.changedTouches[0];
//手指移动后的位置
let endPoint = touch.clientY;
//距离的差
let disPoint = endPoint - startPoint;
//此时con的定位
let endPosition = startPosition + disPoint;
//临界值
if(endPosition >= 0) {
endPosition = 0
}else if(endPosition <= oWrap.offsetHeight - oCon.offsetHeight){
endPosition = oWrap.offsetHeight - oCon.offsetHeight
}
//赋值
oCon.style.top = endPosition + "px";
},{passive:false})
},{passive:false})
```
14.多指事件(只能是ios端支持)
1)gesturestart:手指触碰当前元素,屏幕上有两个或者两个以上的手指
2)gesturechange:手指触碰当前元素,屏幕上有两个或者两个以上的手指位置在发生移动
3)gestureend:在gesturestart后, 屏幕上只剩下两根以下(不包括两根)的手指