# 移動端開發
### 1. 1px問題如何解決javascript
#### ①僞類 + transform(比較完美)
> 原理是把原先元素的 border 去掉,而後利用 :before 或者 :after 重作 border ,並 transform 的 scale 縮小一半,原先的元素相對定位,新作的 border 絕對定位
##### 單條bordercss
```
.hairlines li{
position: relative;
border:none;
}
.hairlines li:after{
content: '';
position: absolute;
left: 0;
background: #000;
width: 100%;
height: 1px;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
}
```
##### 四條 borderhtml
```
.hairlines li{
position: relative;
margin-bottom: 20px;
border:none;
}
.hairlines li:after{
content: '';
position: absolute;
top: 0;
left: 0;
border: 1px solid #000;
-webkit-box-sizing: border-box;
box-sizing: border-box;
width: 200%;
height: 200%;
-webkit-transform: scale(0.5);
transform: scale(0.5);
-webkit-transform-origin: left top;
transform-origin: left top;
}
```
> 樣式使用的時候,也要結合 JS 代碼,判斷是否 Retina 屏java
```
if(window.devicePixelRatio && devicePixelRatio >= 2){
document.querySelector('ul').className = 'hairlines';
}
```
#### ②淘寶M站是經過 viewport + rem 實現的(適合新項目,方便)
> lib-flexible的庫,而這個庫就是用來解決H5頁面終端適配的。android
---ios
### 2.300ms延時問題
#### 產生緣由
> 用戶在 iOS Safari 裏邊點擊了一個連接。因爲用戶能夠進行雙擊縮放或者雙擊滾動的操做,當用戶一次點擊屏幕以後,瀏覽器並不能馬上判斷用戶是確實要打開這個連接,仍是想要進行雙擊操做。所以,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點擊了屏幕。css3
- [ ] **因而,300 毫秒延遲就這麼誕生了。**
#### 解決方案
1. 禁用縮放web
```
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">
```
> 這個解決方案看似完美,但也帶來一個明顯的缺陷 —— 你必須徹底禁用縮放來達到目的,而從移動端站點的可用性和可訪問性來看,縮放是至關關鍵的一環。你極可能已經遇到過這個問題,即你想要放大一張圖片或者一段字體較小的文本,卻發現沒法完成操做。
2. width=device-width Meta 標籤api
```
<meta name="viewport" content="width=device-width">
```
- [x] **沒有雙擊縮放就沒有 300 毫秒點擊延遲。**
> 這一解決方案的另外一個關鍵之處在於它只是去除了雙擊縮放,但用戶仍可使用雙指縮放 (pinch to zoom)。可見,縮放功能並不是被徹底禁用,也就不存在可用性和可訪問性的問題了。
這是一個使人振奮的方案,很好地提高了移動端站點的性能。固然,主要的問題是 width=device-width 這一優化目前僅被 Chrome 32 所支持。瀏覽器
3.指針事件
> touch-action 的默認值爲 auto,將其置爲 none 便可移除目標元素的 300 毫秒延遲。例如,下面的代碼在 IE10 和 IE11 上移除了全部連接和按鈕元素的點擊延遲。
```
a[href], button {
-ms-touch-action: none; /* IE10 */
touch-action: none; /* IE11 */
}
```
> 你甚至能夠在 <body> 元素上設置 touch-action: none,這就完全禁用了雙擊縮放 (注:這也同時禁用了雙指縮放,所以也會帶來前面討論到的可訪問性和可用性問題。)
#### **目前的解決方案**
**①指針事件的 polyfill**
> 指針事件的 polyfill 比較多,如下列出比較流行的幾個。
- Google 的 Polymer
- 微軟的 HandJS
- @Rich-Harris 的 Points
> 爲避免 300 毫秒點擊延遲,咱們主要關心這些 polyfill 是如何在非 IE 瀏覽器中模擬 CSS touch-action 屬性的,這實際上是一個不小的挑戰。因爲瀏覽器會忽略不被支持的 CSS 屬性,惟一可以檢測開發者是否聲明瞭 touch-action: none 的方法是使用 JavaScript 去請求並解析全部的樣式表。HandJS 也正是這麼作的,但無論是從性能上來看仍是其餘一些複雜的方面,這都會遇到問題。
>
> Polymer 則是經過判斷標籤上的 touch-action 屬性 (attribute),而非 CSS 代碼。下面的代碼展現了 Polymer 是如何在連接上模擬 CSS touch-action: none 屬性的。
```
<a href="http://google.com" touch-action="none">Google</a>
```
**②FastClick**
> FastClick 是 FT Labs 專門爲解決移動端瀏覽器 300 毫秒點擊延遲問題所開發的一個輕量級的庫。簡而言之,FastClick 在檢測到 touchend 事件的時候,會經過 DOM 自定義事件當即觸發一個模擬 click 事件,並把瀏覽器在 300 毫秒以後真正觸發的 click 事件阻止掉。
```
window.addEventListener( "load", function() {
FastClick.attach( document.body );
}, false );
```
> attach() 方法雖可在更具體的元素上調用,直接綁定到 <body> 上能夠確保整個應用都能受益。當 FastClick 檢測到當前頁面使用了基於 <meta> 標籤或者 touch-action 屬性的解決方案時,會靜默退出。能夠說,這是真正的跨平臺方案出來以前一種很好的變通方案。
**③Kendo UI Mobile**
> 最後一點,若是你是 Kendo UI Mobile 的用戶,那你徹底沒必要擔憂上述問題。一個自定義的點擊延遲解決方案已經做爲 Touch widget 的一部分打包好了。這個 touch widget 是一個跨平臺的 API,幫助處理全部平臺的用戶點擊事件,全部的 Kendo UI Mobile 組件都會默認調用它。
### 3.點擊穿透問題
**什麼是點擊穿透?**
> 假如頁面上有兩個元素A和B。B元素在A元素之上。咱們在B元素的touchstart事件上註冊了一個回調函數,該回調函數的做用是隱藏B元素。咱們發現,當咱們點擊B元素,B元素被隱藏了,隨後,A元素觸發了click事件。
> 這是由於在移動端瀏覽器,事件執行的順序是**touchstart > touchend > click**。而click事件有300ms的延遲,當touchstart事件把B元素隱藏以後,隔了300ms,瀏覽器觸發了click事件,可是此時B元素不見了,因此該事件被派發到了A元素身上。若是A元素是一個連接,那此時頁面就會意外地跳轉。
**解決方案**
(1)遮擋
> 因爲 click 事件的滯後性,在這段時間內原來點擊的元素消失了,因而便「穿透」了。所以咱們順着這個思路就想到,能夠給元素的消失作一個fade效果,相似jQuery裏的fadeOut,並設置動畫duration大於300ms,這樣當延遲的 click 觸發時,就不會「穿透」到下方的元素了。
> 一樣的道理,不用延時動畫,咱們還能夠動態地在觸摸位置生成一個透明的元素,這樣當上層元素消失而延遲的click來到時,它點擊到的是那個透明的元素,也不會「穿透」到底下。在必定的timeout後再將生成的透明元素移除
(2)pointer-events
pointer-events是CSS3中的屬性,它有不少取值,有用的主要是auto和none,其餘屬性值爲SVG服務。
|取值 | 含義|
|:---:|:-----:|
auto | 效果和沒有定義 pointer-events 屬性相同,鼠標不會穿透當前層。
none | 元素再也不是鼠標事件的目標,鼠標再也不監聽當前層而去監聽下面的層中的元素。可是若是它的子元素設置了pointer-events爲其它值,好比auto,鼠標仍是會監聽這個子元素的。
- [ ] 所以解決「穿透」的辦法就很簡單,demo以下
```
$('#closePopup').on('tap', function(e){
$('#popupLayer').hide();
$('#bgMask').hide();
$('#underLayer').css('pointer-events', 'none');
setTimeout(function(){
$('#underLayer').css('pointer-events', 'auto');
}, 400);
});
```
(3)fastclick
```
FastClick.attach(document.body);
```
> 今後全部點擊事件都使用click,不會出現「穿透」的問題,而且沒有300ms的延遲。
### 4.移動端兼容問題
1. IOS移動端click事件300ms的延遲相應(上面已有解決方案)
2. 一些狀況下對非可點擊元素(label,span)監聽click事件,iso下不會觸發!
> css增長cursor:pointer就搞定了
3. h5底部輸入框被鍵盤遮擋問題
> h5頁面當輸入框在最底部,點擊軟鍵盤後輸入框會被遮擋。可採用以下方式解決
```
var oHeight = $(document).height(); //瀏覽器當前的高度
$(window).resize(function(){
if($(document).height() < oHeight){
$("#footer").css("position","static");
}else{
$("#footer").css("position","absolute");
}
});
```
4. 不讓 Android 手機識別郵箱
```
<meta content="email=no" name="format-detection" />
```
5. 禁止 iOS 識別長串數字爲電話
```
<meta content="telephone=no" name="format-detection" />
```
6. 禁止 iOS 彈出各類操做窗口
```
-webkit-touch-callout:none
```
7. 消除 transition 閃屏
```
-webkit-transform-style: preserve-3d; /*設置內嵌的元素在 3D 空間如何呈現:保留 3D*/
-webkit-backface-visibility: hidden; /*(設置進行轉換的元素的背面在面對用戶時是否可見:隱藏)*/
```
8. iOS 系統中文輸入法輸入英文時,字母之間可能會出現一個六分之一空格
```
能夠經過正則去掉 this.value = this.value.replace(/\u2006/g, '');
```
9. 禁止ios和android用戶選中文字
```
-webkit-user-select:none
```
10. CSS動畫頁面閃白,動畫卡頓
> 解決方法:
- 1.儘量地使用合成屬性transform和opacity來設計CSS3動畫,不使用position的left和top來定位
- 2.開啓硬件加速
```
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
```
11. fixed定位缺陷
> - ios下fixed元素容易定位出錯,軟鍵盤彈出時,影響fixed元素定位
> - android下fixed表現要比iOS更好,軟鍵盤彈出時,不會影響fixed元素定位
> - ios4下不支持position:fixed
> - 解決方案: 可用iScroll插件解決這個問題
12. localStorage/sessionStorage
> PC端,這兩個API在低版本的IE下是沒有,因此是須要用try..catch包裹的.
> 在移動端,我剛剛開始是不加的,所測試的手機也沒問題.可是如今不少瀏覽器有無痕模式,這個模式下,localStorage相關的API時禁用的.因此使用時,仍是要保證代碼的健壯性
13. 在ios和andriod中,audio元素和video元素在沒法自動播放
> 應對方案:觸屏即播
```
$('html').one('touchstart',function(){
audio.play()
})
```
14. ios下取消input在輸入的時候英文首字母的默認大寫
```
<input type="text" autocapitalize="none">
```
15. 阻止旋轉屏幕時自動調整字體大小
```
html,
body,
form,
fieldset,
p,
div,
h1,
h2,
h3,
h4,
h5,
h6 {
-webkit-text-size-adjust:none;
}
```
16. Input 的placeholder會出現文本位置偏上的狀況
```
input 的placeholder會出現文本位置偏上的狀況:PC端設置line-height等於height可以對齊,
而移動端仍然是偏上,解決是設置line-height:normal
```
17. 往返緩存問題
```
點擊瀏覽器的回退,有時候不會自動執行js,特別是在mobilesafari中。這與往返緩存(bfcache)有關係。
解決方法 :window.onunload = function(){};
```
18. 在移動端修改難看的點擊的高亮效果,iOS和安卓下都有效
```
* {-webkit-tap-highlight-color:rgba(0,0,0,0);}
```
> 不過這個方法在如今的安卓瀏覽器下,只能去掉那個橙色的背景色,點擊產生的高亮邊框仍是沒有去掉,有待解決!
19. ios滾動不流暢
```
overflow: scroll;
-webkit-overflow-scrolling: touch;/* 解決ios滑動不流暢問題 */
```
20. h5移動端,當input輸入框喚起虛擬鍵盤時,fixed定位的元素帶來的佈局問題
- 問題1:H5 web 移動端,input輸入框喚起鍵盤時。fixed定位好的元素跟隨頁面滾動, fixed屬性失效,滿屏任性橫飛。
- 問題2:使用第三方輸入法的ios手機,會出現鍵盤彈出延遲,致使普通佈局的輸入框(input/textarea等) 位置靠下的元素被鍵盤擋住
```
// CSS
.scrollWrapper {
position: absolute;
left: 0;
right: 0;
bottom: 0;
top:0;
}
bottomInput {
position: absolute;
bottom:0;
left:0;
right: 0;
}
// HTML
<body>
<div class="scrollWrapper">
<div class="bottomInput">
<input type="text" placeholder="input"/>
</div>
</div>
</body>
// javascript
// 在輸入框獲取焦點, 鍵盤彈起後, 真的是一行代碼
var interval = setInterval(function() {
document.body.scrollTop = document.body.scrollHeight
}, 100)
```
### 5.css3動畫
```
animation: name duration timing-function delay iteration-count direction fill-mode play-state;
```
**同時要配合** @keyframes
```
@keyframes name {
form {
}
to {
}
}
```
- [x] animation 參數說明
- name
> 與 @keyframes 後 name 一致,動畫名稱
- duration
> 一個動畫持續的事件,要帶單位 s/ms
- timing-function
> 動畫的速度曲線,又稱之爲緩動類型。
> 1. liner 動畫從頭到位速度相同,通常用於平滑的效果
> 1. ease 默認值,逐漸變慢
> 1. ease-in 加速
> 1. ease-out 減速
> 1. ease-in-out 先加速再減速
> 1. cubic-bezier 自定義貝塞爾曲線
> 1. 除此以外還有個重要的值,step-start,能夠實現一幀一幀播放的效果,在特殊場景有更好的效果
- delay
> 動畫延遲執行的時間,須要單位 s/ms
- iteration-count
> 動畫迭代的次數,能夠設置具體的數值,默認值1,使用 infinite 關鍵字能夠實現動畫不間斷播放
- direction
> 動畫的前進方向,默認爲 normal,表明正向播放,使用值 alternate,能夠實現動畫完成時的倒帶效果
- fill-mode
> 填充模式,指的是動畫的每一個週期間的狀態,一般使用默認值 none [這篇文章有很好的解釋](http://www.zhangxinxu.com/wordpress/2013/06/css3-animation-%E7%82%B9%E7%82%B9%E7%82%B9%E7%AD%89%E5%BE%85%E6%8F%90%E7%A4%BA%E6%95%88%E6%9E%9C/)
- play-state
> 控制動畫的運行狀態,默認爲 running,可選值 paused
- [ ] 例子demo
- 外層圓圈
```
.circle {
...
animation: scale 2s ease infinite normal;
}
@keyframes scale {
0% {
transform: scale(0);
opacity: 0;
}
8% {
transform: scale(.5);
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0;
}
}
```
- 內層圓圈
```
.circle1 {
...
animation: scaleout 1s ease-in-out infinite alternate;
}
@keyframes scaleout {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
}
}
```
```
<div>
<h2>動畫1</h2>
<div class="wrap">
<div class="circle"></div>
<div class="circle1"></div>
<span class="text">正在等待司機接單...</span>
</div>
</div>
<div>
<h2>動畫2</h2>
<div class="wrap">
<div class="circle animation2 animation20"></div>
<div class="circle animation2 animation21"></div>
<div class="circle animation2 animation22"></div>
<div class="circle animation2 animation23"></div>
<div class="fixedcirle"></div>
</div>
</div>
// css
body {
padding: 100px;
}
span {
display: inline-block;
}
.wrap {
position: relative;
float: left;
width: 200px;
height: 200px;
margin: 100px;
}
.circle {
position: absolute;
width: 200px;
height: 200px;
background: radial-gradient(#fff, #54bfd0);
border-radius: 50%;
-webkit-animation: scale 2s ease infinite normal;
-moz-animation: scale 2s ease infinite normal;
-o-animation: scale 2s ease infinite normal;
animation: scale 2s ease infinite normal;
}
.circle1 {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
width: 100px;
height: 100px;
border-radius: 50%;
/*background: #076d7d;*/
background: radial-gradient(#fff, #076d7d);
-webkit-animation: scaleout 1s ease-in-out infinite alternate;
-moz-animation: scaleout 1s ease-in-out infinite alternate;
-o-animation: scaleout 1s ease-in-out infinite alternate;
animation: scaleout 1s ease-in-out infinite alternate;
}
.text {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
/* width: 150px;
height: 20px;*/
text-align: center;
line-height: 200px;
}
.animation2 {
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100px;
height: 100px;
margin: auto;
-webkit-animation: animation2 4s linear infinite normal;
-moz-animation: animation2 4s linear infinite normal;
-o-animation: animation2 4s linear infinite normal;
animation: animation2 4s linear infinite normal;
}
.animation20 {
}
@keyframes animation2 {
0% {
/*transform: scale(1);*/
/*opacity: 1;*/
}
100% {
transform: scale(4);
opacity: 0;
}
}
.animation21 {
-webkit-animation-delay: 1s;
-moz-animation-delay: 1s;
-o-animation-delay: 1s;
animation-delay: 1s;
}
.animation22 {
-webkit-animation-delay: 2s;
-moz-animation-delay: 2s;
-o-animation-delay: 2s;
animation-delay: 2s;
}
.animation23 {
-webkit-animation-delay: 3s;
-moz-animation-delay: 3s;
-o-animation-delay: 3s;
animation-delay: 3s;
}
.fixedcirle {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100px;
height: 100px;
margin: auto;
border-radius: 50%;
/*background: radial-gradient(rgba(255, 0, 0, 0), #076d7d);*/
background: #076d7d;
}
@-webkit-keyframes scale {
0% {
-webkit-transform: scale(0);
opacity: 0;
}
8% {
-webkit-transform: scale(.5);
opacity: 1;
}
100% {
-webkit-transform: scale(2);
opacity: 0;
}
}
@-moz-keyframes scale {
0% {
-moz-transform: scale(0);
opacity: 0;
}
8% {
-moz-transform: scale(.5);
opacity: 1;
}
100% {
-moz-transform: scale(2);
opacity: 0;
}
}
@-o-keyframes scale {
0% {
-o-transform: scale(0);
opacity: 0;
}
8% {
-o-transform: scale(.5);
opacity: 1;
}
100% {
-o-transform: scale(2);
opacity: 0;
}
}
@keyframes scale {
0% {
transform: scale(0);
opacity: 0;
}
8% {
transform: scale(.5);
opacity: 1;
}
100% {
transform: scale(2);
opacity: 0;
}
}
@-webkit-keyframes scaleout {
0% {
-webkit-transform: scale(1);
}
100% {
-webkit-transform: scale(2);
/*opacity: 0.5;*/
}
}
@-moz-keyframes scaleout {
0% {
-moz-transform: scale(1);
}
100% {
-moz-transform: scale(2);
/*opacity: 0.5;*/
}
}
@-o-keyframes scaleout {
0% {
-o-transform: scale(1);
}
100% {
-o-transform: scale(2);
/*opacity: 0.5;*/
}
}
@keyframes scaleout {
0% {
transform: scale(1);
}
100% {
transform: scale(2);
/*opacity: 0.5;*/
}
}
```
### 6.丟幀問題
> 迴流與重繪的知識: 瀏覽器會解析三個東西:HTML、Javascript、CSS。
> 瀏覽器首先會根據HTML生成DOM Tree,其次會根據CSS生成CSS Rule Tree,javascript能夠經過DOM API與CSS API操做DOM Tree與CSS Rule Tree,從而引發頁面變化。
>
> 瀏覽器解析結束會經過DOM Tree與CSS Rule Tree造成render tree,只有display不爲none的元素纔會造成render Tree,render Tree造成後瀏覽器會調用GUI繪製頁面,在此以前作的一件事情即是layout或者說reflow。上面的描述簡單而言能夠分爲如下流程:
>
> l 生成DOM樹
>
> l 計算CSS樣式
>
> l 構建render tree
>
> l reflow,定位元素位置大小
>
> l 繪製頁面
>
> 在這個過程當中,**如果javascript動態改變DOM Tree便會引發reflow**
> 頁面中的元素改變,只要不影響尺寸,好比只是顏色改變只會引發repaint不會引發迴流
>
> 不然,reflow不可避免,這個時候便須要從新計算造成render Tree
> reflow耗用的系統資源較大,**DOM Tree** 中受到影響的節點皆會reflow,而後影響其子節點最壞的狀況是全部節點reflow,該問題引起的現象即是低性能的電腦風扇不停的轉,手機變得很熱,而且很是耗電,如下操做可能引發reflow
>
> l 操做dom結構
>
> l 動畫
>
> l DOM樣式修改
>
> l 獲取元素尺寸的API
#### 從新認識Timeline
[詳細講解Timeline](http://www.cnblogs.com/yexiaochai/p/4314260.html)

#### 丟幀
> 瀏覽器一次的刷新約16ms
> 若是中間有一次的操做好比渲染的時間大於了16ms而致使瀏覽器沒有來得及繪製,那麼那次的操做便失效了,這個就是所謂的丟幀。
### 7.移動端性能優化

[使用requestAnimationFrame()優化JavaScript動畫性能](http://www.webhek.com/post/using-requestanimationframe.html)