歡迎關注我的公眾號:前端偵探
很多頁面佈局,特別是那種工具類的、比如編輯器、視覺化平臺等,為了充分的利用螢幕空間,都會提供拖拽調節各個分欄尺寸的功能,比如像 vscode
抽象開來,其實就是這樣一個佈局
你也可以先看實際效果:CSS 可拉伸分欄佈局 2(codepen.io)
是不是非常靈活呢?其實純 CSS 也是可以實現這樣的效果的,一起看看吧
一、基本實現原理
實現這個效果需要藉助 resize 特性,可以天然的實現元素拉伸特性。最常見的就是 textarea
,預設就是可以拉伸的
<textarea></textarea>
不過,我們這裡需要的不是textarea
,而是普通的元素。普通的元素要實現這樣的效果也很容易,只需要在overflow
不是visible
的情況下,新增resize
屬性就行了
.resizable {
resize: both;
overflow: scroll;
}
原理就是這麼簡單,那麼如何運用呢?
二、自定義右下角 resize
雖然看似可以拉伸,但是可拉伸範圍實在是太小了。該如何增加可拉伸範圍呢?這裡有兩種思路:
- 通過偽元素自定義
- 容器整體放大
先說第一種思路。要定義尺寸,首先需要搞明白 resize
指的是什麼?經過簡單的測試發現,在 chrome 中,resize
其實就是橫縱滾動條的交界處,比如直接設定滾動條的尺寸
::-webkit-scrollbar {
width: 20px;
height: 20px;
background-color: rosybrown;
}
現在將滾動條高度改大一點
::-webkit-scrollbar {
width: 20px;
height: 100px;
background-color: rosybrown;
}
可以看到 resize
也跟著變化了
當滾動條高度足夠大時,右側就變成整條都可以拉伸了
::-webkit-scrollbar {
width: 20px;
height: 100vh;
background-color: rosybrown;
}
然後,這個斜線條紋可以用偽元素::-webkit-resizer
來修改
div::-webkit-resizer{
background-color: royalblue;
}
不過遺憾的是,這種方式只適合-webkit-
瀏覽器,所以firefox
就不行了。
下面來看第二種思路:整體放大。
這裡說的整體放大,指的是將整個容器通過transform
進行放大,這樣一來,右下角的resize
也會跟隨放大了,比如
div{
width: 300px;
height: 20px;
transform: scaleY(100);/*足夠大的放大倍數*/
overflow: scroll;
resize: horizontal;
}
這樣也能達到整條側邊都可以拉伸的目的了。
下面來看實際應用吧
三、兩欄拉伸佈局
循序漸進,先實現兩欄佈局。比如這樣
通常這類佈局都有一定的約束,比如這裡的 MAIN
是自適應空間的,SIDE
是固定尺寸,先快速寫出佈局和樣式
<div class="con">
<aside>
SIDE
</aside>
<main>
MAIN
</main>
</div>
關鍵樣式如下
.con{
display: flex;
}
aside{
width: 200px;
}
main{
flex: 1;
}
那麼,如何讓左邊側邊欄居右拖拽功能呢?很簡單,將剛才可拉伸的元素放入側邊欄,讓寬度由裡面的拉伸元素決定(flex 子元素天然支援該特性),內容著用絕對定位覆蓋來實現,實現如下
<aside>
<div class="resize"></div>
<div class="line"></div>
<section>SIDE</section>
</aside>
由於 firefox
的resize
無法自定義,所以這裡單獨一個標籤來模擬拉伸軸
aside{
position: relative;
overflow: hidden;
}
.resize{
width: 200px;
height: 16px;
transform: scaleY(100);
overflow: scroll;
resize: horizontal;
opacity: 0;
}
.line{
position: absolute;
top: 0;
right: 0;
width: 4px;
bottom: 0;
background-color: royalblue;
opacity: 0;
transition: .3s;
pointer-events: none;
}
.resize:hover+.line,
.resize:active+.line{
opacity: 1;
}
這樣就實現了左邊側邊欄拉伸的功能
四、三欄拉伸佈局
有時候會出現兩邊側邊欄,中間部分是自適應的,如下
這種如何實現呢?首先按照兩欄佈局的思路
<div class="con">
<aside>
<div class="resize"></div>
<div class="line"></div>
<section>SIDE</section>
</aside>
<main>
MAIN
</main>
<aside class="right">
<div class="resize"></div>
<div class="line"></div>
<section>SIDE</section>
</aside>
</div>
不過這樣會有一個很明顯的問題,由於resize
是在右側,如果放在右邊側邊欄,那肯定就相反了,具體表現就是,往右拉伸,右側邊欄反而增大,不符合直覺
有沒有什麼辦法讓resize
到左邊來呢?
首先想到的是通過翻轉變換,水平方向上翻轉可以scaleX(-1)
來實現,合併起來就是
.right .resize{
transform: scale(-1, 100);
}
在 Chrome 下表現不錯
但是,Firefox 就有點奇怪了
朝右邊拖拽,右側邊欄寬度反而增加。究其原因,在 Firefox上,transform
水平翻轉僅僅改變了視覺上的效果,並沒有改變互動行為,有沒有辦法可以真正改變resize
的位置呢?
還真有,不過僅可以改變水平方向上的位置,通過direction
屬性。這是一個可以改變文件方向流的屬性,有些語言方向是從右往左的,所以設定後,resize
也從右側變到了左側。
所以實現就是
.right .resize{
direction: rtl;
}
這樣下來,Chrome 和 Firefox 均正常了
完整程式碼可以訪問:CSS 可拉伸分欄佈局 (codepen.io)或者CSS 可拉伸分欄佈局 (juejin.cn)
五、其他組合分欄效果
組合分欄效果少不了垂直方向上的。
垂直方向的分欄和水平方向大同小異,只需要水平方向上縮放足夠大就行了。
.resize-top{
width: 16px;
resize: vertical;
transform: scaleX(100);
}
現在可以嘗試實現文章開頭佈局效果
<div class="con">
<aside>
<div class="resize"></div>
<div class="line"></div>
<section>SIDE</section>
</aside>
<main>
<div class="main">
MAIN
</div>
<footer>
<div class="resize resize-top"></div>
<div class="line"></div>
<section>bottom</section>
</footer>
</main>
</div>
不過有個缺陷就是,無法通過direction
或者其他手段,將resize
真正地從下移到上面
只能通過transform: scale(-1, 100);
實現了,這樣就導致垂直方向上的拉伸在 Firefox 體驗不佳。效果如下
Chrome 表現完美:
Firefox 表現差強人意:
完整程式碼可以訪問:CSS 可拉伸分欄佈局 2(codepen.io) 或者CSS 可拉伸分欄佈局 2(juejin.cn)
繼續調整一下,還可以實現這樣的佈局效果
完整程式碼可以訪問:CSS 可拉伸分欄佈局 3(codepen.io) 或者CSS 可拉伸分欄佈局 3(juejin.cn)
六、總結一下
以上就通過純 CSS 實現了4種常見的分欄拉伸效果,基本能滿足常見的佈局需求了,是不是非常實用呢?下面總結一些要點
- 實現原理是 CSS resize 屬性
- resize 生效的條件是 overflow 不能是 visible
- resize 在 Chrome 下其實是橫縱滾動條的交匯處,改變滾動條尺寸可以改變 resize 大小
- resize 還可以通過縮放整體容器來實現
- resize 預設是在右下角,可以通過水平翻轉到左下角,Chrome 完美支援拉伸,Firefox 不行
- 還可以通過 direction 改變文件流的方式,將 resize 從右下角變到左下角
- 垂直方向上 resize 只能通過 transform 翻轉方式實現,因此 Firefox 體驗較差
雖然 Firefox 在垂直方向上略有缺陷,如果你對相容性沒太多需求,比如公司內部專案,Electron 應用等,那就放心大膽的使用吧,千萬不要被相容性束縛了你的思維。最後,如果覺得還不錯,對你有幫助的話,歡迎點贊、收藏、轉發❤❤❤
歡迎關注我的公眾號:前端偵探