一、移動(dòng)端300ms點(diǎn)擊延遲
一般情況下磺送,如果沒有經(jīng)過特殊處理,移動(dòng)端瀏覽器在派發(fā)點(diǎn)擊事件的時(shí)候灿意,通常會(huì)出現(xiàn)300ms左右的延遲估灿。也就是說,當(dāng)我們點(diǎn)擊頁面的時(shí)候移動(dòng)端瀏覽器并不是立即作出反應(yīng)缤剧,而是會(huì)等上一小會(huì)兒才會(huì)出現(xiàn)點(diǎn)擊的效果馅袁。在移動(dòng)WEB興起的初期,用戶對(duì)300ms的延遲感覺不明顯荒辕。但是汗销,隨著用戶對(duì)交互體驗(yàn)的要求越來越高,現(xiàn)今抵窒,移動(dòng)端300ms的點(diǎn)擊延遲逐漸變得明顯而無法忍受大溜。
那么,移動(dòng)端300ms的點(diǎn)擊延遲是怎么來的呢估脆?
問題由來
這要追溯至 2007 年初钦奋。蘋果公司在發(fā)布首款 iPhone 前夕,遇到一個(gè)問題:當(dāng)時(shí)的網(wǎng)站都是為大屏幕設(shè)備所設(shè)計(jì)的疙赠。于是蘋果的工程師們做了一些約定付材,應(yīng)對(duì) iPhone 這種小屏幕瀏覽桌面端站點(diǎn)的問題。
這當(dāng)中最出名的圃阳,當(dāng)屬雙擊縮放(double tap to zoom)厌衔,這也是會(huì)有上述 300 毫秒延遲的主要原因。
雙擊縮放捍岳,顧名思義富寿,即用手指在屏幕上快速點(diǎn)擊兩次睬隶,iOS 自帶的 Safari 瀏覽器會(huì)將網(wǎng)頁縮放至原始比例。 那么這和 300 毫秒延遲有什么聯(lián)系呢页徐? 假定這么一個(gè)場(chǎng)景苏潜。用戶在 iOS Safari 里邊點(diǎn)擊了一個(gè)鏈接。由于用戶可以進(jìn)行雙擊縮放或者雙擊滾動(dòng)的操作变勇,當(dāng)用戶一次點(diǎn)擊屏幕之后恤左,瀏覽器并不能立刻判斷用戶是確實(shí)要打開這個(gè)鏈接,還是想要進(jìn)行雙擊操作搀绣。因此飞袋,iOS Safari 就等待 300 毫秒,以判斷用戶是否再次點(diǎn)擊了屏幕链患。 鑒于iPhone的成功巧鸭,其他移動(dòng)瀏覽器都復(fù)制了 iPhone Safari 瀏覽器的多數(shù)約定,包括雙擊縮放麻捻,幾乎現(xiàn)在所有的移動(dòng)端瀏覽器都有這個(gè)功能纲仍。之前人們剛剛接觸移動(dòng)端的頁面,在欣喜的時(shí)候往往不會(huì)care這個(gè)300ms的延時(shí)問題芯肤,可是如今touch端界面如雨后春筍,用戶對(duì)體驗(yàn)的要求也更高压鉴,這300ms帶來的卡頓慢慢變得讓人難以接受崖咨。
也就是說,移動(dòng)端瀏覽器會(huì)有一些默認(rèn)的行為油吭,比如雙擊縮放击蹲、雙擊滾動(dòng)。這些行為婉宰,尤其是雙擊縮放歌豺,主要是為桌面網(wǎng)站在移動(dòng)端的瀏覽體驗(yàn)設(shè)計(jì)的。而在用戶對(duì)頁面進(jìn)行操作的時(shí)候心包,移動(dòng)端瀏覽器會(huì)優(yōu)先判斷用戶是否要觸發(fā)默認(rèn)的行為类咧。
那有什么辦法可以解決這個(gè)問題呢?
瀏覽器開發(fā)商的解決方案
瀏覽器開發(fā)商要對(duì)移動(dòng)端瀏覽器本身的設(shè)計(jì)進(jìn)行改善蟹腾,以提供長(zhǎng)遠(yuǎn)的解決方案痕惋。
目前,瀏覽器開發(fā)商的解決方案主要有一下三種方案:
方案一:禁用縮放
當(dāng)HTML文檔頭部包含如下meta
標(biāo)簽時(shí):
<meta name="viewport" content="user-scalable=no">
<meta name="viewport" content="initial-scale=1,maximum-scale=1">
表明這個(gè)頁面是不可縮放的娃殖,那雙擊縮放的功能就沒有意義了值戳,此時(shí)瀏覽器可以禁用默認(rèn)的雙擊縮放行為并且去掉300ms的點(diǎn)擊延遲。
這個(gè)方案有一個(gè)缺點(diǎn)炉爆,就是必須通過完全禁用縮放來達(dá)到去掉點(diǎn)擊延遲的目的堕虹,然而完全禁用縮放并不是我們的初衷卧晓,我們只是想禁掉默認(rèn)的雙擊縮放行為,這樣就不用等待300ms來判斷當(dāng)前操作是否是雙擊赴捞。但是通常情況下逼裆,我們還是希望頁面能通過雙指縮放來進(jìn)行縮放操作,比如放大一張圖片螟炫,放大一段很小的文字波附。
方案二:更改默認(rèn)的視口寬度
一開始,為了讓桌面站點(diǎn)能在移動(dòng)端瀏覽器正常顯示昼钻,移動(dòng)端瀏覽器默認(rèn)的視口寬度并不等于設(shè)備瀏覽器視窗寬度掸屡,而是要比設(shè)備瀏覽器視窗寬度大,通常是980px然评。我們可以通過以下標(biāo)簽來設(shè)置視口寬度為設(shè)備寬度仅财。
<meta name="viewport" content="width=device-width">
因?yàn)殡p擊縮放主要是用來改善桌面站點(diǎn)在移動(dòng)端瀏覽體驗(yàn)的,而隨著響應(yīng)式設(shè)計(jì)的普及碗淌,很多站點(diǎn)都已經(jīng)對(duì)移動(dòng)端坐過適配和優(yōu)化了盏求,這個(gè)時(shí)候就不需要雙擊縮放了,如果能夠識(shí)別出一個(gè)網(wǎng)站是響應(yīng)式的網(wǎng)站亿眠,那么移動(dòng)端瀏覽器就可以自動(dòng)禁掉默認(rèn)的雙擊縮放行為并且去掉300ms的點(diǎn)擊延遲碎罚。如果設(shè)置了上述meta
標(biāo)簽,那瀏覽器就可以認(rèn)為該網(wǎng)站已經(jīng)對(duì)移動(dòng)端做過了適配和優(yōu)化纳像,就無需雙擊縮放操作了荆烈。
這個(gè)方案相比方案一的好處在于,它沒有完全禁用縮放竟趾,而只是禁用了瀏覽器默認(rèn)的雙擊縮放行為憔购,但用戶仍然可以通過雙指縮放操作來縮放頁面。
方案三:CSS touch-action
網(wǎng)上很多文章把這個(gè)方案歸結(jié)為指針事件岔帽,這令我很疑惑玫鸟。
以我的理解來看,指針事件的提出并不是為了解決300ms點(diǎn)擊延遲的犀勒,而是為了使用一個(gè)單獨(dú)的事件模型屎飘,對(duì)鼠標(biāo)、觸摸贾费、觸控等多種輸入類型進(jìn)行統(tǒng)一的處理枚碗。也就是說,移動(dòng)瀏覽器不用再為不同的輸入設(shè)備設(shè)計(jì)不同的事件铸本,網(wǎng)頁的開發(fā)者也不用再為不同輸入類型的設(shè)備寫不同的事件響應(yīng)代碼肮雨,而是通過統(tǒng)一的指針事件就可以開發(fā)出跨不同輸入類型終端的應(yīng)用。
跟300ms點(diǎn)擊延遲相關(guān)的箱玷,是touch-action
這個(gè)CSS屬性怨规。這個(gè)屬性指定了相應(yīng)元素上能夠觸發(fā)的用戶代理(也就是瀏覽器)的默認(rèn)行為陌宿。如果將該屬性值設(shè)置為touch-action: none
,那么表示在該元素上的操作不會(huì)觸發(fā)用戶代理的任何默認(rèn)行為波丰,就無需進(jìn)行300ms的延遲判斷壳坪。
而設(shè)置這個(gè)CSS屬性與否,指針事件應(yīng)該都是可以工作的掰烟。所以爽蝴,網(wǎng)上的文章令我很疑惑,希望有大神能給我指示~ 纫骑。蝎亚。~
現(xiàn)有的解決方案
要解決300ms點(diǎn)擊延遲的問題,從長(zhǎng)遠(yuǎn)來說先馆,自然還是得瀏覽器開發(fā)商提供統(tǒng)一的最終的解決方案发框。但是,到目前為止煤墙,以上三種方案并不能提供很好的兼容性梅惯,對(duì)于方案一和方案二,Chrome是率先支持的仿野,F(xiàn)irefox緊隨其后铣减,然而令Safari頭疼的是,它除了雙擊縮放還有雙擊滾動(dòng)操作脚作,如果采用這種兩種方案葫哗,那勢(shì)必連雙擊滾動(dòng)也要一起禁用;對(duì)于方案三鳖枕,IE是支持的魄梯,但是其他瀏覽器支持不完善桨螺。具體請(qǐng)看這篇文章:移動(dòng)端Click300毫秒點(diǎn)擊延遲的來龍去脈(轉(zhuǎn))宾符。
所以,在瀏覽器開發(fā)商最終統(tǒng)一的解決方案出來之前灭翔,我們還有一些基于Javascript的現(xiàn)成的解決方案可以用魏烫。
方案一:指針事件的polyfill
現(xiàn)在除了IE,其他大部分瀏覽器都還不支持指針事件肝箱。有一些JS庫哄褒,可以讓我們提前使用指針事件,比如
- Google 的 Polymer
- 微軟的 HandJS
- @Rich-Harris 的 Points
然而煌张,我們現(xiàn)在關(guān)心的不是指針事件呐赡,而是與300ms延遲相關(guān)的CSS屬性touch-action
。由于除了IE之外的大部分瀏覽器都不支持這個(gè)新的CSS屬性骏融,所以這些指針事件的polyfill必須通過某種方式去模擬支持這個(gè)屬性链嘀。一種方案是JS去請(qǐng)求解析所有的樣式表萌狂,另一種方案是將touch-action
作為html標(biāo)簽的屬性。
方案二:FastClick
FastClick 是 FT Labs 專門為解決移動(dòng)端瀏覽器 300 毫秒點(diǎn)擊延遲問題所開發(fā)的一個(gè)輕量級(jí)的庫怀泊。FastClick的實(shí)現(xiàn)原理是在檢測(cè)到touchend事件的時(shí)候茫藏,會(huì)通過DOM自定義事件立即出發(fā)模擬一個(gè)click事件,并把瀏覽器在300ms之后的click事件阻止掉霹琼。
二务傲、點(diǎn)擊穿透問題
說完移動(dòng)端點(diǎn)擊300ms延遲的問題,還不得不提一下移動(dòng)端點(diǎn)擊穿透的問題枣申∈燮希可能有人會(huì)想,既然click點(diǎn)擊有300ms的延遲糯而,那對(duì)于觸摸屏天通,我們直接監(jiān)聽touchstart事件不就好了嗎?
使用touchstart去代替click事件有兩個(gè)不好的地方熄驼。
第一:touchstart是手指觸摸屏幕就觸發(fā)像寒,有時(shí)候用戶只是想滑動(dòng)屏幕,卻觸發(fā)了touchstart事件瓜贾,這不是我們想要的結(jié)果诺祸;
第二:使用touchstart事件在某些場(chǎng)景下可能會(huì)出現(xiàn)點(diǎn)擊穿透的現(xiàn)象。
什么是點(diǎn)擊穿透祭芦?
假如頁面上有兩個(gè)元素A和B筷笨。B元素在A元素之上。我們?cè)贐元素的touchstart事件上注冊(cè)了一個(gè)回調(diào)函數(shù)龟劲,該回調(diào)函數(shù)的作用是隱藏B元素胃夏。我們發(fā)現(xiàn),當(dāng)我們點(diǎn)擊B元素昌跌,B元素被隱藏了仰禀,隨后,A元素觸發(fā)了click事件蚕愤。
這是因?yàn)樵谝苿?dòng)端瀏覽器答恶,事件執(zhí)行的順序是touchstart > touchend > click。而click事件有300ms的延遲萍诱,當(dāng)touchstart事件把B元素隱藏之后悬嗓,隔了300ms,瀏覽器觸發(fā)了click事件裕坊,但是此時(shí)B元素不見了包竹,所以該事件被派發(fā)到了A元素身上。如果A元素是一個(gè)鏈接,那此時(shí)頁面就會(huì)意外地跳轉(zhuǎn)周瞎。
參考文章鏈接
移動(dòng)端Click300毫秒點(diǎn)擊延遲的來龍去脈(轉(zhuǎn))
移動(dòng)端click事件延遲300ms到底是怎么回事悟狱,該如何解決?
詳細(xì)解析-移動(dòng)H5點(diǎn)擊穿透現(xiàn)象