複雜幀動畫之移動端video採坑實現

本文做者:IMWeb IMWeb團隊 原文出處:IMWeb社區 未經贊成,禁止轉載html

在企鵝輔導品牌頁中,咱們須要實現一個動畫以下:前端

總體效果

頁面滾動到動畫區域,播放動畫, 對應動畫部分以下:react

動畫

幀動畫當前的實現有如下幾種方式:ios

  1. GIF 動畫git

    你們比較熟悉的圖片格式github

  2. lottieweb

    Airbnb 開源項目,經過解析 AE 動畫爲 json 數據,支持跨平臺的動畫效果解決方案;lottie 在輔導中已經有實際應用,使用過的同窗都表示對其實現效果和開發速度表示稱讚和推薦,若是你還不瞭解 lottie, 推薦 lottie 系列學習文章,請戳我ajax

  3. APNG (Animated Portable Network Graphics)chrome

    基於 PNG 格式擴展的一種動畫格式,增長了對動畫圖像的支持,其誕生是爲了替代老舊的 GIF 格式,但部分瀏覽器不支持,須要考慮兼容;json

  4. HTML video 元素

GIF 動畫適用於處理色彩簡單、動效簡單的動畫,如 logo 、 icon 圖這樣的小圖動畫,在上面須要實現的動畫中明顯細節比較多,區域也比較大,考慮到質量 GIF 排除在外

在使用哪一種方式實現該動畫上,結合同事 @ajaxchen 的調研結論:

  1. lottie 在設計師經過 AE 製做了動畫以後,經過 AE 插件 bodymovin 將動畫導出 json 給到咱們前端開發,在使用這段 json 數據中,咱們引入了 lottie-web 腳原本解析這段 json 數據渲染成爲SVG / canvas 動畫,效果以下圖, 左圖爲用 lottie 實現,右圖爲我咱們的目標實現效果

對比圖

能夠看到實現仍是存在着差別,顏色、數字傾斜度、虛線的透視都沒有達到預期,因而放棄lottie 的使用,但這並不否認 lottie 在實現其它動畫的優秀效果

  1. APNG

    在對設計師給到的分段的動畫幀圖片壓縮以後,其實現結果 apng 大小高達 29M,webp 格式 17M, 如此龐大的體積,且實現清晰度達不到預期,也只能放棄該方式;因爲 APNG 在一些瀏覽器上不支持,在實現時需引入 apng-canvas 將 apng 轉化爲 canvas;

  2. createJS

    在我將 ISUX 上的文章《你離高效製做動畫只差一篇文章的距離》發送給咱們的設計小哥

    以後,他如此回覆我

  1. HTML video

    在上面嘗試無果以後,個人同事@zzbozheng 向我展現了一個 lol 的頁面,神奇,竟然是用video來實現!我怎麼就沒想到!

omg

​ 查看 video 標籤的兼容性,不管是咱們品牌頁的 PC 版仍是移動 web 端,兼容性均可以知足咱們的需求

​ 設計小哥哥給到的動畫 MP4 視頻大小是 350k, 350k對比幾十兆簡直就是輕量,查了一番 video 的自動播放實現,有一些坑,跟設計師小哥哥也溝通了一番綜合考慮以後毅然踩上了 video 的坑

video 標籤有對應的事件方法, 可查閱文檔

下面是在移動端 web 使用 video 過程當中的採坑總結:

  1. video 在 safari 和桌面端 chrome 中可能沒法自動播放

    這裏的自動播放,不管是 video 標籤的 autoplay 屬性仍是經過 js 自動調用 video 的 play 方法都是自動播放

    桌面端 chrome 自動播放主要受制於 autoplay policy ,遵循對應的策略則能夠自動播放,這主要考量於用戶的體驗;由於使用muted(靜音)屬性能夠容許自動播放, 咱們的動畫原本就是沒有聲音的,因此在 video 標籤中加上 muted 屬性

<video muted />
複製代碼
  1. 隱藏視頻控制條

    在 video 標籤中,只要不加 controls 屬性,通常是不會顯示控制條的,這樣就看不出來是一個視頻了,固然有些安卓機器的瀏覽器的確處於一種失控狀態,後面會提到 ○| ̄|_

  2. IOS 視頻自動全屏播放

    查閱資料,video 標籤添加兩個屬性便可小屏播放

<video muted playsInline webkit-playsinline="true" />
複製代碼
  1. 微信不容許自動播放視頻,必須經過用戶交互才能播放

    開始的時候就有過來人的同事提醒過要我注意下微信的視屏自動播放,通過別人的反饋,其實不止是微信不容許,有些機器瀏覽器也是不容許,這個時候該怎麼辦?結合 touch 事件一塊兒實現。視頻播放是監聽 scroll 事件,等到可視範圍內調用 video.play() 自動播放,既然有些瀏覽器須要用戶交互,那能夠選擇 touch 事件,當用戶 touch 到這塊展現播放區域,觸發 touch 事件調用 play, 這裏咱們的動畫區域足夠大,不擔憂用戶 touch 不到。這裏使用變量來表示視頻是否已經播放,若是已經播放就再也不執行 touch 事件,避免頻繁調用 play

  2. 有些安卓瀏覽器沒法自動播放,touch 事件也沒法觸發播放

    video 標籤的 play 方法返回一個 promise,可經過 promise 來檢測到 video 是否可自動播放

