如何做一個(gè)讓人聞風(fēng)喪膽的 H5?(內(nèi)有干貨)

2015-9-30    用心設(shè)計(jì)

藍(lán)藍(lán)設(shè)計(jì)m.bouu.cn )是一家專(zhuān)注而深入的界面設(shè)計(jì)公司,為期望卓越的國(guó)內(nèi)外企業(yè)提供有效的UI界面設(shè)計(jì)BS界面設(shè)計(jì) 、 cs界面設(shè)計(jì) 、 ipad界面設(shè)計(jì) 、 包裝設(shè)計(jì) 、 圖標(biāo)定制 、 用戶(hù)體驗(yàn) 、交互設(shè)計(jì)、 網(wǎng)站建設(shè) 、平面設(shè)計(jì)服務(wù)

如果您想訂閱本博客內(nèi)容,每天自動(dòng)發(fā)到您的郵箱中, 請(qǐng)點(diǎn)這里

來(lái)源:莫貝網(wǎng)


如何做一個(gè)讓人聞風(fēng)喪膽的 H5?

前言

最近火熱的有聲娛樂(lè)平臺(tái) APP,企鵝 FM,在8月28日鬼節(jié)前夕,聯(lián)合《盜墓筆記》推出了“勇敢者的游戲”活動(dòng)。作為一個(gè) UI 工程師,在這個(gè)移動(dòng)互聯(lián)網(wǎng)叱咤風(fēng)云的時(shí)代,每次看到朋友圈中被分享的各種花樣 H5 頁(yè)面,總是心癢難耐,也想做有著酷炫動(dòng)畫(huà)和帶感聲效的 H5 呢?;叵氲阶龉砉?jié)活動(dòng)頁(yè)的時(shí)候,接近午夜零點(diǎn)還在調(diào)整頁(yè)面效果,看著頁(yè)面上漸隱漸現(xiàn)的可怕畫(huà)面,活生生嚇到了自己,也是蠻難忘的。作為剛剛來(lái)到活動(dòng)頁(yè)新手 村的朋友,踩到了一些坑,所以讓我進(jìn)入正題吧。哦,等一下,請(qǐng)先掃一下二維碼啦~


如何做一個(gè)讓人聞風(fēng)喪膽的 H5

與設(shè)計(jì)師的溝通

在拿到視覺(jué)稿和需求單之后,我們需要了解整個(gè)活動(dòng)的流程。有的時(shí)候,設(shè)計(jì)師并不會(huì)把每個(gè)頁(yè)面的動(dòng)畫(huà)效果做成視頻,而是用口述的方式和工程師進(jìn)行溝通。這樣就需要工程師結(jié)合活動(dòng)頁(yè)流程和設(shè)計(jì)稿之后,自己先構(gòu)思一些動(dòng)效再去同產(chǎn)品以及設(shè)計(jì)溝通,這樣交流的效率才會(huì)比較高。

動(dòng)畫(huà)新手有的時(shí)候會(huì)天馬行空想到一些奇怪的效果,可能會(huì)不符合整體設(shè)計(jì)風(fēng)格,可能會(huì)違反現(xiàn)實(shí)物理規(guī)律,有自己的想法,還要和產(chǎn)品設(shè)計(jì)確認(rèn)。比如這個(gè)頁(yè)面:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

一開(kāi)始是做成了先出現(xiàn)手電筒,再出現(xiàn)光,在我的設(shè)想中剛開(kāi)始手電筒上不會(huì)有那層黃綠色的光。后來(lái)經(jīng)設(shè)計(jì)師提醒:如果完全沒(méi)有光源,也應(yīng)該看不到手電筒。才改成了現(xiàn)在的方案:燈光閃兩下:物理定律什么的,我才記不清了呢T T。

P.S. 做動(dòng)畫(huà)的時(shí)候銘記動(dòng)效原則,基本上動(dòng)畫(huà)的效果不會(huì)跑偏。

具體實(shí)現(xiàn)

