概要
本文件針對移動前端開發,包括 Hybrid
裡面的web頁面,非 Native
應用,適用於iOS6.0+
, Android4.0+
,是多年積累的經驗,分享給大家。
目錄
相容性
CSS偽類:active
如果你想使用元素的偽類來實現 按下啟用
狀態,那麼你需要知道以下問題:
- iOS上的幾乎任何瀏覽器,定義元素的偽類
:active
都是無效; - Android上,
Android Browser
和Chrome
都支援偽類:active
,其它第三方瀏覽器有部分不支援; - 定義了
:active
並且當前瀏覽器環境支援,當手指在滾動或者無意間的劃過時,:active
狀態都會被啟用;
為了規避上述所有的問題,如果需要
按下啟用
狀態,推薦使用js
新增一個className
清除輸入框內陰影
iOS上的幾乎任何瀏覽器輸入框(input, textarea)預設有內部陰影,但無法使用 box-shadow
來清除,如果不需要陰影,可以這樣關閉:
input,
textarea {
/* 方法1: 去掉邊框 */
border: 0;
/* 方法2: 邊框色透明 */
border-color: transparent;
/* 方法3: 重置輸入框預設外觀 */
-webkit-appearance: none;
appearance: none;
}
複製程式碼
修正iOS輸入框禁用文字色
在 iOS
上,如果將輸入框 disabled
,此時輸入框內的文字顏色將比 color
所定義的要淺,並且無法通過給輸入框的偽類 :disabled
定義 color
來修正。
想解決這個問題,可以作如下設定,定義輸入框的文字填充色:
input:disabled {
-webkit-text-fill-color: #000;
}
複製程式碼
需要注意的是,在 Mac
上的 Safari
也有同樣的問題。
Samsung S4圓角Bug
Samsung S4
手機在 Android Browser4.4.2
上(其他版本未測),如果你使用了 border-radius
,並且使用了 -webkit-transform
屬性,當使用了 translatez
或者 translate3d
值,圓角會出現問題:
.test {
border: 2px solid red;
width: 50px;
height: 50px;
border-radius: 50%;
background-color: gray;
box-shadow: 0 2px 5px rgba(0, 0, 0, .3);
-webkit-transform: translate(0, 0) translatez(0);
transform: translate(0, 0) translatez(0);
}
複製程式碼
<div class="test"></div>
複製程式碼
如上程式碼,-webkit-transform: translate(0, 0) translatez(0)
將會導致圓角無法包裹住 background-color
。
當然,-webkit-transform: translate3d(0, 0, 0)
也是一樣的,所以如果你的某個場景是這樣的,那麼可以直接使用 -webkit-transform: translate(0, 0)
來避免這個問題。
邊框圓角致背景溢位
在紅米和OPPO等手機某些版本的 Android Webview
中,如果一個元素定義了 border
+ border-radius
,這時如果該元素有背景,那麼背景將會溢位圓角之外。
之所以會出現這個問題:其主要原因是因為CSS對背景裁剪(background-clip)有不同的處理方式,通常它可以是 border-box | padding-box | content-box
這3種方式。
瀏覽器的預設裁減方式是 border-box
,即溢位 border
之外的背景都將被裁減。
對於上述無法裁減邊框之外背景的手機,將值定義為 padding-box | content-box
都能fix這問題,不過更推薦使用 padding-box
。因為使用 content-box
,如果定義了 padding
不為 0
,背景將無法鋪滿元素。
一個失敗的圓(圓角)
在移動平臺上開發時,用CSS畫一個圓很簡單,只需要一句程式碼:
.circle {
border-radius: 50%;
}
複製程式碼
不過,在 Android Browser2.*
上,這個定義將會失效,而顯示為預設的矩形。
因為 Android Browser2.*
不支援以 百分比
作為 border-radius
的值,所以如果你需要相容 Android Browser2.*
,那麼你可以這樣:
.circle {
width: 10rem;
height: 10rem;
border-radius: 5rem;
}
複製程式碼
如果你覺得這樣定義不夠靈活,想懶一點,那麼其實可以給 border-radius
預設一個比較大的值,比如 100rem
,用以避免當元素的尺寸變了,圓角半徑也得跟著變,除非元素的尺寸超出了你預設的閥值。
不要使用偽元素動畫
有的時候你可能會為了減少頁面上的DOM數,而使用偽元素。但如果你想給偽元素增加 animation
或者 transition
動畫,這時候會碰上支援性問題。
如果你的專案需要支援以下系統版本,那麼建議直接使用真實元素:
iOS Safari6.1及以下
Android Browser4.1.*及以下
,包括一些深度定製的系統,比如:- 魅族 - Flyme OS 4.1.1.1C及以下(比這高的版本尚未測試過)- 我們國產能別這麼坑麼(安卓版本為4.4.4的魅族MX4 pro)
:checked與兄弟選擇符一起使用的bug
在 Android Browser4.2.*及以下
(可能版本稍有出入)(包括坑爹的Flyme),如果你有這樣一段程式碼:
input:checked ~ .test {
background-color: #f00;
}
複製程式碼
那麼將無任何效果,如果你想使得上述程式碼生效,有2種方式:
第一種,使用 input
和 +
進行啟用:
html + input {}
input:checked ~ .test {
background-color: #f00;
}
複製程式碼
只要存在 input
和 +
選擇符配合使用的選擇器(空規則集也行)即可使得上述程式碼啟用生效。
第二種,直接換成 +
:
input:checked + .test {
background-color: #f00;
}
複製程式碼
為什麼flex佈局不生效
- 使用塊級元素作為
flex items(flex子項)
;
Android Browser4.3及以下
,iOS Safari6.1及以下
的flex子項
需要使用塊級元素,在這些版本之上還可以使用行內塊元素
在這些版本中,如果你發現flex子項之間出現了間隙,或者在未定義換行的情況下子項自身抑或子項之間換行了,或者出現了其它不正常的情況,那麼仔細看一下flex子項可能是使用了行內級元素;
- 當橫向佈局時,給
flex子項
子項定義width
為非auto
的值
Android Browser4.3及以下
,iOS Safari6.1及以下
的flex子項
如果沒有顯式的定義width
為非auto
的值,那麼子項分配父元素剩餘空間時將會不符合標準預期;
- 當縱向佈局時,給
flex子項
子項定義height
為非auto
的值
Android Browser4.3及以下
,iOS Safari6.1及以下
的flex子項
如果沒有顯式的定義height
為非auto
的值,那麼子項分配父元素剩餘空間時將會不符合標準預期;
為什麼小於12px字號不生效
如果你是從pc
開發轉到移動平臺的,或者應該記得在pc
端,Chrome
及後來加入Webkit陣營的Opera
都不支援頁面字號小於12px
,當然你可以通過更改瀏覽器設定來改變這一情況,然後這並沒有什麼卵用,不是麼?
不幸的是,在移動端這個限制也依然存在,在Android Chrome
上(包括部分版本上的Android Browser
),仍然不支援小於12px的字號(測試至Android5.0.2, Chrome46),除此之外,其他瀏覽器包括iOS上眾瀏覽器都能夠很好的支援超小字型。
所以,如果希望你的程式足夠安全,儘量不要定義小於12px的字號,或者換一種方式來實現。
題外話:假設你的專案使用了
rem
,那麼不要使用10
作為換算因子,原因也如上
chrome中body使用rem失效
我知道很多人已經開始使用 rem
作為專案中的單位了。但是遺憾的是,在 Chrome
和 Opera
上,如果我們給 body
元素應用了 rem
,那麼這個取值將會計算錯誤。
假設我們有如下程式碼:
html {
font-size: 62.5%;
}
body {
font-size: 1.4rem;
}
複製程式碼
因為大部分瀏覽器的預設字號都是 16px
,所以 html
的字號計算出來應該是 16px * 62.5% = 10px
。此時,我們預期 body
的 font-size
為 14px
。然而實際情況與我們想象的不太一樣,最終 body
的計算值並不是 14px
,它忽略了 html
的定義,而是直接使用了瀏覽器的預設字號作為參照。於是最終計算值為:16px * 1.4rem = 22.4px
。測至 chrome 45.0
和 Opera 33.0
仍然存在這個問題,不過 chrome 49.0
和 Opera 37.0
看起來已經被修復了。
為了有效的繞過這個問題,並且實現相同的效果,我們可以將程式碼修改如下:
html {
font-size: 62.5%;
}
body {
font-size: 1.4em;
}
複製程式碼
由於 body
是 html
的直接子元素,所以此時對 body
使用 em
與 rem
的效果是相同的。
不要對html設定百分比字號
很嚴肅的和大家說,如果你在使用 rem
這項技術,那麼儘可能不要對html設定百分比大小的字號。比如這樣的:
html {
font-size: 62.5%;
}
複製程式碼
由於大部分瀏覽器的預設字號是 16px
,所以能計算出 html
的字號實際為 10px
。我們在 為什麼小於12px字號不生效 中說過,部分瀏覽器會將小於 12px
的字變成 12px
來顯示。那麼此時,在這些瀏覽器下,如果我做了這樣的定義:
.demo {
width: 10rem;
}
複製程式碼
你預期得到 10px * 10rem = 100px
,但實際上得到的確是 12px * 10rem = 120px
。這是非常大的錯誤,我們應當儘量避免。
與此同時,雖然大部分瀏覽器的預設字號是 16px
,但仍然有使用其它預設值的瀏覽器,比如我依稀記得 firefox
使用了 15px
。而且最重要的是,使用者是可以改變瀏覽器預設字號的,所以你認為的可能並不是你認為的。
所以不要對html設定百分比字號,尤其是不要對它使用計算值比 12px
小的字號。我推薦大家這樣做:
html {
font-size: 100px;
}
複製程式碼
以 100px
作為因子,計算也非常方便。如果你想要設定一個元素的寬度是 20px
,那麼只需要:
.demo {
width: .2rem;
}
複製程式碼
經驗
禁止儲存或拷貝影象
通常當你在手機或者pad上長按影象 img
,會彈出選項 儲存影象
或者 拷貝影象
,如果你不想讓使用者這麼操作,那麼你可以通過以下方法來禁止:
img {
-webkit-touch-callout: none;
}
複製程式碼
需要注意的是,該方法只在
iOS
上有效。
取消touch高亮
在移動裝置上,所有設定了偽類 :active
的元素,預設都會在啟用狀態時,顯示高亮框,如果不想要這個高亮,那麼你可以通過以下方法來禁止:
.xxx {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
複製程式碼
禁止選中內容
如果你不想使用者可以選中頁面中的內容,那麼你可以禁掉:
html {
-webkit-user-select: none;
}
複製程式碼
快速回彈滾動
- 早期的時候,移動端的瀏覽器都不支援非body元素的滾動條,所以一般都藉助 iScroll;
- Android 3.0/iOS解決了非body元素的滾動問題,但滾動條不可見,同時iOS上只能通過2個手指進行滾動;
- Android 4.0解決了滾動條不可見及增加了快速回彈滾動效果,不過隨後這個特性又被移除;
- iOS從5.0開始解決了滾動條不可見及增加了快速回彈滾動效果
在iOS上如果你想讓一個元素擁有像 Native 的滾動效果,你可以這樣做:
.xxx {
overflow: auto; /* auto | scroll */
-webkit-overflow-scrolling: touch; /* 該規則可能引起iOS UIWebView崩潰 */
}
複製程式碼
設定新增到主螢幕的Web App標題
iOS Safari
允許使用者將一個網頁新增到主螢幕然後像 App
一樣來操作它。我們知道每個 App
下方都會有一個名字,iOS Safari
提供了一個私有的 meta
來定義這個名字,程式碼如下:
<meta name="apple-mobile-web-app-title" content="Web App名稱" />
複製程式碼
Android Chrome31.0
,Android Browser5.0
也開始支援新增到主螢幕了,但並沒有提供相應的定義標題的方式,所以如果你想統一 iOS
和 Android
平臺定義 Web app 名稱的方式,可以使用 title
標籤來定義,程式碼如下:
<title>Web App名稱</title>
複製程式碼
但如果你想要網頁標題和App名字不一樣的話,那就只有iOS才行。
設定新增到主螢幕的Web App圖示
當我們將一個網頁新增到主螢幕時,除了會需要設定標題之外,肯定還需要能夠自定義這個App的圖示,程式碼如下:
<link rel="apple-touch-icon" href="app.png" />
複製程式碼
不過該方案,在擬物設計的 iOS6及以前
會自動為圖示新增一層高光效果,iOS7
已使用了扁平化設計,所以如果使用該方案,在不同版本下得到的效果會不一致。
當然,你也可以使用原圖作為App的圖示,用以保持各平臺表現一致,程式碼如下:
<link rel="apple-touch-icon-precomposed" href="app.png" />
複製程式碼
如果你想給不同的裝置定不同的圖示,可以通過 sizes
屬性來定義,形如:
<link rel="apple-touch-icon" sizes="76x76" href="ipad.png@1x" />
<link rel="apple-touch-icon" sizes="120x120" href="iphone-retina@2x.png" />
<link rel="apple-touch-icon" sizes="152x152" href="ipad-retina@2x.png" />
<link rel="apple-touch-icon" sizes="180x180" href="iphone-retina@3x.png" />
複製程式碼
規則如下:
- 如果沒有跟相應裝置推薦尺寸一致的圖示,會優先選擇比推薦尺寸大並且最接近推薦尺寸的圖示。
- 如果沒有比推薦尺寸大的圖示,會優先選擇最接近推薦尺寸的圖示。
- 如果有多個圖示符合推薦尺寸,會優先選擇包含關鍵字precomposed的圖示。
實際情況下,大部分智慧手機都接近或者已經達到視網膜屏質量,所以如果想省事的話,可以分別為 iPhone
和 iPad
定義一種高質量的 icon
即可。
該方案在 iOS
和 Android5.0+
上都通用。
新增到主螢幕時隱藏位址列和狀態列(即全屏)
當我們將一個網頁新增到主螢幕時,會更希望它能有像 App
一樣的表現,沒有位址列和狀態列全屏顯示,程式碼如下:
<meta name="apple-mobile-web-app-capable" content="yes" />
複製程式碼
該方案在 iOS
和 Android5.0+
上都通用。
新增到主螢幕時設定系統頂欄顏色
當我們將一個網頁新增到主螢幕時,還可以對 系統顯示手機訊號、時間、電池的頂部狀態列
顏色進行設定,前提是開啟了:
<meta name="apple-mobile-web-app-capable" content="yes" />
複製程式碼
有了這個前提,你可以通過下面的方式來進行定義:
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
複製程式碼
content只有3個固定值可選:default | black | black-translucent
- 如果設定為
default
,狀態列將為正常的,即白色,網頁從狀態列以下開始顯示; - 如果設定為
black
,狀態列將為黑色,網頁從狀態列以下開始顯示; - 如果設定為
black-translucent
,狀態列將為灰色半透明,網頁將充滿整個螢幕,狀態列會蓋在網頁之上;
該設定只在 iOS
上有效。
電話號碼識別
在 iOS Safari
(其他瀏覽器和Android均不會)上會對那些看起來像是電話號碼的數字處理為電話連結,比如:
- 7位數字,形如:1234567
- 帶括號及加號的數字,形如:(+86)123456789
- 雙連線線的數字,形如:00-00-00111
- 11位數字,形如:13800138000
可能還有其他型別的數字也會被識別,但在具體的業務場景中,有些時候這是不必須的,所以你可以關閉電話自動識別,然後在需要撥號的地方,開啟電話撥出和簡訊功能。
- 關閉電話號碼識別:
<meta name="format-detection" content="telephone=no" />
複製程式碼
- 開啟撥打電話功能:
<a href="tel:123456">123456</a>
複製程式碼
- 開啟傳送簡訊功能:
<a href="sms:123456">123456</a>
複製程式碼
郵箱地址識別
在 Android
(iOS不會)上,瀏覽器會自動識別看起來像郵箱地址的字串,不論有你沒有加上郵箱連結,當你在這個字串上長按,會彈出發郵件的提示。
- 關閉郵箱地址識別:
<meta name="format-detection" content="email=no" />
複製程式碼
- 開啟郵件傳送:
<a href="mailto:dooyoe@gmail.com">dooyoe@gmail.com</a>
複製程式碼
如果想同時關閉電話和郵箱識別,可以把它們寫到一條 meta 內,程式碼如下:
<meta name="format-detection" content="telephone=no,email=no" />
複製程式碼
關閉iOS鍵盤首字母自動大寫
在iOS中,預設情況下鍵盤是開啟首字母大寫的功能的,如果業務不想出現首字母大寫,可以這樣:
<input type="text" autocapitalize="off" />
複製程式碼
關閉iOS輸入自動修正
在iOS中,預設輸入法會開啟自動修正輸入內容的功能,如果不需要的話,可以這樣:
<input type="text" autocorrect="off" />
複製程式碼
禁止文字縮放
當移動裝置橫豎屏切換時,文字的大小會重新計算,進行相應的縮放,當我們不需要這種情況時,可以選擇禁止:
html {
-webkit-text-size-adjust: 100%;
}
複製程式碼
需要注意的是,PC端的該屬性已經被移除,該屬性在移動端要生效,必須設定 `meta viewport'
效能優化
待續啊待續。。。