移動端經驗速遞

xiangzhihong發表於2018-07-27

概要

本文件針對移動前端開發,包括 Hybrid 裡面的web頁面,非 Native 應用,適用於iOS6.0+, Android4.0+,是多年積累的經驗,分享給大家。

目錄

相容性

CSS偽類:active

如果你想使用元素的偽類來實現 按下啟用 狀態,那麼你需要知道以下問題:

  • iOS上的幾乎任何瀏覽器,定義元素的偽類 :active 都是無效;
  • Android上,Android BrowserChrome 都支援偽類 :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佈局不生效

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 作為專案中的單位了。但是遺憾的是,在 ChromeOpera 上,如果我們給 body 元素應用了 rem,那麼這個取值將會計算錯誤。

假設我們有如下程式碼:

html {
  font-size: 62.5%;
}
body {
  font-size: 1.4rem;
}
複製程式碼

因為大部分瀏覽器的預設字號都是 16px,所以 html 的字號計算出來應該是 16px * 62.5% = 10px。此時,我們預期 bodyfont-size14px。然而實際情況與我們想象的不太一樣,最終 body 的計算值並不是 14px,它忽略了 html 的定義,而是直接使用了瀏覽器的預設字號作為參照。於是最終計算值為:16px * 1.4rem = 22.4px。測至 chrome 45.0Opera 33.0 仍然存在這個問題,不過 chrome 49.0Opera 37.0 看起來已經被修復了。

為了有效的繞過這個問題,並且實現相同的效果,我們可以將程式碼修改如下:

html {
  font-size: 62.5%;
}
body {
  font-size: 1.4em;
}
複製程式碼

由於 bodyhtml 的直接子元素,所以此時對 body 使用 emrem 的效果是相同的。

不要對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;
}
複製程式碼

快速回彈滾動

  1. 早期的時候,移動端的瀏覽器都不支援非body元素的滾動條,所以一般都藉助 iScroll;
  2. Android 3.0/iOS解決了非body元素的滾動問題,但滾動條不可見,同時iOS上只能通過2個手指進行滾動;
  3. Android 4.0解決了滾動條不可見及增加了快速回彈滾動效果,不過隨後這個特性又被移除;
  4. 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.0Android Browser5.0 也開始支援新增到主螢幕了,但並沒有提供相應的定義標題的方式,所以如果你想統一 iOSAndroid 平臺定義 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的圖示。

實際情況下,大部分智慧手機都接近或者已經達到視網膜屏質量,所以如果想省事的話,可以分別為 iPhoneiPad 定義一種高質量的 icon 即可。

該方案在 iOSAndroid5.0+ 上都通用。

新增到主螢幕時隱藏位址列和狀態列(即全屏)

當我們將一個網頁新增到主螢幕時,會更希望它能有像 App 一樣的表現,沒有位址列和狀態列全屏顯示,程式碼如下:

<meta name="apple-mobile-web-app-capable" content="yes" />
複製程式碼

該方案在 iOSAndroid5.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

可能還有其他型別的數字也會被識別,但在具體的業務場景中,有些時候這是不必須的,所以你可以關閉電話自動識別,然後在需要撥號的地方,開啟電話撥出和簡訊功能。

  1. 關閉電話號碼識別:
<meta name="format-detection" content="telephone=no" />
複製程式碼
  1. 開啟撥打電話功能:
<a href="tel:123456">123456</a>
複製程式碼
  1. 開啟傳送簡訊功能:
<a href="sms:123456">123456</a>
複製程式碼

郵箱地址識別

Android (iOS不會)上,瀏覽器會自動識別看起來像郵箱地址的字串,不論有你沒有加上郵箱連結,當你在這個字串上長按,會彈出發郵件的提示。

  1. 關閉郵箱地址識別:
<meta name="format-detection" content="email=no" />
複製程式碼
  1. 開啟郵件傳送:
<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'

效能優化

待續啊待續。。。

相關文章