仔細(xì)想想,這個(gè)活動(dòng)頁(yè)面并沒(méi)有用到什么高深技巧,基本上是用 position 定位和 CSS3 動(dòng)畫(huà)完成的。不過(guò)在寫(xiě)頁(yè)面之前,還是有不少擔(dān)心的:

  1. 頁(yè)面兼容怎么做按照 iPhone6 的尺寸確定元素的位置,然后用 zoom 或者 transform: scale(x) 拉伸頁(yè)面或者拉伸元素。在實(shí)際開(kāi)發(fā)的時(shí)候,我一度對(duì)這兩個(gè)屬性的用法產(chǎn)生混淆,所以作些了研究,稍后會(huì)詳細(xì)說(shuō)說(shuō)這兩個(gè)屬性。
  2. 3D 變化效果怎么實(shí)現(xiàn)大家應(yīng)該早就聽(tīng)說(shuō)過(guò)或者使用過(guò) perspective 和 perspective-origin 這兩個(gè)屬性了,雖然教程和分享都看過(guò)不少,但真正寫(xiě)起來(lái)還是有一些摸不著頭腦,各種搜索關(guān)于 3D 動(dòng)畫(huà)的解釋之后我認(rèn)為原理大概是這樣的:如何做一個(gè)讓人聞風(fēng)喪膽的 H5簡(jiǎn) 單粗暴地說(shuō),請(qǐng)想象你是站在上圖中的紅點(diǎn)位置,你與物體間的距離是 perspective,眼睛的位置是 perspective-origin。好了,現(xiàn)在站定位置,去看這個(gè)物體,想象物體投影在某個(gè)平面上的效果(這里的平面就是我們的顯示屏),這就是 3D 投影的結(jié)果。關(guān)于 perspective-origin,可以看看這個(gè)demo。
    說(shuō)了這么多,在實(shí)際運(yùn)用中,我還是找了一個(gè)生成器
    得到的效果大概是這樣的:

    如何做一個(gè)讓人聞風(fēng)喪膽的 H5

    如何做一個(gè)讓人聞風(fēng)喪膽的 H5

    想要重點(diǎn)說(shuō)一下磁帶的實(shí)現(xiàn),主要牽涉到的圖片資源是下面這幾個(gè):
    如何做一個(gè)讓人聞風(fēng)喪膽的 H5
    如何做一個(gè)讓人聞風(fēng)喪膽的 H5
    如何做一個(gè)讓人聞風(fēng)喪膽的 H5

    磁帶被分成了3個(gè)部分,磁帶底部,磁帶封面和磁帶。其中封面和磁帶是正視圖,需要使用 3D 旋轉(zhuǎn),讓這兩個(gè)元素“躺下去”,而且為了保證這三個(gè)元素之間不會(huì)因?yàn)槠聊坏目s放,出現(xiàn)錯(cuò)位的問(wèn)題,需要保證磁帶封面和磁帶的定位是基于磁帶底部的。其實(shí)磁 帶上還有兩片蓋子,不知道大家有沒(méi)有注意到。其實(shí)這個(gè)蓋子是左右對(duì)稱(chēng)且中心對(duì)稱(chēng)的,所以完全可以只用一張圖片完成這樣的效果,用 transform: scale(-1, 1); 和transform: scale(1, -1); 實(shí)現(xiàn)。

  3. 動(dòng)畫(huà)如何才有代入感如何做一個(gè)讓人聞風(fēng)喪膽的 H5這 個(gè)活動(dòng)頁(yè)面我個(gè)人最喜歡的地方就是星星砸下去的動(dòng)畫(huà),感覺(jué)所有的戲份都在它身上。開(kāi)始的設(shè)想只是星星砸下去,感謝在制作過(guò)程中,經(jīng)驗(yàn)豐富的同事所提的建 議:星星砸下去的時(shí)候要有灰塵濺起或者火星四濺的效果。后來(lái)和設(shè)計(jì)商量,最后用了灰塵濺起的效果。不過(guò)本來(lái)還想做,星星背后的鐵板應(yīng)該要有震動(dòng)的效果。由 于時(shí)間關(guān)系,震動(dòng)的效果有點(diǎn)不好添加,所以放棄了,這一點(diǎn)感覺(jué)有一些遺憾。可能頁(yè)面新手的經(jīng)驗(yàn)不夠,很多動(dòng)畫(huà)的效果因?yàn)橛邢薜南胂罅λ圆惶晟?。這個(gè)時(shí) 候和身邊經(jīng)驗(yàn)豐富的同事請(qǐng)教是很有效的方法。同時(shí),一定要多看 B 站拓寬視野才行哦。