video.play()
  .then(() => {
    // play success
  })
  .catch( err => {
    // auto play fail
  })
複製代碼

​ 當 catch 到 error 時,只能啓用兼容方案,設計小哥哥給了我幾張幀圖片,讓我漸隱漸現實現圖片播放。 ​

​ ​ 然而!在華爲榮耀 8 的微信裏面,我發現了個詭異的問題,視頻沒有播放,同時 video.play 沒有 catch 到 error,而是正常的執行到了 then 方法,也就是說 play 方法返回成功,然而視頻實際沒有播放,這,這, 這, 是在欺騙個人感情!

​ 無奈之下, 針對安卓的微信端,視頻所有啓用兼容模式(幾張圖片漸隱漸現)

  1. 論安卓瀏覽器的各類詭異表現
    1. oppo 機視頻播放自動懸浮置頂

2. video 控制條沒法隱藏 3. 視頻沒法控制地自動全屏播放 4. ...

我:"設計小哥哥,這我無能爲力

設計: "找出全部對應的機型和瀏覽器,對這些不支持的瀏覽器使用兼容模式播放動畫

我:"這全部的機型實在難以控制和所有覆蓋到...

設計: "那就先對全部的安卓都使用兼容模式吧,後面對此優化

因而就這樣幹掉了全部的安卓 video
複製代碼
  1. ios QQ 瀏覽器視頻播放完畢,展現推薦視頻

這個 video 我是設置了循環播放的,硬生生 QQ 瀏覽器就在視頻播放完畢後展現推薦視頻,而且中止了個人循環播放,這讓個人頁面顯的有點 low, 這明顯是不仁道的,嘗試無果以後,因而我諮詢 QQ 瀏覽器的同事幫忙這個問題, 他讓我在 video 標籤上加上這個屬性,便可使用系統播放器,而拒絕被攔截植入推薦視屏, 感謝@eddiecmchen 提供的意見

mtt-playsinline=」true複製代碼
  1. 設計師導出的視頻背景色與提供的色彩有色差 這在不一樣 PC 設備中存在差別,例如 MAC 與 windows , 在移動端暫時還沒發現,可是能夠發現視頻在移動端展現與 PC 上展現的色彩差別

左圖爲模擬器效果,右圖爲 iphone safari打開效果

至此附上實現的部分代碼塊,項目使用 react 技術棧

<video
   muted
   src="***"
   preload="auto"
   playsInline
   webkit-playsinline="true"
   mtt-playsinline="true"
   loop
   ref={this.videoRef}
/>
複製代碼
playVideo = () => {
    const { isVideoCanAutoPlay, isPlayedVideo } = this.state;
    // 播放視頻
    const videoDom = this.videoRef.current;
    if (videoDom && !isPlayedVideo && isVideoCanAutoPlay) {
      const playPromise = videoDom.play();
      if (playPromise) {
        playPromise
          .then(() => {
            this.setState({
              isPlayedVideo: true,
            });
          })
          .catch((err) => {
            badjs.info(`[品牌頁][AI VIDEO 動畫]: 自動播放出錯 ${err}`);

            ++this.catchVideoErrorCount;

            // 經過點擊和scroll後都沒法播放視屏,使用兼容性方案
            if (this.catchVideoErrorCount >= 2) {
              this.setState({
                isVideoCanAutoPlay: false,
              });
            }
          });
      }
    }
  };
複製代碼

最後總結:

  1. 移動端 web 對於 video 自動播放的兼容性是在太差,尤爲安卓,一些瀏覽器對 video 標籤進行攔截,並以本身的方式實現,或是懸浮置頂播放,或是兩個視屏播放衝突,或是控制條沒法隱藏,或是播放默認全屏,若是用其它方式能夠實現動畫儘可能仍是用其它方式

  2. 對於 video 的自動播放,考慮一些瀏覽器限制必須經過用戶交互才能使用,若是視屏是在第一屏則有點難度,仍是須要用戶經過點擊才能播放,若是不是第一屏則可經過 touch 事件來觸發,畢竟用戶下拉滾動仍是會觸發 touch 事件

  3. video 的 play 方法返回的 promise 存在華爲榮耀8 微信裏返回 play 成功,可是卻沒有播放視頻

參考文檔和網站:

  1. developer.mozilla.org/zh-CN/docs/…
  2. lol.qq.com/

感謝在這次採坑過程當中給予幫助的同事~

相關文章
相關標籤/搜索