欢迎关注我的公众号:前端侦探
很多页面布局,特别是那种工具类的、比如编辑器、可视化平台等,为了充分的利用屏幕空间,都会提供拖拽调节各个分栏尺寸的功能,比如像 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 应用等,那就放心大胆的使用吧,千万不要被兼容性束缚了你的思维。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤
欢迎关注我的公众号:前端侦探
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。