踩到了一些坑

頁(yè)面布局并不復(fù)雜。前文也提到,基本上使用 position: absolute; 來(lái)實(shí)現(xiàn)的,不過(guò)遇到了一些問(wèn)題就有了以下總結(jié):

  1. 殺雞就不要用牛刀,能又快又好解決問(wèn)題才最重要如何做一個(gè)讓人聞風(fēng)喪膽的 H5上圖是首頁(yè)的截圖,頁(yè)面加載之后應(yīng)該可以看到“膽量測(cè)試”下面的藍(lán)色線(xiàn)條有一個(gè)動(dòng)畫(huà)。故事是這樣的,自從 SVG 帝王小啪帶著神器 svgartisan 降臨(對(duì) SVG 有興趣的同學(xué)歡迎加群 426886128 一同討論 SVG 技術(shù)),做頁(yè)面的時(shí)候總想加上一點(diǎn) SVG。然而這個(gè)藍(lán)色線(xiàn)條上有,所以用 PS 導(dǎo)出 SVG 后還要做二次處理才能還原設(shè)計(jì)稿 上的效果,而且 SVG 的代碼你懂得,它總是有點(diǎn)長(zhǎng)。其實(shí)有個(gè)簡(jiǎn)單粗暴的方法:改變藍(lán)色線(xiàn)條的圖片寬度,雖然這個(gè)方法從性能上看并不好,但考慮到這個(gè)頁(yè)面也只有這里發(fā)生了重繪, 所以還是用圖片+寬度控制來(lái)實(shí)現(xiàn)了。不知道大家會(huì)不會(huì)為了某一種技術(shù)而去做某一件事情,但其實(shí)完成那件事情才是真正的目的,卻因?yàn)槟莻€(gè)技術(shù)而耽誤了不少進(jìn) 度,這樣就有點(diǎn)進(jìn)入了炫技的誤區(qū)。
  2. 答應(yīng)我,偽元素上就不要做動(dòng)畫(huà)了
    偽元素真的是神一樣的存在,一個(gè)標(biāo)簽自帶兩個(gè)兒子,不知道為什么就有種金閃閃的感覺(jué)。但是偽元素上的動(dòng)畫(huà)真的很坑,年少無(wú)知,頁(yè)面都寫(xiě)完了,發(fā)現(xiàn)在 iOS 上美如畫(huà)的動(dòng)畫(huà)效果,到了小米和魅族上就……總之看到屏幕那一刻我是這樣的:如何做一個(gè)讓人聞風(fēng)喪膽的 H5Android 上坑多,不要一次應(yīng)用太多新技術(shù)。比如在魅族上用 flexbox 布局,就要加上 display: -webkit-box。還有一個(gè)教訓(xùn)就是,頁(yè)面果然應(yīng)該做一個(gè)測(cè)試一個(gè)啊QAQ。因?yàn)檫@個(gè)項(xiàng)目是重構(gòu)和前端并行開(kāi)發(fā)的……把偽元素改成實(shí)際 DOM 元素的時(shí)候,是懷著一顆對(duì)不起前臺(tái)的心的。
  3. 請(qǐng)寫(xiě)好注釋如何做一個(gè)讓人聞風(fēng)喪膽的 H5與UI工程師對(duì) 接的前臺(tái)同學(xué)需要看注釋才知道什么時(shí)候要加什么class,想到剛剛開(kāi)始接需求的時(shí)候,從來(lái)不寫(xiě)注釋…真是對(duì)不起前臺(tái)同學(xué)T T現(xiàn)在我個(gè)人的注釋如上圖所示。也看過(guò)組里不同同事的注釋風(fēng)格,大同小異,主體思想就是“在XX時(shí)候添加X(jué)X class”這樣,和對(duì)接的同學(xué)約定好就可以~

