【移动端】
1. 什么是移动端
大前端时代:
- 前端开发涉及的领域越来越多,如:PC端,移动端,小程序,App,甚至是物联网
- 大前端’的大字体现在地位重要,涉及领域众多
- 前后端完全分离
移动端开发:
- PC端:指电脑端,使用电脑访问的页面
- 移动端:手机访问
- 比如:使用手机浏览器访问淘宝,京东等网页版
- 手机网页版,App 应用,小程序等统称为移动端开发
- 目前主流开发: 移动端
2. 屏幕相关概念
2.1 屏幕大小
-
屏幕大小是指屏幕的对角线长度,单位一般是英寸(inch)。
-
常见的手机屏幕大小有: 3.5寸、4寸、4.7寸、5.0寸、5.5寸、6.0寸等等
-
英寸与厘米的换算关系为 :1英寸(inch) = 2.54厘米(cm)
2.2 屏幕分辨率
概念:
- 屏幕分辨率是指屏幕在:横向、纵向上所拥有的 ‘物理像素点’总数。一般表示用 n * m 表示。
- 设备能控制显示的最小单元,可以把物理像素看成是对应的像素点
- 例如: IPhone 6 的屏幕分辨率为 750 * 1334
注意事项:
- 屏幕分辨率是一个固定值,屏幕生产出来就确定了,无法修改!
- 屏幕分辨率、显示分辨率是两个概念,电脑或手机的设置中可以修改的是:显示分辨率。
- 显示分辨率指的是设备当前所用到的物理像素点数,或者说:屏幕分辨率 >= 显示分辨率。
2.3 常见手机分辨率
3. 像素相关概念
3.1 物理像素
概念:
- 屏幕的分辨率
- 设备能控制显示的最小单元,可以把物理像素看成是对应的像素点
特点:
-
由屏幕制造商决定,屏幕生产后无法修改
-
物理像素点个数越多,图像越清晰,但人类肉眼识别是有极限的,当到了极限之后就无法分辨
-
常用:iphone6物理像素: 750 ***** 1334
作用:
- 决定控制屏幕显示的像素点个数,屏幕分辨率的大小
理解:
-
可以认为是屏幕上的发光点
-
演唱会上组成大的LED*屏幕上的一块一块的小屏幕,由小的发光晶体管组成
3.2 css像素
概念:
- css像素又名: 逻辑像素,css像素是一个抽象的长度单位,单位是px
- 编写css、JS中所使用的
- 都是css像素(可以理解为:“程序员像素”)
特点:
- 虚拟像素
- 无法像长度单位一样直接衡量,最终需要转换为物理像素进行量化
作用:
- 开发者进行样式编写的单位,最终由设备转换为物理像素量化在页面上
请思考:
- 代码中所写的1px(css像素 ),到了屏幕上到底对应几个物理像素呢?
- 是1个css像素就对应1个物理像素(“发光的灯泡”)吗?
转换介质:设备独立像素
3.3 设备独立像素
概念:
- 设备独立像素简称 DIP 或 DP(device-independent pixel)
- 又称:屏幕密度无关像素。
- 理解:我们的电脑、手机设备中有一个坐标系,这个坐标系中的一个点,就是一个设备独立像素,对应一个可以由程序去使用的虚拟像素(css像素)。程序根据屏幕特性、将设备独立像素上的点对应到屏幕上的物理像素点。
特点:
- 虚拟像素,设备厂商根据屏幕特性设置的,无法更改
- 可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用并控制的虚拟像素
- 1css像素 = 1设备独立像素,利用设备独立像素描述移动端设备尺寸的时候,单位也是px,比如iphone6的尺寸(设备独立像素)是 375 * 667
作用:
- 最终转换为物理像素进行量化
- 设备独立像素的出现,使得即使在高清屏下,(例如苹果的Retina屏),也可以让元素有正常的尺寸,让代码不受到设备的影响
历史:
- 在没出现【高清屏】的年代,1个css像素对应1个物理像素,但自从【高清屏】问世,二者就不再是1对1的关系了。苹果公司在2010年推出了一种新的显示标准:在屏幕尺寸不变的前提下,把更多的物理像素点压缩至一块屏幕里,这样分辨率就会更高,显示效果就会更佳细腻。苹果将这种屏幕称为:’Retina 屏幕(又名:视网膜屏幕)’,与此同时推出了配备这种屏幕的划时代数码产品——iPhone4
视网膜屏幕:
- 起名视网膜屏幕,指人类肉眼可识别的最大分辨率屏幕
- Dpr(devicePixelRatio)为 2
3.4 三者像素关系
设备独立像素与css像素
- 在无缩放的情况下(标准情况):1css像素 = 1设备独立像素
- 移动端目前大都是不使用缩放情况
设备独立像素与物理像素关系
- 普通屏幕下 1 个设备独立像素 对应 1 个物理像素
- 高清屏幕下 1 个设备独立像素 对应 N 个物理像素
3.5 设备像素比(dpr)
概念:
- 单一方向上设备【物理像素】和【设备独立像素】的比例。即:dpr = 物理像素 / 设备独立像素
获取
- Window.devicePixelRatio
常见设备像素比:
像素之间关系
- 普通屏(dpr = 1):1css像素 = 1设备独立像素 = 1物理像素
- 高清屏(dpr = 2):1css像素 = 1设备独立像素 = 2物理像素
- 高清屏(dpr = 3):1css像素 = 1设备独立像素 = 3物理像素
示例:程序员写了一个width为300px的盒子,那么:
- 它占据了300个css像素;
- 若用户不进行缩放,则对应300个设备独立像素;
- 在dpr为2的设备上,这300个css像素占据了300*2=600个物理像素(横向)
总结:以iphone6为例(横向)
- 物理像素:750px
- 设备独立像素:375px
- css像素:375px
4. 视口viewport
4.1 视口分类
- PC端视口
- 移动端视口
- 布局视口
- 视觉视口
- 理想视口(完美视口)
4.2 PC端视口
概念:
- pc端视口的默认宽度和浏览器窗口的宽度一致;
- 在 css 标准文档中,视口也被称为:初始包含块;
- 它是所有 css 百分比宽度推算的根源;
获取方法:
- 获取浏览器窗口文档显示区域的宽度,不包含滚动条
- document.documentElement.clientWidth
- 包含滚动条可视区域
- window.innerWidth
- 包含滚动条、边框的可视区域
- window.outerWidth
- 设备整个屏幕的宽度,与浏览器无关
- screen.width
4.3 移动端视口
4.3.1 布局视口
概念:
- Css布局时的画布,用于约束页面内容显示的范围
- 可以理解为我们画画时候的画板大小,用于约束绘画者绘画的范围
大小:
默认980px
作用:
-
用于解决早期的页面在手机上显示的PC问题
4.3.2 视觉视口
概念:
- 视觉视口就是用户可见的区域,它的绝对宽度永远和设备屏幕一样宽
作用:
- 用于解决单一使用布局视口压缩页面出现的问题;
- 比如:压缩后页面内容太小,用户无法精准点击甚至是无法查看清楚页面内容
4.3.3 理想视口
概念:
- 当页面在浏览器中呈现最佳效果即为理想视口
- 布局视口宽度 = 视觉视口宽度 = 设备宽度
作用:
-
用于使页面完美呈现在浏览器中
-
解决单一压缩页面在手机浏览器中带来的问题
4.3.4 理想视口实现
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
扩展内容: viewport选项
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no">
- width: 布局视口宽度
- initial-scale: 初始缩放比例
- maximum-scale: 最大缩放比例
- minimum-scale: 最小缩放比例
- user-scalable: 是否允许用户缩放,
问题延伸:
实现理想视口以后,虽然没有滚动条和页面压缩现象了,但是移动端设备的型号很多,屏幕大小不一致,那么不同移动端设备下,页面内的元素大小如何显示?大小固定? || 根据屏幕大小不同元素也随之变化?
解决问题:
适配
5. 适配
请思考:
为什么要做适配
场景:
- 实际开发中上线后的移动端项目需要在不同的手机上供用户使用访问,不同的手机屏幕尺寸大小不一样
- 那么在开发中需要单独为每一中手机单独开发页面吗?
5.1 适配方案
- viewport适配
- rem适配
- vw适配
5.2 viewport适配
-
适配方案:
- 通过meta标签进行viewport设置达到适配效果
- 主要是调整布局视口大小
- 拿到设计稿之后,设置布局视口宽度为设计稿宽度,然后直接按照设计稿给宽高进行布局即可
-
优点:
- 开发页面的时候直接按照设计稿的尺寸进行编写即可
-
缺点:
- 有些不希望被适配的东西,例如边框,也被适配了,导致比设计稿大的设备上边框太粗
- 图片失真,内容显示不清
viewport 适配的思路:
在进入页面,要渲染这个页面,渲染的时候从上到下执行代码,先执行一段js代码,获取设备的宽度
然后立即用js去设置一个meta标签,这个meta标签的width设置为当前设备的宽度
5.3 px, em, rem的区别
- px:
- 绝对单位,一旦设置,就无法因为适应页面大小而改变
- em:
- 相对单位,em是相对于其父元素来设置字体大小的,一般都是以的“font-size”为基准
- 子元素字体大小的em是相对于父元素字体大小
- 元素的width/height/padding/margin用em的话是相对于该元素的font-size
- rem:
- 相对单位,rem是相对于根节点字体大小
- 一旦设置根标签字体大小,body标签必须设置字体大小,否则会继承根标签字体大小
5.4 rem适配
5.4.1 方案一:
使用rem 适配的时候,需要设置body字体大小,否则会影响em值的大小
- 适配细节:
- 将根节点字体设置为100px
- 1rem = 100px
- 编写的值rem(设备元素尺寸) = (设计稿元素尺寸 / 设计稿宽度 * 设备宽度) / 100 rem
- 比如:iphone6手机下,设计稿750, 设计稿元素宽高为375的div,设置宽高应该是: (375/750 * 375)/100 = 1.875 rem
- 优点:
- 方案统一,完美适配
- 缺点:
- 计算相对复杂
- 注意点:
- 使用rem 适配的时候,需要设置body字体大小,否则会影响em值的大小
5.4.2 方案二:
-
适配细节:
- 将页面设备宽度或 设计稿宽度均等分10份
- 方式一:设备等分: 1rem = 1/10设备宽度
设备等分: 1rem = 1/10设备宽度代码:
<script> function remRefresh() { let clientWidth = document.documentElement.clientWidth; // 将屏幕等分10份 let rem = clientWidth / 10; document.documentElement.style.fontSize = rem + 'px'; // 设置html元素的字体大小,让rem单位生效 document.body.style.fontSize = '12px'; // 设置body的字体,重置一下字体 } window.addEventListener('pageshow', () => { remRefresh() }) // 函数防抖 let timeoutId; window.addEventListener('resize', () => { timeoutId && clearTimeout(timeoutId); timeoutId = setTimeout(() => { remRefresh() }, 300) }) </script>
- 方式二:设计稿等分: 1rem = 1 /10 设计稿宽度
- 设计稿的值直接换算成rem计算 编写的值 rem = 设计稿元素尺寸/设计稿等分10份的值
- 比如:iphone6手机下,设计稿750, 设计稿元素宽高为375的div,设置宽高应该是: 375/(750/10)= 5rem
-
优点:
- 换算简单,完美适配,推荐使用
- 可搭配第三方库自动换算:lib-flexible 、 postcss-plugin-px2rem
-
注意点:
- 使用rem 适配的时候,需要设置body字体大小,否则会影响em值的大小
5.5 vw适配
- 概念:视口单位vw,vh
- 1vw = 1%屏幕宽度
- 1vh = 1%屏幕高度
- 适配细节:
- 需要将设计稿等分100份
- 计算设计稿元素占比多少份
- 比如:750设计稿上375的元素, 375 / 750 /100 = ?vw
- 注意点:
- 只能使用vw适配,不能使用vh
- 有的机型可能宽度一样,但高度不一样,比如:iphone6和iphoneX
- 缺点:
- 换算复杂
6. 移动端事件
6.1 事件分类
- touchstart 元素上触摸开始时触发
- touchmove 元素上触摸移动时触发
- touchend 手指从元素上离开时触发
- touchcancel 触摸被打断时触发,很少使用
6.2 事件绑定方式
nodeEle.ontouchstart = function(e){
console.log('touch start',e)
}
nodeEle.addEventListener('touchstart', function(e){
console.log('touch start',e)
})
6.3 事件点透
6.3.1 click事件在移动端延迟
- 互联网刚兴起的时候,更多是使用PC 的网页,即使在手机上,通常需要使用手指进行缩放来查看页面内容,如何缩放呢?双击放大。、。。
- 浏览器为了区分用户到底是点击还是双击缩放,需要等待,等待得时长大概是300ms,此时用的事件是click事件
- touchstart: 手指一旦触摸屏幕就触发,不需要等待,因此,click事件会有时间差
- 如果设置meta view标签,延迟时间大概是100ms左右
6.3.2 事件点透现象
- 原因: 在移动端touchstart事件结束后会默认触发元素的click事件
- 场景: 如果touch事件隐藏一个遮罩的话,touchstart作用在遮罩后会自动触发click事件,该click事件自动作用在遮罩后方的元素的身上
<style>
* {
margin: 0;
padding: 0;
}
a {
display: block;
height: 100vh;
width: 100vm;
text-align: center;
line-height: 80vh;
}
#mask {
position: fixed;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.2);
width: 100vw;
height: 100vh;
text-align: center;
line-height: 100vh;
}
.btn {
width: 200px;
height: 40px;
background-color: yellowgreen;
color: #fff;
border: none;
outline: none;
}
</style>
<a href="http://www.atguigu.com">点击去尚硅谷</a>
<div id="mask">
<button class="btn">点我关闭遮罩</button>
</div>
let btn = document.querySelector('.btn');
let mask = document.querySelector('#mask');
btn.addEventListener('touchstart', function(){
mask.style.display = 'none';
})
6.3.3 事件点透解决方案
-
方案一:
- 阻止默认行为
btn.addEventListener('touchstart', (e) => { e.preventDefault() mask.style.display = 'none' })
-
方案二:
- 使用click事件代替touch事件
btn.addEventListener('click', () => { mask.style.display = 'none' })
-
方案三:
- 让隐藏的目标元素延迟隐藏,延迟时间大于300ms
btn.addEventListener('touchstart', (e) => { setTimeout(() => { mask.style.display = 'none' }, 300) })
7. 移动端经典问题
7.1 问题: 1px像素边框过粗**
-
场景重现:
设计稿: 宽度750, 设计稿中有个box的div width 375px height 375px
UI设计师:我需要你将这个box的div的边框设置成1个像素,颜色为红色
前端开发工程师: 好的
代码实现: div: border: 1px solid red
UI设计师: 你的效果不对,我要的是1个像素,你设计的边框错粗,大于1个像素
-
问题:
前端工程师代码明明写的是1px的border,UI工程师为什么说边框比1个像素粗呢
-
原因:
- UI工程师需要的是1个物理像素的边框,即在设计稿上占比是1个像素,设计稿总宽是750
- 前端工程师编写的是1px, 比如在iphone6下,因为dpr = 2, 所以1px在同一个方向上 = 2个物理像素
- 因此边框比1物理像素要粗
7.2 解决方案
多媒体查询器,根据dpr不同,对border进行对应的缩放
* {
margin: 0;
padding: 0;
}
.box {
width: 5rem;
height: 5rem;
font-size: 16px;
border: 1px solid red;
}
/* 多媒体查询器 */
@media screen and (-webkit-min-device-pixel-ratio: 2) {
.box {
border: 0.5px solid red;
}
}
@media screen and (-webkit-min-device-pixel-ratio: 3) {
.box {
border: 0.333333px solid red;
}
}