I implemented my own split-pane with HTML/JS/CSS Flexbox.
I'm having trouble with the splitter in the following case- one of the panels has a fixed size (in px), and the other one is set to grow (flex-grow: 1
).
In case the other panel has children with size, it won't scroll to the end. It gets stuck at the size of the children.
Can this be fixed with CSS on the split-pane panels but not on the children?
It's very important for me to use flex as I want to maintain responsiveness of my application, and want to avoid fixed sizes wherever I can.
This is a JSFiddle sample of my question.
Code snippet given below. Thanks!
function startDrag() {
glass.style = 'display: block;';
glass.addEventListener('mousemove', drag, false);
}
function endDrag() {
glass.removeEventListener('mousemove', drag, false);
glass.style = '';
}
function drag(event) {
var splitter = getSplitter();
var panel = document.getElementById('c2');
var currentWidth = panel.offsetWidth;
var currentLeft = panel.offsetLeft;
panel.style.width = (currentWidth - (event.clientX - currentLeft)) + "px";
}
function getSplitter() {
return document.getElementById('splitter');
}
var con = document.getElementById('container');
var splitter = document.createElement('div');
var glass = document.getElementById('glass');
splitter.className = 'splitter';
splitter.id = 'splitter';
con.insertBefore(splitter, con.lastElementChild);
splitter.addEventListener('mousedown', startDrag, false);
glass.addEventListener('mouseup', endDrag, false);
.container {
display: flex;
border: 1px solid;
width: 500px;
height: 300px;
position: absolute;
}
.c1 {
background-color: blue;
flex: 1;
height: 100%;
}
.c2 {
background-color: green;
width: 150px;
}
.splitter {
width: 20px;
cursor: col-resize;
}
.glass {
height: 100%;
width: 100%;
cursor: col-resize;
display: none;
position: absolute;
}
.grandchild {
background-color: red;
width: 50px;
height: 50px;
}
<div id="container" class="container">
<div id="glass" class="glass"></div>
<div class="c1">
<div class="grandchild"></div>
</div>
<div id="c2" class="c2"></div>
</div>
It gets stuck at the size of the children
This is expected behavior when using a flexbox
. I guess if you want to scroll to the end then you can use position: absolute
for the grandchild
relative to c1
:
.grandchild {
background-color: red;
width: 50px;
height: 50px;
position: absolute;
top: 0;
left: 0;
}
Give overflow: hidden
to c1
too:
.c1 {
background-color: blue;
flex: 1;
height: 100%;
position: relative;
overflow: hidden;
}
Cheers!
function startDrag() {
glass.style = 'display: block;';
glass.addEventListener('mousemove', drag, false);
}
function endDrag() {
glass.removeEventListener('mousemove', drag, false);
glass.style = '';
}
function drag(event) {
var splitter = getSplitter();
var panel = document.getElementById('c2');
var currentWidth = panel.offsetWidth;
var currentLeft = panel.offsetLeft;
panel.style.width = (currentWidth - (event.clientX - currentLeft)) + "px";
}
function getSplitter() {
return document.getElementById('splitter');
}
var con = document.getElementById('container');
var splitter = document.createElement('div');
var glass = document.getElementById('glass');
splitter.className = 'splitter';
splitter.id = 'splitter';
con.insertBefore(splitter, con.lastElementChild);
splitter.addEventListener('mousedown', startDrag, false);
glass.addEventListener('mouseup', endDrag, false);
.container {
display: flex;
border: 1px solid;
width: 500px;
height: 300px;
position: absolute;
}
.c1 {
background-color: blue;
flex: 1;
height: 100%;
position: relative;
overflow: hidden;
}
.c2 {
background-color: green;
width: 150px;
}
.splitter {
width: 20px;
cursor: col-resize;
}
.glass {
height: 100%;
width: 100%;
cursor: col-resize;
display: none;
position: absolute;
}
.grandchild {
background-color: red;
width: 50px;
height: 50px;
position: absolute;
top: 0;
left: 0;
}
<div id="container" class="container">
<div id="glass" class="glass"></div>
<div class="c1">
<div class="grandchild"></div>
</div>
<div id="c2" class="c2"></div>
</div>
Solution:
So I guess your strategy should be to use an absolute grandchild
that fills the whole side-panel, and then put the content
inside like:
<div class="grandchild">
<div class="content"></div>
</div>
and change these styles:
.grandchild {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.grandchild .content{
background-color: red;
width: 50px;
height: 50px;
}
Example below:
function startDrag() {
glass.style = 'display: block;';
glass.addEventListener('mousemove', drag, false);
}
function endDrag() {
glass.removeEventListener('mousemove', drag, false);
glass.style = '';
}
function drag(event) {
var splitter = getSplitter();
var panel = document.getElementById('c2');
var currentWidth = panel.offsetWidth;
var currentLeft = panel.offsetLeft;
panel.style.width = (currentWidth - (event.clientX - currentLeft)) + "px";
}
function getSplitter() {
return document.getElementById('splitter');
}
var con = document.getElementById('container');
var splitter = document.createElement('div');
var glass = document.getElementById('glass');
splitter.className = 'splitter';
splitter.id = 'splitter';
con.insertBefore(splitter, con.lastElementChild);
splitter.addEventListener('mousedown', startDrag, false);
glass.addEventListener('mouseup', endDrag, false);
.container {
display: flex;
border: 1px solid;
width: 500px;
height: 300px;
position: absolute;
}
.c1 {
background-color: blue;
flex: 1;
height: 100%;
position: relative;
overflow: hidden;
}
.c2 {
background-color: green;
width: 150px;
}
.splitter {
width: 20px;
cursor: col-resize;
}
.glass {
height: 100%;
width: 100%;
cursor: col-resize;
display: none;
position: absolute;
}
.grandchild {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.grandchild .content{
background-color: red;
width: 50px;
height: 50px;
}
<div id="container" class="container">
<div id="glass" class="glass"></div>
<div class="c1">
<div class="grandchild">
<div class="content"></div>
</div>
</div>
<div id="c2" class="c2"></div>
</div>
In case the other panel has children with size, it won't scroll to the end. It gets stuck at the size of the children.
This is because an initial setting of a flex container is min-width: auto
on the flex items. This means that a flex item, by default, cannot be smaller than the size of its content.
Can this be fixed with CSS on the split-pane panels but not on the children?
Yes. Override the default with min-width: 0
or with any overflow
other than visible
:
.c1 {
background-color: blue;
flex: 1;
height: 100%;
overflow: hidden; /* or min-width: 0 */
}
revised fiddle
function startDrag() {
glass.style = 'display: block;';
glass.addEventListener('mousemove', drag, false);
}
function endDrag() {
glass.removeEventListener('mousemove', drag, false);
glass.style = '';
}
function drag(event) {
var splitter = getSplitter();
var panel = document.getElementById('c2');
var currentWidth = panel.offsetWidth;
var currentLeft = panel.offsetLeft;
panel.style.width = (currentWidth - (event.clientX - currentLeft)) + "px";
}
function getSplitter() {
return document.getElementById('splitter');
}
var con = document.getElementById('container');
var splitter = document.createElement('div');
var glass = document.getElementById('glass');
splitter.className = 'splitter';
splitter.id = 'splitter';
con.insertBefore(splitter, con.lastElementChild);
splitter.addEventListener('mousedown', startDrag, false);
glass.addEventListener('mouseup', endDrag, false);
.container {
display: flex;
border: 1px solid;
width: 500px;
height: 300px;
position: absolute;
}
.c1 {
background-color: blue;
flex: 1;
height: 100%;
overflow: hidden;
}
.c2 {
background-color: green;
width: 150px;
}
.splitter {
width: 20px;
cursor: col-resize;
}
.glass {
height: 100%;
width: 100%;
cursor: col-resize;
display: none;
position: absolute;
}
.grandchild {
background-color: red;
width: 50px;
height: 50px;
}
<div id="container" class="container">
<div id="glass" class="glass"></div>
<div class="c1">
<div class="grandchild"></div>
</div>
<div id="c2" class="c2"></div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With