zoom 和 transform: scale(x); 的使用

我將會(huì)在接下來(lái)詳細(xì)談到前文提到的 zoom 和 transform: scale(x); 問(wèn)題。

為什么要使用縮放

現(xiàn)在不管是活動(dòng)頁(yè)的設(shè)計(jì)稿還是產(chǎn)品頁(yè)的設(shè)計(jì)稿,逐漸以 375×667 的 iPhone6 為基礎(chǔ)。但是實(shí)際生活里,這些頁(yè)面是會(huì)出現(xiàn)在細(xì)細(xì)長(zhǎng)長(zhǎng)的 iPhone5、480px 高度的 iPhone4 還有大屏幕的 iPhone 6+,更不要說(shuō)在三星小米魅族一加等等等等尺寸都不知道怎么辦才好的 Android 系列上打開(kāi)會(huì)是什么gui。

拿這次的活動(dòng)頁(yè)面設(shè)計(jì)稿 來(lái)說(shuō),與用戶(hù)產(chǎn)生交互的按鈕在頁(yè)面篇底部的位置。有一個(gè)前提,為了兼容不同寬度的屏幕,所以頁(yè)面是基于 iPhone 6 的 375px 用 zoom 屬性進(jìn)行縮放,可以看出iPhone 5 和 iPhone 4 的寬度一樣,而且看設(shè)計(jì)稿,頁(yè)面元素是從上到下分布的:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

也就是說(shuō),使用相同的 zoom 值,滿(mǎn)足了 iPhone5 的頁(yè)面效果,但是在 iPhone4 上,按鈕就會(huì)偏底,頁(yè)面整體感覺(jué)也偏底。但是 zoom 值不能隨便更改,否則紅框中的錄音機(jī)圖片的左右邊界就會(huì)顯示出來(lái)。所以要針對(duì) iPhone 4 調(diào)整元素的之間的間距,最終的效果大概是這樣的:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

可以看得出效果并不是很好,整個(gè)頁(yè)面非常的擁擠,所以在這個(gè)情況下,我覺(jué)得用統(tǒng)一 zoom 值來(lái)調(diào)整有點(diǎn)一棍子打倒了,如果一個(gè)個(gè)元素微調(diào),那么最好效果會(huì)好得多。加上 zoom 會(huì)有一定的性能問(wèn)題,組里的同事有些是 zoom 調(diào)整,也有給每個(gè)元素加 class 通過(guò) transform: scale() 調(diào)整的。重構(gòu)最神奇的就是,條條大路通羅馬,怎么樣都能達(dá)到自己想要的視覺(jué)效果,但是中間會(huì)因?yàn)楦鞣N原因,實(shí)現(xiàn)的方式不太一樣。

拿到設(shè)計(jì)稿一開(kāi)始就先看看這個(gè)設(shè)計(jì)稿的布局,有一些是從頁(yè)面頂部到底部都有效果的,這個(gè)時(shí)候就要考慮在 iPhone4 這樣屏幕不夠高的設(shè)備上如何保證頁(yè)面完整呈現(xiàn);或者在不影響交互的情況下,隱藏哪些元素。有的時(shí)候頁(yè)面上元素比較集中,這個(gè)時(shí)候就要考慮在 iPhone6+ 這樣的大屏幕設(shè)備上,要不要調(diào)整間距使得頁(yè)面不會(huì)太空曠。

要知曉設(shè)計(jì)稿背后的含義,不是一拿到就開(kāi)始做了,有些元素其實(shí)是要整體考慮的。有些乍一看好像是用 position 定位,分別寫(xiě) top 值就好。殊不知,設(shè)計(jì)師真正要表達(dá)的是,作為一個(gè)整體,它們?cè)陧?yè)面上要絕對(duì)居中。沒(méi)有 get 到這個(gè) point,兼容的時(shí)候就要哭了。

zoom 和 transform:scale 的概念

先來(lái)看一下 zoom 和 transform:scale 的說(shuō)明:

