# 参考链接
[链接1](http://caibaojian.com/mobile-knowledge.html)
[链接2](https://www.cnblogs.com/luguiqing/p/7910686.html)
[链接3](https://www.cnblogs.com/superlizhao/p/8729190.html)
[链接4](https://juejin.im/post/5cddf289f265da038f77696c#heading-46)
[TOC]
# viewport
viewport 模板:
忽略将页面中的数字识别为电话号码:
`<meta name="format-detection" content="telephone=no" />`
H5 页面窗口自动调整到设备宽度,并禁止用户缩放页面:
`<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />`
忽略 Android 平台中对邮箱地址的识别:
`<meta name="format-detection" content="email=no" />`
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="telephone=no" name="format-detection">
<meta content="email=no" name="format-detection">
<title>标题</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
这里开始内容
</body>
</html>
```
# 相关概念
来源:[链接4](https://juejin.im/post/5cddf289f265da038f77696c#heading-46)
## 英寸
一般用英寸描述屏幕的物理大小,如电脑显示器的`17`、`22`,手机显示器的`4.8`、`5.7`等使用的单位都是英寸。
需要注意,上面的尺寸都是屏幕对角线的长度:
![](https://box.kancloud.cn/d8b1c4e3b44aaef589cbb9476f6d9f9f_1280x903.png =400x)
英寸(`inch`,缩写为`in`)在荷兰语中的本意是大拇指,一英寸就是指甲底部普通人拇指的宽度。
英寸和厘米的换算:`1英寸 = 2.54 厘米`
## 分辨率
<span style="font-size: 20px;">像素</span>
像素即一个小方块,它具有特定的位置和颜色。
图片、电子屏幕(手机、电脑)就是由无数个具有特定颜色和特定位置的小方块拼接而成。
像素可以作为图片或电子屏幕的最小组成单位。
通常我们所说的分辨率有两种:屏幕分辨率和图像分辨率。
<span style="font-size: 20px;">屏幕分辨率</span>
屏幕分辨率指一个屏幕具体由多少个像素点组成:
![](https://img.kancloud.cn/25/a1/25a1d169356e62a92591f92a63f0658c_1280x889.png )
`iPhone XS Max`和`iPhone SE`的分辨率分别为`2688 x 1242`和`1136 x 640`。这表示手机分别在垂直和水平上所具有的像素点数。
当然分辨率高不代表屏幕就清晰,屏幕的清晰程度还与尺寸有关。
<span style="font-size: 20px;">图像分辨率</span>
我们通常说的`图片分辨率`其实是指图片含有的`像素数`,比如一张图片的分辨率为`800 x 400`。这表示图片分别在垂直和水平上所具有的像素点数为`800`和`400`。
同一尺寸的图片,分辨率越高,图片越清晰。
![](https://box.kancloud.cn/bb0283d7d91c744d8cc56326dfd2dc59_788x133.png)
<span style="font-size: 20px;">PPI</span>
`PPI(Pixel Per Inch)`:每英寸包括的像素数。
`PPI`可以用于描述屏幕的清晰度以及一张图片的质量。
使用`PPI`描述图片时,`PPI`越高,图片质量越高,使用`PPI`描述屏幕时,`PPI`越高,屏幕越清晰。
在上面描述手机分辨率的图片中,我们可以看到:`iPhone XS Max` 和 `iPhone SE`的`PPI`分别为`458`和`326`,这足以证明前者的屏幕更清晰。
由于手机尺寸为手机对角线的长度,我们通常使用如下的方法计算`PPI`:
![](https://box.kancloud.cn/b46a79e3e5b553dd6748339a6782889a_307x83.png)
<span style="font-size: 20px; ">DPI</span>
`DPI(Dot Per Inch)`:即每英寸包括的点数。
这里的点是一个抽象的单位,它可以是屏幕像素点、图片像素点也可以是打印机的墨点。
平时你可能会看到使用`DPI`来描述图片和屏幕,这时的`DPI`应该和`PPI`是等价的,`DPI`最常用的是用于描述打印机,表示打印机每英寸可以打印的点数。
一张图片在屏幕上显示时,它的像素点数是规则排列的,每个像素点都有特定的位置和颜色。
当使用打印机进行打印时,打印机可能不会规则的将这些点打印出来,而是使用一个个打印点来呈现这张图像,这些打印点之间会有一定的空隙,这就是`DPI`所描述的:打印点的密度。
![](https://box.kancloud.cn/d6e006606b6347be499cd8621fa5f90a_624x296.png)
在上面的图像中我们可以清晰的看到,打印机是如何使用墨点来打印一张图像。
所以,打印机的`DPI`越高,打印图像的精细程度就越高,同时这也会消耗更多的墨点和时间。
## 设备独立像素
实际上,上面我们描述的像素都是`物理像素`,即设备上真实的物理单元。
下面我们来看看`设备独立像素`究竟是如何产生的:
智能手机发展非常之快,在几年之前,我们还用着分辨率非常低的手机,比如下面左侧的白色手机,它的分辨率是`320x480`,我们可以在上面浏览正常的文字、图片等等。
但是,随着科技的发展,低分辨率的手机已经不能满足我们的需求了。很快,更高分辨率的屏幕诞生了,比如下面的黑色手机,它的分辨率是`640x940`,正好是白色手机的两倍。
理论上来讲,在白色手机上相同大小的图片和文字,在黑色手机上会被缩放一倍,因为它的分辨率提高了一倍。这样,岂不是后面出现更高分辨率的手机,页面元素会变得越来越小吗?
![](https://img.kancloud.cn/eb/9b/eb9ba996c7e20b126dad7262d9d71d07_1268x960.png)
然而,事实并不是这样的,我们现在使用的智能手机,不管分辨率多高,他们所展示的界面比例都是基本类似的。乔布斯在`iPhone4`的发布会上首次提出了`Retina Display`(视网膜屏幕)的概念,它正是解决了上面的问题,这也使它成为一款跨时代的手机。
![](https://img.kancloud.cn/2c/2a/2c2ad082244b5bc140585376fc66db9c_488x367.png)
在`iPhone4`使用的视网膜屏幕中,把`2x2`个像素当`1`个像素使用,这样让屏幕看起来更精致,但是元素的大小却不会改变。
![](https://box.kancloud.cn/07092530b6d4c6d2e6c85615e94bfd70_926x333.png)
我们必须用一种单位来同时告诉不同分辨率的手机,它们在界面上显示元素的大小是多少,这个单位就是设备独立像素(`Device Independent Pixels`)简称`DIP`或`DP`。上面我们说,列表的宽度为`300`个像素,实际上我们可以说:列表的宽度为`300`个设备独立像素。
<span style="font-size:20px;">设备像素比</span>
设备像素比`device pixel ratio`简称`dpr`,即物理像素和设备独立像素的比值。
在`web`中,浏览器为我们提供了`window.devicePixelRatio`来帮助我们获取`dpr`。
在`css`中,可以使用媒体查询`min-device-pixel-ratio`,区分`dpr`:
```css
@media (-webkit-min-device-pixel-ratio: 2),(min-device-pixel-ratio: 2){ }
```
# 移动端适配方案
## flexible 方案
`flexible`方案是阿里早期开源的一个移动端适配解决方案,引用`flexible`后,我们在页面上统一使用`rem`来布局。
它的核心代码非常简单:
```js
// set 1rem = viewWidth / 10
function setRemUnit () {
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'
}
setRemUnit();
```
`rem`是相对于`html`节点的`font-size`来做计算的。上面的代码中,将`html`节点的`font-size`设置为页面`clientWidth`(布局视口)的`1/10`,即`1rem`就等于页面布局视口的`1/10`,这就意味着我们后面使用的`rem`都是按照页面比例来计算的。
这时,我们只需要将`UI`出的图转换为`rem`即可。
以`iPhone6`为例:布局视口为`375px`,则`1rem = 37.5px`,这时`UI`给定一个元素的宽为`75px`(设备独立像素),我们只需要将它设置为`75 / 37.5 = 2rem`。
## vh、vw 方案
`vh、vw`方案即将视觉视口宽度 `window.innerWidth`和视觉视口高度`window.innerHeight` 等分为 100 份。
上面的`flexible`方案就是模仿这种方案,因为早些时候`vw`还没有得到很好的兼容。
| 单位 | 描述 |
| --- | --- |
| vw| viewpoint width 视窗宽度; 1vw = 视窗宽度的 1% |
| vh| viewpoint height 视窗高度;1vh = 视窗高度的 1% |
| vmin| vw 和 vh 中较小的那个 |
| vmax| vw 和 vh 中较大的那个 |
如果视觉视口为`375px`,那么`1vw = 3.75px`,这时`UI`给定一个元素的宽为`75px`(设备独立像素),我们只需要将它设置为`75 / 3.75 = 20vw`。
这里的比例关系我们也不用自己换算,我们可以使用`PostCSS`的 `postcss-px-to-viewport` 插件帮我们完成这个过程。写代码时,我们只需要根据`UI`给的设计图写`px`单位即可。
当然,没有一种方案是十全十美的,`vw`同样有一定的缺陷:
- `px`转换成`vw`不一定能完全整除,因此有一定的像素差。
- 比如当容器使用`vw`,`margin`采用`px`时,很容易造成整体宽度超过`100vw`,从而影响布局效果。当然我们也是可以避免的,例如使用`padding`代替`margin`,结合`calc()`函数使用等等.
# 1px 问题
为了适配各种屏幕,我们写代码时一般使用设备独立像素来对页面进行布局。
而在设备像素比大于`1`的屏幕上,我们写的`1px`实际上是被多个物理像素渲染,这就会出现`1px`在有些屏幕上看起来很粗的现象。
## 伪类 + transform
基于`media`查询判断不同的设备像素比对线条进行缩放:
```css
.border_1px:before{
content: '';
position: absolute;
top: 0;
height: 1px;
width: 100%;
background-color: #000;
transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px:before{
transform: scaleY(0.5);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.border_1px:before{
transform: scaleY(0.33);
}
}
```
## 使用图片来代替
基于`media`查询判断不同的设备像素比给定不同的`border-image`或`background-image`
```css
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
background: url(../img/1pxline.png) repeat-x left bottom;
background-size: 100% 1px;
}
}
```
## svg
上面我们`border-image`和`background-image`都可以模拟`1px`边框,但是使用的都是位图,还需要外部引入。
借助`PostCSS`的`postcss-write-svg`我们能直接使用`border-image`和`background-image`创建`svg`的`1px`边框:
```css
@svg border_1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
.example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
```
编译后:
```css
.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
```
# 图像模糊问题
## 产生原因
我们平时使用的图片大多数都属于位图(`png、jpg...`),位图由一个个像素点构成的,每个像素都具有特定的位置和颜色值。理论上,位图的每个像素对应在屏幕上使用一个物理像素来渲染,才能达到最佳的显示效果。
而在`dpr > 1`的屏幕上,位图的一个像素可能由多个物理像素来渲染,然而这些物理像素点并不能被准确的分配上对应位图像素的颜色,只能取近似值,所以相同的图片在`dpr > 1`的屏幕上就会模糊:
![](https://box.kancloud.cn/c6b954987f3174e445a5e9aac358e6c0_498x166.png)
## 解决方案
为了保证图片质量,我们应该尽可能让一个屏幕像素来渲染一个图片像素,所以,针对不同`DPR`的屏幕,我们需要展示不同分辨率的图片。
如:在`dpr=2`的屏幕上展示两倍图`(@2x)`,在`dpr=3`的屏幕上展示三倍图`(@3x)`。
![](https://box.kancloud.cn/3b25b503fe80b0619377e73a88f124da_700x330.png)
<span style="font-size: 20px;">media 查询</span>
使用`media`查询判断不同的设备像素比来显示不同精度的图片:
```css
.avatar{
background-image: url(conardLi_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.avatar{
background-image: url(conardLi_2x.png);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.avatar{
background-image: url(conardLi_3x.png);
}
}
```
<span style="font-size: 20px;">image-set</span>
```css
.avatar {
background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
```
<span style="font-size: 20px;">srcset</span>
使用`img`标签的`srcset`属性,浏览器会自动根据像素密度匹配最佳显示图片:
```html
<img src="conardLi_1x.png"
srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
```
<span style="font-size: 20px;">使用 svg</span>
`SVG`的全称是可缩放矢量图(`Scalable Vector Graphics`)。不同于位图的基于像素,`SVG`则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
除了我们手动在代码中绘制`svg`,我们还可以像使用位图一样使用`svg`图片:
```css
<img src="conardLi.svg">
<img src="data:image/svg+xml;base64,[data]">
.avatar {
background: url(conardLi.svg);
}
```
# 触摸事件
## 点透问题
场景:当点击绝对定位元素的时候,下面的元素虽然被遮盖,但也被触发了。
原因:touchstart 早于 touchend 早于click。 亦即 click 的触发是有延迟的,这个时间大概在 300ms 左右,也就是说我们 tap 触发之后蒙层隐藏, 此时 click 还没有触发,300ms 之后由于蒙层隐藏,我们的 click 触发到了下面的 a 链接上。
解决方案:
(1)尽量都使用 touch 事件来替换 click 事件。例如用 touchend 事件(推荐)。
(2)用 fastclick,https://github.com/ftlabs/fastclick
,原理: 在检测到 touchend 事件的时候,通过 DOM 自定义事件立即触发一个 click 事件,并把浏览器在 300ms 之后真正的 click 事件阻止掉
(3)延迟一定的时间(300ms+)来处理事件 (不推荐)
[https://www.cnblogs.com/jianzhixuan/p/6944960.html](https://www.cnblogs.com/jianzhixuan/p/6944960.html)
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令