最近在群裡,有個小夥伴問了這麼一道很有趣的問題:
為了簡化實際效果,我們看這麼一張示意效果圖:
可以看到,當容器高度沒有超過某一個值時,沒有箭頭圖示。反之,箭頭圖示出現。
這個效果在很多場景都會出現,可以算是一個高頻場景,那麼在今天,我們能否不使用 JavaScript,僅僅憑藉 CSS 實現類似於這樣的功能呢?
答案當然是可以,XBoxYan 大佬在 CSS 實現超過固定高度後出現展開摺疊按鈕 介紹了一種非常巧妙的藉助浮動的解法,十分有意思,感興趣的同學可以先行一步瞭解。
當然,浮動 float
在現如今的 CSS 世界,運用的已經非常少了。那麼除了浮動,還有沒有其它有意思的解法?本文我們將一起來探究探究。
第一種方法,非常簡單,但是對相容性有所要求。那就是使用容器查詢 -- @container
語法。
容器查詢在 新時代佈局新特性 -- 容器查詢 也詳細介紹過。
簡單而言,容器查詢它給予了 CSS,在不改變瀏覽器視口寬度的前提下,只是根據容器的寬度或者高度變化,對佈局做調整的能力。
基於這個場景,我們假設我們有如下的 HTML/CSS 結構:
<div class="g-container">
<div class="g-content">
Lorem ipsum dolor s...
</div>
</div>
.g-container {
position: relative;
width: 300px;
height: 300px;
resize: vertical;
overflow: hidden;
.g-content {
height: 100%;
}
.g-content::before {
content: "↑";
position: absolute;
bottom: 0px;
left: 50%;
transform: translate(-50%, 0);
}
}
它是這麼一個樣式效果:
其中,我們給元素 .g-content
新增了 resize: vertical
,讓它變成了一個可以在豎直方向上通過拖動改變高度的容器,以模擬容器在不同內容的場景下,高度不一致的問題:
我們通過元素的偽元素實現了箭頭 ICON,並且它是一直顯示在容器內的。
下面,我們通過簡單的幾句容器查詢程式碼,就可以實現讓箭頭 ICON,只在容器高度超過特定高度的時候才出現:
.g-container {
container-type: size;
container-name: container;
}
@container container (height <= 260px) {
.g-content::before {
opacity: 0;
}
}
簡單解釋一下:
.g-container
它被用作容器查詢的目標容器
container-type
屬性指定了容器的型別為 size,表示我們將使用容器的尺寸來應用樣式。container-name
屬性指定了容器的名稱為 container,以便在後面的容器查詢規則中參照。@container container (height <= 260px) {}
表示這是一個容器查詢規則,在括號中的條件 (height <= 260px)
表示當容器的高度小於等於 260px
時,應用該規則下的樣式260px
時,.g-content
元素的偽元素將變得透明這樣,我們就非常簡單的實現了容器在不同高度下,ICON 元素的顯示隱藏切換:
完整的程式碼,你可以戳這裡:CodePen Demo -- flexible content
當然,這個方案的唯一缺點在於,截止至今天(2023-11-11),相容性不是那麼好:
那,有沒有相容性更好的方案?當然,來我們一起來看看 clamp
+ calc
的方案。
clamp
+ calc
大顯神威上面效果的核心在於:
那麼想想看,如果拿容器的高度減去一個固定的高度值,會發生什麼?假設一下,ICON 元素的 CSS 程式碼如下:
.g-content::before {
content: "↑";
position: absolute;
left: 50%;
transform: translate(-50%, 0);
bottom: calc(100% - 200px);
}
仔細觀察 bottom: calc(100% - 200px)
,在元素的 bottom 屬性中,100%
表示的是容器當前的高度,因此 calc(100% - 200px)
的含義就代表,容器當前高度減去一個固定高度 200px
。因此:
200px
,calc(100% - 200px)
表示的是一個正值200px
,calc(100% - 200px)
表示的是一個負值200px
,calc(100% - 200px)
表示 0我們看看這種情況下,整個 ICON 的表現是如何的:
可以看到,當容器高度大於 200px
的時候,箭頭 ICON 確實出現了,但是,它無法一直定位在整個容器的最下方。
有什麼辦法讓它在出現後,一直定位在容器的最下方嗎?
別忘了,CSS 中,還有幾個非常有意思的數學函數:min()
、max()
、clamp()
,它們可以有效限定動態值在某個範圍之內!
不太瞭解的,可以看看這篇 現代 CSS 解決方案:CSS 數學函數
利用 clamp()
,我們可以限定計算值的最大最小範圍,在這個場景下,我們可以限制 bottom
的最大值為 10px
:
.g-content::before {
// ...
bottom: clamp(-99999px, calc(100% - 200px), 10px);
}
上面的程式碼 clamp(-99999px, calc(100% - 200px), 10px)
,核心在於,如果 calc(100% - 200px)
的計算值大於 10px
,它只會取值為 10px
,利用這個技巧,我們可以在容器高度超長時,把箭頭 ICON 牢牢釘在容器的下方,無論容器的高度是多少:
到此,結束了嗎?顯然沒有。
雖然上面的程式碼,解決當 calc(100% - 200px)
的計算值大於 10px
的場景,但是沒有解決,當 calc(100% - 200px)
的計算值處於 -10px ~ 10px
這個範圍內的問題。
我們可以清楚的看到,當我們往下拖動容器變高的時候,箭頭元素是逐漸慢慢向上出現,而不是突然在某一個高度下,直接出現,所以在實際使用中,會出現這種 ICON 只出現了一半的尷尬場景:
但是,莫慌!這個問題也好解決,我們只需要給 calc(100% - 200px)
的計算值,乘上一個超級大的倍數即可。原因在於:
calc(100% - 200px)
的計算值是負數時,我們其實不希望 ICON 出現,此時,乘上一個超級大的倍數,依然是負數,不影響效果calc(100% - 200px)
的計算值是正數時,為了避免 ICON 處在只漏出部分的尷尬場景,通過乘上一個超級大的倍數,讓整個計算值變得非常大,但是由於又有 clamp()
最大值的限制,無論計算值多大,都只會取 10px
看看程式碼,此時,整個 bottom
的取值就改造成了:
.g-content::before {
// ...
bottom: clamp(-9999px, calc(calc(100% - 200px) * 100000), 10px);
}
通過,將 calc(100% - 200px)
的值,乘上一個超大的倍數 100000
,無論是正值還是負值,我們把計算值放大了 100000 倍。這樣,整個效果就達成了我們想要的效果:
仔細看上圖,ICON 元素從漸現,變成了瞬間出現!與上面的 @container
效果幾乎一致,最終達成了我們想要的效果。
其核心就在於 clamp(-9999px, calc(calc(100% - 200px) * 100000), 10px)
,一定需要好好理解這一段程式碼背後的邏輯。
基於此,我們就巧妙的利用 clamp()
+ calc()
方法,近似的實現了類似於 if/else
的邏輯,實在是妙不可言!
CodePen Demo -- flexible content
好了,本文到此結束,希望本文對你有所幫助