Specifies the initial zoom factor for the window or viewing area. This is a magnifying glass type of zoom. Interactively changing the zoom factor from the initial zoom factor does not affect the size of the initial or the actual viewport.

從定義上看 zoom 縮放的是被 zoom 的容器的視口,可以把它想象成放大鏡的效果,這個(gè)屬性是可被繼承的,所以我們做設(shè)備屏幕兼容的時(shí)候,可以在 body 標(biāo)簽下加一個(gè) div 包裹住頁(yè)面上的其他元素,然后在這個(gè) div 上加 zoom,達(dá)到的視覺(jué)效果就是頁(yè)面上其他元素也被縮放了。但是有些元素并不支持 zoom。

A two-dimensional transformation is applied to the coordinate system an element renders in through the ‘transform’ property. This property contains a list of transform functions. The final transformation value for a coordinate system is obtained by converting each function in the list to its corresponding matrix (either defined in this specification or by reference to the SVG specification), then multiplying the matrices.

在說(shuō) scale 應(yīng)該要先看看 transform。transform 屬性應(yīng)用到元素的過(guò)程其實(shí)是矩陣變換的過(guò)程,在渲染的時(shí)候,元素的坐標(biāo)就會(huì)被確定下來(lái),然后和 transform 的屬性值進(jìn)行矩陣運(yùn)算得到最終的坐標(biāo),不過(guò)你會(huì)發(fā)現(xiàn),一個(gè)絕對(duì)定位的元素通過(guò) transform 改變顯示位置后,這個(gè)元素的 tbrl 值并不會(huì)被更新,且 transform 屬性不可繼承的。

The value of the transform property is a list of applied in the order provided. … specifies a scale operation using the [sx,1] scaling vector, where sx is given as the parameter. … specifies a scale operation using the [1,sy] scaling vector, where sy is given as the parameter.

scale 是 transform 的一個(gè)屬性值,這是一個(gè)縮放矩陣。當(dāng)一個(gè)元素被定義了 transfrom: scale(x); 后,還是再結(jié)合它的 transfrom-origin,才能確定最后的縮放效果。依然是兼容屏幕分辨率的問(wèn)題,要想 transfrom: scale(x) 達(dá)到和 zoom 相似的效果,要記得把 transfrom-origin 設(shè)置成 0 0。這么設(shè)置的原因是,在文檔流中的元素,是以它的左上角為中心進(jìn)行 zoom 的,而當(dāng)元素脫離文檔流時(shí),要使 transform: scale(x) 和 zoom 達(dá)到相同的效果,還要具體分析 transform-origin 要如何設(shè)置。

大概你也注意到了,在前一句中,我說(shuō)的是“相似的效果”而不用“一樣的效果”,這是因?yàn)槭褂?scale 的時(shí)候可能遇到下面這樣的問(wèn)題。下圖中左邊為 transform:scale(.85),右邊為 zoom: .85:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

下面這段是外層容器的樣式,背景是定義在 switch-wh 動(dòng)畫(huà)中,通過(guò)絕對(duì)定位讓瀏覽器自行計(jì)算,保證容器大小占滿(mǎn)整個(gè)屏幕:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

因?yàn)?zoom 是作用在 body 下面這個(gè)占滿(mǎn)了屏幕空間的容器,所以根據(jù)定義以及 zoom 的繼承性,我們可以說(shuō)在這個(gè)頁(yè)面上使用 zoom 其實(shí)是縮放了整個(gè)屏幕(也就是視口),可以想象成在瀏覽器中打開(kāi)了頁(yè)面,然后放大這個(gè)頁(yè)面的效果:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

為什么 scale 會(huì)留下右部和底部的迷の白色呢?讓我們回到 transform 的定義中,“applied to the coordinate system an element renders in through the ‘transform’ property”。當(dāng)元素都進(jìn)行渲染了,坐標(biāo)已經(jīng)確定了,再進(jìn)行縮放,也就是在原來(lái)元素基礎(chǔ)上改變大小。所以 .sf-index 雖然在渲染時(shí)四個(gè)角的位置分別是(0,0)、(100%,0)、(0,100%)、(100%, 100%),經(jīng)過(guò)以 (0,0) 為變換中心的 scale,就變成了(0,0)、(85%,0)、(0,85%)、(85%,85%)。我們就會(huì)看到頁(yè)面右邊出現(xiàn)寬度為15%的一條白邊,以及頁(yè)面下方 高度為15%的白邊。

