# 參考鏈接
[鏈接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`等使用的單位都是英寸。
需要注意,上面的尺寸都是屏幕對角線的長度:

英寸(`inch`,縮寫為`in`)在荷蘭語中的本意是大拇指,一英寸就是指甲底部普通人拇指的寬度。
英寸和厘米的換算:`1英寸 = 2.54 厘米`
## 分辨率
<span style="font-size: 20px;">像素</span>
像素即一個小方塊,它具有特定的位置和顏色。
圖片、電子屏幕(手機、電腦)就是由無數個具有特定顏色和特定位置的小方塊拼接而成。
像素可以作為圖片或電子屏幕的最小組成單位。
通常我們所說的分辨率有兩種:屏幕分辨率和圖像分辨率。
<span style="font-size: 20px;">屏幕分辨率</span>
屏幕分辨率指一個屏幕具體由多少個像素點組成:

`iPhone XS Max`和`iPhone SE`的分辨率分別為`2688 x 1242`和`1136 x 640`。這表示手機分別在垂直和水平上所具有的像素點數。
當然分辨率高不代表屏幕就清晰,屏幕的清晰程度還與尺寸有關。
<span style="font-size: 20px;">圖像分辨率</span>
我們通常說的`圖片分辨率`其實是指圖片含有的`像素數`,比如一張圖片的分辨率為`800 x 400`。這表示圖片分別在垂直和水平上所具有的像素點數為`800`和`400`。
同一尺寸的圖片,分辨率越高,圖片越清晰。

<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`:

<span style="font-size: 20px; ">DPI</span>
`DPI(Dot Per Inch)`:即每英寸包括的點數。
這里的點是一個抽象的單位,它可以是屏幕像素點、圖片像素點也可以是打印機的墨點。
平時你可能會看到使用`DPI`來描述圖片和屏幕,這時的`DPI`應該和`PPI`是等價的,`DPI`最常用的是用于描述打印機,表示打印機每英寸可以打印的點數。
一張圖片在屏幕上顯示時,它的像素點數是規則排列的,每個像素點都有特定的位置和顏色。
當使用打印機進行打印時,打印機可能不會規則的將這些點打印出來,而是使用一個個打印點來呈現這張圖像,這些打印點之間會有一定的空隙,這就是`DPI`所描述的:打印點的密度。

在上面的圖像中我們可以清晰的看到,打印機是如何使用墨點來打印一張圖像。
所以,打印機的`DPI`越高,打印圖像的精細程度就越高,同時這也會消耗更多的墨點和時間。
## 設備獨立像素
實際上,上面我們描述的像素都是`物理像素`,即設備上真實的物理單元。
下面我們來看看`設備獨立像素`究竟是如何產生的:
智能手機發展非常之快,在幾年之前,我們還用著分辨率非常低的手機,比如下面左側的白色手機,它的分辨率是`320x480`,我們可以在上面瀏覽正常的文字、圖片等等。
但是,隨著科技的發展,低分辨率的手機已經不能滿足我們的需求了。很快,更高分辨率的屏幕誕生了,比如下面的黑色手機,它的分辨率是`640x940`,正好是白色手機的兩倍。
理論上來講,在白色手機上相同大小的圖片和文字,在黑色手機上會被縮放一倍,因為它的分辨率提高了一倍。這樣,豈不是后面出現更高分辨率的手機,頁面元素會變得越來越小嗎?

然而,事實并不是這樣的,我們現在使用的智能手機,不管分辨率多高,他們所展示的界面比例都是基本類似的。喬布斯在`iPhone4`的發布會上首次提出了`Retina Display`(視網膜屏幕)的概念,它正是解決了上面的問題,這也使它成為一款跨時代的手機。

在`iPhone4`使用的視網膜屏幕中,把`2x2`個像素當`1`個像素使用,這樣讓屏幕看起來更精致,但是元素的大小卻不會改變。

我們必須用一種單位來同時告訴不同分辨率的手機,它們在界面上顯示元素的大小是多少,這個單位就是設備獨立像素(`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`的屏幕上就會模糊:

## 解決方案
為了保證圖片質量,我們應該盡可能讓一個屏幕像素來渲染一個圖片像素,所以,針對不同`DPR`的屏幕,我們需要展示不同分辨率的圖片。
如:在`dpr=2`的屏幕上展示兩倍圖`(@2x)`,在`dpr=3`的屏幕上展示三倍圖`(@3x)`。

<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 基礎
- React + ts
- 樣式設計
- 組件測試
- 圖標解決方案
- Storybook 的使用
- Input 組件
- 在線 mock server
- 打包與發布
- Algorithm
- 排序算法及常見問題
- 劍指 offer
- 動態規劃
- DataStruct
- 概述
- 樹
- 鏈表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 課程實戰記錄
- 服務器
- 操作系統基礎知識
- Linux
- Nginx
- redis
- node.js
- 基礎及原生模塊
- express框架
- node.js操作數據庫
- 《深入淺出 node.js》筆記
- 前半部分
- 后半部分
- 數據庫
- SQL
- 面試題收集
- 智力題
- 面試題精選1
- 面試題精選2
- 問答篇
- 2025面試題收集
- Other
- markdown 書寫
- Git
- LaTex 常用命令
- Bugs