CSS秘密花園: 通過亮度調節去強調(De-emphasize)
《 CSS Secrets 》是 @Lea Verou 最新著作,這本書講解了有關于CSS中一些小秘密。是一本CSSer值得一讀的一本書,經過一段時間的閱讀,我、@南北和@彥子一起將在W3cplus發布一系列相關的讀后感,與大家一起分享。
很多時候,我們需要通過在元素背后添加一個半透明的深色疊加來讓內容變暗,強調并提醒用戶關注某個UI元素。例如,lightboxes和“quick tours”接口經常需要這種效果。
來完成這個效果的最常見的技術是添加一個額外的HTML元素來調節亮度,并應用一些如下的CSS:
.overlay { /* For dimming */
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: rgba(0,0,0,.8);
}
.lightbox { /* The element to draw attention to */
position: absolute;
z-index: 1;
/* [rest of styling] */
}
深色疊加的目的是把用戶的注意力放到我們希望用戶注意的元素上邊,然后元素后邊的內容都變暗。 .lightbox 有一個更高的 z-index ,可以讓它放置在深色疊加之上。所有這些都是非常OK沒有問題的,但是它需要一個額外的HTML元素,也就是說效果不能只通過CSS應用。這不是什么大問題,但是這是一個我們希望可以避免的不便之處,如果可以的話。幸運的是,大多數的情況下我們都可以搞定。
基于偽元素的解決方案
我們可以使用偽元素來消除對額外HTML元素的需求,如下:
body.dimmed::before {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
background: rgba(0,0,0,.8);
}
這是一個稍微好點的解決方案,這也意味著我們現在可以直接通過CSS應用這種效果。但是,問題來了,這不是非常方便,因為 <body> 元素可能已經應用了一些其它的東西在它的 ::before 偽元素之上了。所以,也就是說如果想要應用這個效果,我們通常需要一些JavaScript來應用到 dimmed 類上。
我們可以通過給元素本身的 ::before 偽元素應用深色疊加、并給它一個 z-index:-1 來解決這個問題,這樣它就位于我們的元素之下了。盡管它解決了可移植性的問題,它并不能給我們控制Z軸的位置提供很精確的控制。它可能最終會被放在我們的元素下邊(這是可取的)或放在我們的元素以及它的幾個父元素下邊。
它的另一個問題是,偽元素沒有自己的JavaScript事件。當使用一個單獨的元素來進行疊加的時候,我們可以給它添加事件句柄——例如:當用戶點擊疊加層的時候,關閉高亮窗口。如果我們在同一個想要強調的元素上使用偽元素,想要檢測用戶是否點擊了覆蓋層或者元素是很棘手的。
box-shadow的解決方案
偽元素的解決方案非常靈活,而且符合大多數人對疊加的期望。但是,對于簡單的用例或原型設計,我們可以采用 box-shadow 的spread半徑,把它增大到你在每一邊希望指定的大小。也就是說我們可以創建一個非常大的零偏移零模糊的shadow,用一種迅速又隨性的方式來模擬覆蓋層。
box-shadow: 0 0 0 999px rgba(0,0,0,.8);
第一個通過的解決方案有一個明顯的問題是,在非常大分辨率( > 2000px )的地方它就會有問題。我們可以通過使用一個再大一點的數字來緩解這種情況,或者通過使用viewport單位來完全地解決這個問題,這樣我們可以確保“overlay”總會比我們的viewport大。因為我們不能使用不同的水平和垂直spread半徑值,viewport單位應該是 vmax 。如果你對于 vmax 這個單位不熟悉, 1vmax 等于 1vw 或 1vh ,取較大值。 100vw 等于viewport的width,同樣, 100vh 等于viewport的height值。因此,能夠滿足我們需求的最小值是 50vmax ,因為它在每一邊都會添加,所以我們的覆蓋層的最終尺寸是 100vmax +我們的元素的尺寸:
box-shadow: 0 0 0 50vmax rgba(0,0,0,.8);
這種技術非常快速而且容易應用,但是它有兩個相當嚴重的問題,限制了它的實用性。你發現了嗎?
首先,因為我們的元素的尺寸是和viewport相關的,和頁面沒有關系,當我們滾動頁面的時候,會看到覆蓋層的邊界,除非元素是 position: fixed; 定位的,或者是頁面本身不夠長,不能滾動。此外,因為頁面可以是很長很長的,它不會機智地嘗試去通過增加spread半徑來克服這一點。相反,我建議你只對 fixed 定位的元素,或頁面很小沒有滾動的情況下使用這種技術。
第二,使用一個單獨的元素(或偽元素)作為覆蓋層并不僅僅會將用戶的注意力引導到我們想要的元素上。它還會阻止鼠標和頁面的其余部分交互,因為它捕獲了指針事件。 box-shadow 沒有這個屬性。因此,它只會在視覺上幫助用戶將注意力引導到特定的元素上,而不會自己捕獲任何鼠標交互事件。至于這是否可以接受,要看你具體的使用情況。
backdrop解決方案
如果你想要變成焦點的元素是一個模式對話框 <dialog> ( <dialog> 元素通過它的 showModal() 方法顯示),它已經有一個覆蓋層了,通過用戶代理樣式表。這種原生的覆蓋還可以通過 ::backdrop 偽元素來添加樣式,例如,讓它變暗一點:
dialog::backdrop {
background: rgba(0, 0, 0, .8);
}
這種方法唯一需要注意的地方是,在編寫的時候,瀏覽器的支持是非常有限的,所以一定要在使用前檢查其當前狀態。記住,即使它不被支持,如果對話框沒有覆蓋層的話,也不會影響到什么東西,因為它只是一個用戶體驗的改善。
來自: http://www.w3cplus.com/css3/css-secrets/de-emphasize-by-dimming.html