好像 zoom 無(wú)敵了呢

看起來(lái),好像兼容的時(shí)候應(yīng)該用 zoom 呢。嗯看到 scale 之后的結(jié)果我就是這么想的。接著就發(fā)現(xiàn) zoom 之后的頁(yè)面,文字的顯示不太正常。下圖左邊是被 zoom 的 iPhone4,右邊是沒(méi)有被 zoom 的 iPhone6:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

由于頁(yè)面是被整體縮放了,所以文字也自然出現(xiàn)了縮放,剛好這種好像被砍了一刀的文字效果還蠻適合鬼節(jié)的活動(dòng)頁(yè)面,所以我并沒(méi)有做處理。正常來(lái)說(shuō),如果需要做處理就是調(diào)整文字的 line-height 和容器的 height,使其不出現(xiàn)遮擋。

正如頁(yè)面元素經(jīng)過(guò) zoom 后,實(shí)際的大小會(huì)發(fā)生改變,圖片的大小也發(fā)生了改變,使用雪碧圖就出現(xiàn)了一些問(wèn)題。雪碧圖是把各種小圖拼合到一張大圖上面,通過(guò) width、height 和 background-position 定位到圖片,看下圖可以發(fā)現(xiàn)相鄰圖片的邊界也一起顯示出來(lái)了。

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

審查元素發(fā)現(xiàn),用于顯示圖片的元素尺寸也不對(duì)?。?/span>

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

可以看出這個(gè)元素正確的尺寸應(yīng)該是 198×52,經(jīng)過(guò) zoom: 1.10 放大后容器反而變小了,后來(lái)將 zoom 值調(diào)整到 1.104(414/375),圖片的邊界問(wèn)題算是解決了。

關(guān)于圖片沒(méi)有正常顯示的問(wèn)題,我的推斷是,原因在于 zoom 值設(shè)定偏小,圖片經(jīng)過(guò) zoom 后沒(méi)有被正確地計(jì)算,而圖片的容器又偏大,所以相鄰圖片的邊就被顯示了出來(lái)。后來(lái) zoom 值是根據(jù)比例設(shè)定了,就不會(huì)出現(xiàn)這個(gè)問(wèn)題。

最后,zoom 對(duì)性能不友好,下面兩個(gè) gif 分別是 zoom 和 transform: scale 引起的重繪:

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

如何做一個(gè)讓人聞風(fēng)喪膽的 H5

很明顯,在文檔流中 zoom 加在任意一個(gè)元素上都會(huì)引起整個(gè)頁(yè)面的重新渲染,而 transform: scale 只是在當(dāng)前的元素上重繪。

還有沒(méi)有更好的兼容方法呢

這樣說(shuō)來(lái),簡(jiǎn)直兩個(gè)方法都不能用了嘛…還有沒(méi)有什么別的兼容的方法呢?
有的。
像需要大量圖片的頁(yè)面,做兼容的時(shí)候我們常常擔(dān)心的是什么?當(dāng)然是圖片比例出問(wèn)題咯,所以也會(huì)使用通過(guò)偽元素設(shè)置 padding-top 的方法,保證圖片比例正常地顯示出來(lái)。只是這樣的寫(xiě)法通常要結(jié)合 background-size:cover; 而我們常用的工具 CssGaga 在生成雪碧圖了之后會(huì)覆蓋 background-size。目前的這個(gè)方案的話(huà)……就不合成雪碧圖了。

還有一個(gè)方案是使用 media query 結(jié)合 rem (或百分比)完成這樣的布局,不過(guò)目前 gaga 不支持 background-size 的 rem,所以要采用什么方式合成雪碧圖以及如何生成新的樣式,還需要尋找新的方向。在不需要合成雪碧圖的時(shí)候,可以用這兩種方法。

日歷

鏈接

個(gè)人資料

存檔