css flex多列布局
通过flex实现多列布局代码如下
main.css主要代码:
.multi-col {
display: flex;
height: 700px;
}
.multi-col .col {
height: 100%;
box-sizing: border-box;
position: relative;
flex: 1 1 auto;
}
.multi-col .rigid {
flex: 0 0 auto;
padding-right: 3px;
}
#col1 { width: 200px; background: darkred; }
#col2 { width: 210px; background: darkblue; }
#col3 { background: #777703; }
#col4 { background: white; }
index.html主要代码
<div class="mult-col-ctn">
<div id="col1" class="col rigid"></div>
<div id="col2" class="col rigid"></div>
<div id="col3" class="col"></div>
<div id="col4" class="col"></div>
</div>
最后效果如下
Flex布局Flexbox Layout(Flexible Box)的核心是, 修改容器(Container)内部元素(items)的长宽和次序以更好的填充可用的空间.
上面的css代码非常简单, 通过css属性display: flex
确定flex容器(flex container), 然后容器内部的为flex元素(flex items), 通过flex
属性控制其填充容器的空间的方式.
flex
属性由三部分组成: flex-grow
, flex-shrink
和flex-basis
.
.flex-item {
flex: <'flex-grow'> <'flex-shrink'> <'flex-basis'>
}
flex-group
: 定义元素的放大比例,默认为0. 当为0时, 不放大即使有剩余的空间flex-shrink
: 定义了项目的缩小比例,默认为1. 当为0时, 不缩小flex-basis
: 它的默认值为auto,元素的本来width
或height
js拖拽(drag)事件
通过拖拽事件(drag event)实现动态修改列的宽度.
首先在需要动态修改的列中, 添加拖动条.
.mult-col-ctn .col {
/* .. */
box-sizing: border-box;
position: relative;
padding-right: 3px;
}
.drag {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 3px;
background: darkgray;
cursor: ew-resize;
}
需要动态修改宽度的列, 不能自动放大flex-grow: 0
, 不能自动缩小flex-shrink: 0
, 保留原有尺寸flex-basis: auto
. 即: flex: 0 0 auto
.
<div id="col1" class="col rigid">
<div class="drag"></div>
</div>
<div id="col2" class="col rigid">
<div class="drag"></div>
</div>
html元素是默认是无法拖拽的, 需要修改draggable
属性为true
.
或修改html标签
<div class="drag" draggable="true"></div>
或通过js代码
ctn.querySelectorAll('.drag').forEach(elem => elem.draggable = true)
完整代码
index.html
<!doctype html>
<html>
<meta charset="UTF-8">
<title>TecPoste</title>
<link type="text/css" rel="stylesheet" media="screen,print" href="main.css">
<head>
</head>
<body>
<div class="multi-col">
<div class="col rigid col1">
<div class="drag"></div>
</div>
<div class="col rigid col2">
<div class="drag"></div>
</div>
<div class="col col3"></div>
<div class="col col4"></div>
</div>
<div class="multi-col">
<div class="col rigid col1">
<div class="drag"></div>
</div>
<div class="col rigid col2">
<div class="drag"></div>
</div>
<div class="col col3"></div>
<div class="col col4"></div>
</div>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
main.css
.multi-col {
display: flex;
height: 300px;
width: 900px;
margin-bottom: 1rem;
border: 1px solid black;
}
.multi-col .col {
height: 100%;
box-sizing: border-box;
position: relative;
flex: 1 1 auto;
}
.multi-col .rigid {
flex: 0 0 auto;
padding-right: 3px;
}
.drag {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 3px;
background: darkgray;
cursor: ew-resize;
}
.col1 {
width: 200px;
background: darkred;
}
.col2 {
width: 210px;
background: darkblue;
}
.col3 {
background: #777703;
}
.col4 {
background: white;
}
main.js
const minColWidth = 100;
let currentCol = null;
let currentCtn = null;
let prevX = null;
const regMultiCol = (ctn) => {
ctn.querySelectorAll('.drag').forEach(elem => elem.draggable = true);
};
const validColWidth = (ctn) => {
const len = ctn.children.length;
for (let i = 0; i < len; i++) {
const col = ctn.children[i];
if (col.offsetWidth <= minColWidth) {
return false;
}
}
return true;
};
document.addEventListener('dragstart', (evt) => {
const drag = evt.target;
if (!drag.classList.contains('drag')) {
return;
}
currentCol = drag.parentElement;
currentCtn = currentCol.parentElement;
}, false);
document.addEventListener('dragend', (evt) => {
currentCol = null;
currentCtn = null;
prevX = null;
}, false);
document.addEventListener('dragover', (evt) => {
prevX = prevX || evt.clientX;
if (!currentCol || !currentCtn) {
return;
}
const diff = evt.clientX - prevX;
const width = currentCol.offsetWidth + diff;
currentCol.style.width = width + 'px';
if (!validColWidth(currentCtn)) {
currentCol.style.width = (width - diff) + 'px';
return;
}
prevX = evt.clientX;
event.preventDefault();
}, false);
document.querySelectorAll('.multi-col').forEach(ctn => regMultiCol(ctn));