週末長知識: Parallax Scrolling on Touch Devices

寫在前面,我個人不是這麼熱愛 parallax scrolling。

觸控裝置制作 parallax scrolling 面臨的問題

大部分的 parallax scrolling 效果都是透過 listen window 的 scroll event 來達成,然而在觸控裝置上的體驗會顯得非常詭異。

可以參考一下兩年以前的這篇 onscroll Event Issues on Mobile Browsers

Unlike desktop browsers, most all mobile browsers simply do not fire an onscroll event until the scrolling action comes to a complete stop.

The only mobile browser that handled this event elegantly in my testing was Android’s Jelly Bean browser.

譯:大部分的行動裝置在捲動完全停止前都不會觸發 onscroll 事件(Android 4.3+ 除外)

因此觸控裝置在瀏覽一般 parallax scrolling 網站的時候都是看到一段一段定格的效果,而不會像是使用一般桌面瀏覽器那樣流暢的感覺。

當然,我們也不用太絕望,畢竟那是兩年前的事兒了,現在的 Android 4.3+ 普及率還是比較高的(是這樣說的嗎)。

純 JavaScript 解法(吧)

可能需要視是否為行動裝置來載入 Scrollability,我沒有實際使用過,但理論上是可行的。

請見 Stellar.js 的 iOS demo。

基於 HTML/CSS 結構的解法

就在一陣子以前我讀到了一個系列文章:

意外的發現裡面的 demo 在手機上是可以運作的,讓我非常好奇原因是什麼;從整篇教學文以及網頁原始碼裡看起來,沒有使用任何別的 JS library。經過一番仔細的研究,發現關鍵是在於 裡面的 parallax 舞台不是基於 window 的 onscroll。

讓我們來看一下關鍵的 HTML/CSS 片段:

<body>
  <div class="parallax">
    <div class="parallax__group">
      <div class="parallax__layer parallax__layer--fore">...</div>
      <div class="parallax__layer parallax__layer--base">...</div>
      <div class="parallax__layer parallax__layer--back">...</div>
      <div class="parallax__layer parallax__layer--deep">...</div>
    </div>
  </div>
</body>
.parallax {
  height: 500px; /* fallback for older browsers */
  height: 100vh;
  overflow-x: hidden;
  overflow-y: scroll;
  -webkit-perspective: 300px;
  perspective: 300px;
}
.parallax__group {
  position: relative;
  height: 500px; /* fallback for older browsers */
  height: 100vh;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
}
.parallax__layer {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

可以發現基本上整個的 scroll 動作會被限制在 .parallax 這個 <div> 裡面,而不像一般的做法是在 <body> 上做 scroll。在這樣的設定之下,神秘的現象發生了!

onscroll 事件會持續觸發 (做為等價交換,momentum scrolling 無法作用)

而此時的 JS 程式碼 listen 的目標也確實就是 .parallax 那個 <div>:

var body = document.querySelector('.parallax'), scrollTop = 0;
...
body.addEventListener('scroll', function (e){
  ...
});

所以

前陣子在弄 angular-scroll-watch 的範例的時候還特別針對同一個範例做了 支援/不支援 觸控裝置的版本,大家可以用觸控裝置親自試試看:

但其實

iOS 8 Safari no longer disables scroll events

不好意思讓你讀了這麼久(誤)。

目前 iOS 8 上似乎也只有 Safari 有支援持續觸發 onscroll,所以這篇長的知識應該還算是依然有用的啦!iOS 8 Safari 瀏覽 parallax 網站還真的是順順的欸…

最後關於 parallax scrolling

開頭有提到我不熱愛,其實並不是我不喜歡那個效果的感覺,而是大部分的網站往往會因為過度使用或沒有對效能做最佳化而導至實際上使用的體驗不好。在 parallax scrolling 風靡的這些日子裡,讓我真心覺得做得非常好的網站屈指可數(其實也沒有這麼少啦)。

如果你本身有在做 parallax scrolling 的話,我個人有幾個建議:

  • 加個 smooth mouse wheel 的效果 - 不是所有人都用 Mac/Firefox
  • 全程 60FPS - 偶爾低一點點沒關係,但 50FPS 是底限
  • 不要為了 parallax 而 parallax - 應該先從網頁想傳達的概念下手,不是真的所有網站都適合做 parallax
  • 承上,如果還是想,請適量 - 在不是這麼適合的情況下,如果只有加一點點,還是可以擁有小確幸

關於 60FPS 的部分,如果你不是很了解如何調校的話,可以看看下面這影片