週末長知識: Facebook's "theater" View

facebook_theater.gif

Facebook 長久以來有個顯示 post 的模式(多用在照片/FB影片),稱為 theater

Theater 說穿了其實就是平常蠻常見到的所謂 modal 的效果,搜尋 “jquery modal” 之類的關鍵字可以找到一大堆,那這樣這篇文章是想要說些什麼呢?

常見的 modal 實作

雖然 modal 們乍看都是一樣,互動上還是會因為實作方式的不同而產生不一樣的結果。

基本上可以分成三種。

絕對定位型

modal_type_1.gif

  • 依據產生當下的網頁畫面位置做定位
  • 可以捲動主網頁
  • 捲動時,modal 不會跟著瀏覽器可視範圍

Facebook JS SDK 呼叫 FB.ui() 產生出來 iframe 式的 dialog 就是屬於這種。

有捲軸可捲浮動型

modal_type_2.gif

  • 永遠保持在畫面內
  • 可以捲動主網頁(捲軸、滾輪)
  • 看得到捲軸

大部分的 modal 是屬於這種,因為它不需要在一些多餘的地方動手腳(誤)。

無捲軸可捲浮動型

modal_type_3.gif

  • 永遠保持在畫面內
  • 可以捲動主網頁(滾輪)
  • 看不到捲軸

為了達到不捲動主網頁的效果,通常會對 <html><body> 元素的 CSS overflow 動手腳;若不另外費工寫 JavaScript 處理捲軸寬度問題,會造成開啟 modal 瞬間的視覺體驗不佳。

Bootstrap 的 modal就是屬於這種,並且它有處理捲軸寬度,在打開 modal 的同時給予 <body> 一個 padding-right 來補上捲軸的寬度,便不會有視覺的落差出現。

Bootstrap 提供的 modal 在本身內容超過畫面高度的時候,會產生自己的 scrollHeight 並顯示屬於 modal 的捲軸,此時是無法對主網頁進行捲動的。

不可捲浮動型

  • 永遠保持在畫面內
  • 不可以捲動主網頁

理論上用普通方法難以實現的類型,僅管可以透過 overflow: hidden 讓捲軸消失,瀏覽器還是會聰明的讓滑鼠滾輪可以作用。

參考 http://stackoverflow.com/a/11336442/2378741 ,大概可以瞭解,完全阻止捲動的方法只有讓它其實不用捲;然而其中提到的將 <body>height 限制住的方法有一個致命的缺點 - 無法保留主網頁的捲動位置。造成的視覺落差甚至超過上面提到的「使用 overflow: hidden 卻不處理捲軸寬度」的 case,也因此實際上並沒有看到什麼網頁使用此類的 modal。

Facebook “theater”

現在的 theater 用了一種我以前從來沒見過/想到的方法實作出了不可捲浮動型

IMG_0017.PNG

在 modal 開啟時將頁面內容的容器整個設為 position: fixed,同時取得當時的 scrollTop 並將它的負值設為容器的 top

這個方法確實徹底地攻克了上一段所說不可捲浮動型的難點 - 頁面內容變成 position: fixed 之後,<body> 已經不再需要捲動。而透過設定 topscrollTop 的負值,可以達到無縫銜接捲動位置視覺的效果。

Demo

光說不練是不行的,最後就以一個 prototype demo 來做結吧!

其中 modal 是用 Bootstrap 的 modal 改造的,模仿了 Facebook 是用 display: table-cell 的方式來做垂直置中。

後記

Theater view 有改版過很多次,很早很早以前我曾經想要模擬製作這個效果的時候跟現在的做法是不一樣的。

重點是要常常偷看別人的網站來長知識(?)。