Yijen's blog

關於部落格
繪圖 | 食記 | Web前端技術 | HTML | CSS | JavaScript 研究
  • 304151

    累積人氣

  • 128

    今日人氣

    0

    訂閱人氣

用純 CSS :target selector 實作光箱 (lightbox) 效果

你好我又要來寫廢文了

前情提要:前一次的主題介紹 常用的 CSS pseudo class (CSS偽類) 教學與練習 - PART2,裡面提到一個 CSS3 屬性 :target

這個屬性,只要搭配得宜的 CSS 組合,就能用它來實作 Pure CSS (不摻js,不含外卦) 的光箱 lightbox 效果囉,來看看怎麼寫。

甚麼是 lightbox

就是光箱啦(廢話!),也就是常常用來展示圖片的一種呈現方式。「內容顯示在彈出的視窗,通常底下搭配一個黑色的遮罩,讓前景更突出」你去 Google jQuery lightbox 應該會跑出一大堆 plugin 吧哈哈。
當然我們今天要用 CSS 來實作它!

組合元件

接下來要來做光箱本箱,我們先生一個 .lightbox 並撰寫一些 CSS 讓它水平置中於頁面上

<div id="box1" class="lightbox"></div>

CSS

.lightbox {
    width: 800px;
    height: 600px;
    display: none;

    /* Point */
    margin: auto;
    position: fixed;
    top: 50px;
}

製作切換特定 #id 光箱的開關

這一部分就是用到 :target 的屬性了

#box1 {
    display: none;
}
#box1:target {
    display: block;
}

HTML


<a href="#box1">Open</a>
Open LightBox

製作半透明遮罩

我們在原本的 .lightbox 後面增加一個 .mask div, 來實現全景遮罩的實作。
要注意的是,這個遮罩只在光箱出現時,它才跟著出現。

CSS

:target + .mask {
    display: block;
    width: 100%;

    /* Point */
    height: 100vh;
    background-color: rgba(0,0,0,.5);

    /* Positioning */
    position: fixed;
    left: 0;
    top: 0;
}

HTML

    <div id="box2" class="lightbox"></div>
    <div class="mask"></div>

Demo

Open LightBox with Mask

很好,我們實作了一個簡單的 lightbox,但是目前它還很陽春,接著我們要把光箱 popup 出來增加一些效果,這時候需要搭配 CSS Transition 來幫助我們

.fancy {
    /* Point 1: animation 0.3秒 */
    transition: all 0.3s ease;

    /* Point 2: 出現之前的長相 */
    border-color: transparent;
    opacity: 0;
}
.fancy:target {
    /* Point 3: 出現之後的長相 */
    border-color: #CCC;
    opacity: 1;
}

如此一來,有 fancy 這個 class 的 lightbox 就會用動畫方式來出現。

Demo

Open LightBox with transiton effet

優化UX

到這裡,我們需要再加強二件事

  1. 光箱在關閉時畫面不希望跳動
  2. 光箱要更方便/容易被關閉:例如點擊遮罩

回頭看一下我們目前的 HTML 和 CSS 結構,光箱 div 的呈現與否,是透過 div:target 的選擇器,然而因為切換 #anchor (也就是傳統的錨點行為) 畫面會跳動該 #id 的地方。
我們雖巧妙地將 #lightbox 用CSS定義為 position: fixed ,因而在觸發 :target 時,#lightbox 的顯示並不會使 browser 捲動;但退出呢?

當 url 中有 # 字符號,但頁面中找不到對應的 #id dom element 時,整個畫面是會跳到最上面的。然憑只靠 CSS 無法消除這預設的行為,必項靠 Javascript 才可做到。我們得想另一個辦法。

HTML(Before)

<div id="box4"></div>
<div class="mask"></div>

HTML(After)

<div id="box4">
    <div id="pending"></div>
</div>
<div class="mask"></div>

我們在 .lightbox 裡面 append 了一個 #pending 的 div,接著我們設置以下的CSS

#pending {
    display: block;
    height: 0;
    position: absolute;
}

Demo

Open LightBox No.4

原理同上,我們在 關閉 lightbox 的這個行為將其導至另一個 #url,也就是脫離 :target 的狀態。再者,我們移出的新 url 也是一個絕對定位的位置,因此它的出現與否並不會造成當前畫面的位移。真要說缺點的話,就是我們得多一點點 HTML,讓感覺沒什麼作用的 #pending 存在光箱之中,並發揮它的作用。

遮罩問題

如果有一點慧根的人,看到這裡應該就知道怎麼作了吧?哈哈不過還是得公布我的解法:也就是原本為 div 的 mask 我們將其替換成 a 這個屬性,並 assign 給它同上例一樣的關閉連結 #pending

HTML

<div id="box5" class="lightbox">
    <div id="pending"></div>
    <a href="#pending">close</a>
</div>
<a href="#pending" class="mask"></a>
Open LightBox No.5 (click overlay mask to dismiss)

最後,我們將最佳化的版本 HTML + CSS 再重新撰寫一次

HTML

<div class="lightbox fancy" id="demo">
    <div id="pending"></div>
        <p>...
</div>
<div class="mask"></div>

CSS

.lightbox {
    display: block;
    width: 800px;
    height: 600px;
    background-color: #fff;
    border: 5px solid #CCC;
    padding: 1rem;

    /* Point: center  */
    margin: auto;
    position: fixed;
    top: 50px;    

    /* Point: before box showed up */
    border-color: transparent;
    opacity: 0;
    z-index: -1;

    /* Point: animation */
    transition: opacity .8s ease;
}
.lightbox:target {
    border-color: #CCC;
    opacity: 1;    
    z-index: 1001;
}
:target + .mask {
    display: block;
    width: 100%;

    /* Point */
    height: 100vh;
    background-color: rgba(0,0,0,.5);

    /* Positioning */
    position: fixed;
    z-index: 1000;
    left: 0;
    top: 0;
}
Open final version

Conclusion

以上,是這次 Step by Step 用純 CSS 實作 lightbox 的教學文章。
接著要來說一下用 Pure CSS lightbox 有什麼優點與缺點

優點(Pros)

CSS:target lightbox,可以直接用網址 http://url#lightbox_ID 來呈現你的作品,而不必再用 js 或是後端程式帶參數 (parameter)

缺點(Cons)

關閉光箱的 tricky tech,其實對瀏覽器來說也是一次的導頁,因此在 browser 本身的瀏覽紀錄上面會增加不少東西

這次的實作練習,主要目的是拓展 CSS3 pseudo classes :target 的可用/實用性。而且因為少了 Javascript,整體來說效能應該是比較好的。希望有緣讀到本網誌的朋友喜歡這一次的分享

Browser Capability

IE 9+ 以上以及目前最新版本的其餘 modern browser 通通支援 :target 的使用 :D

相簿設定
標籤設定
相簿狀態