使用純 CSS 實現滾動陰影效果

ChokCoco發表於2021-01-04

開門見山,有這樣一種非常常見的情況,對於一些可滾動的元素而言。通常在滾動的時候會給垂直於滾動的一側新增一個陰影,用於表明當前有元素被滾動給該滾出了可視區域,類似這樣:

可以看到,在滾動的過程中,會出現一條陰影:

對於兩側的列在滾動的過程中,靜止不動,吸附在邊界的問題,通常 CSS 使用 position: sticky 即可解決。

但是對於滾動過程中才出現的陰影(滾動容器內的內容沒有貼邊,則陰影出現,貼邊,則陰影消失),之前的做法一直都是需要藉助 JS 完成的。

那麼,有沒有純 CSS 能夠實現的方案呢?嘿嘿嘿,有。有一種非常討巧的障眼法,下面就讓我們來一步一步揭開它的面紗。

 

神奇的 background-attachment

要使用純 CSS 實現上述滾動陰影,最核心的要使用到的元素就是 background-attachment

在較早的一篇文章裡 -- CSS 實現視差效果,詳細了介紹了 background-attachment,藉助了 background-attachment: fixed 可以簡單的實現網站的滾動視差或者是類似圖片點選的水紋效果,類似這樣:

當然,今天我們的主角不是 background-attachment: fixed,而是 background-attachment: srcoll

 

background-attachment: srcoll

首先,介紹一下 background-attachment,如果指定了 background-image ,那麼 background-attachment 決定背景是在視口中固定的還是隨著包含它的區塊滾動的。

簡單而言,就是決定了在可滾動的容器中,背景圖案是如何進行運動的。通過兩個簡單的 Demo,弄懂 background-attachment: srcoll 和 background-attachment: local

background-attachment: local,這個就是和我們日常使用中的用法是一致的,可滾動容器的背景圖案隨著容器進行滾動:

background-attachment: scroll,這個是今天的主角,它表明背景相對於元素本身固定, 而不是隨著它的內容滾動:

如果你還沒弄明白他們的區別,可以戳下面的 DEMO 自己感受一下:

CodePen Demo -- bg-attachment Demo

 

srcoll 與 local 同時使用,實現障眼法

到這裡,可能很多同學還是懵的,我們到底要做什麼呢?這個和本文的滾動陰影有什麼關聯呢?

別急,滾動陰影的難點在於,初始沒有滾動的時候是沒有陰影展現的,只有當開始滾動,陰影才會出現。

所以這裡,我們藉助 background-attachment: srcoll 和 background-attachment: local 兩個屬性,在滾動初始的時候,利用兩層背景疊加在一起隱藏陰影背景,真正滾動的時候,將疊加的部分移走,只漏出陰影部分即可。

嗯?什麼意思。我們用給滾動容器,加上兩個漸變效果,分別運用上 background-attachment: srcoll 和 background-attachment: local,再疊加起來,像是這樣:

<!-- 可滾動容器 -->
<ul> 
    <li>...</li>
    ...
    <li>...</li>
</ul> 
// 情形一:
.g-one {
    background: linear-gradient(#fff, #f00);
    background-size: 100% 10px;
    background-repeat: no-repeat;
    background-attachment: local;
}

// 情形二:
.g-two {
    background: radial-gradient(at 50% 0, #000, #0f0 70%);
    background-size: 100% 10px;
    background-repeat: no-repeat;
    background-attachment: scroll;
}

// 情形三:
.g-combine {
    background: 
        linear-gradient(#fff, #f00),
        radial-gradient(at 50% 0%, #000, #0f0 70%);
    background-size: 100% 10px, 100% 10px;
    background-repeat: no-repeat;
    background-attachment: local, scroll;
}

實際效果就是這樣,一個背景是隨容器滾動,一個背景是隨容器固定。隨容器滾動的背景充當初始的遮罩層:

OK,可以看大,當滾動的時候,最後一幅疊加的情況,其實就是我們需要的滾動的時候展示不同的顏色(陰影)的效果。我們調整一下兩個漸變的顏色,遮罩層(background-attachment: local)為白色,再把固定不動的陰影層(background-attachment: scroll),利用徑向漸變模擬為我們想要的陰影顏色。

CSS 程式碼大概是這樣:

.g-final {
    background: 
        linear-gradient(#fff, transparent 100%),
        linear-gradient(rgba(0, 0, 0, .5), transparent 100%);
    background-size: 100% 30px, 100% 10px;
    background-repeat: no-repeat;
    background-attachment: local, scroll;
}

利用 linear-gradient(rgba(0, 0, 0, .5), transparent 100%) 線性漸變模擬了一層灰色陰影:

OK,大功告成。上述所有 DEMO,可以戳這裡看看:

CodePen Demo -- Pure CSS Scroll shadow

如文章開頭所示,這技巧也是可以直接運用在 table 裡面:

CodePen Demo -- Pure CSS Table scroll shadow

 

一些問題

層疊順序

當然,在上述的過程中,其實一直有個問題,就是由於是使用背景 background 模擬的陰影,其實最終的效果,內容是在陰影(背景之上的),但是實際效果其實沒有很大的差別,如果能忍受這一點,這個方案是完全可用的。

 

相容性

嗯,當然還有一個問題是就是 background-attachment 的相容問題。讓我們看看 CAN I USE

Can i use 下面的註釋表明,大部分相容問題其實是出在 background-attachment: fixed,對於本文的效果影響不大。

 

最後

本文技巧非原創,第一次看到來自這篇文章:探索CSS屬性*-gradient的實用價值 ,對其能否在實際中運用再做了一些探究。

好了,本文到此結束。

更多精彩 CSS 技術文章彙總在我的 Github -- iCSS ,持續更新,歡迎點個 star 訂閱收藏。

如果還有什麼疑問或者建議,可以多多交流,原創文章,文筆有限,才疏學淺,文中若有不正之處,萬望告知。

相關文章