Reputation: 2662
Let's assume I have a collapsible fixed-width sidebar defined like this:
HTML
<div class="container">
<div class="sidebar" id="sidebar">
SIDEBAR
</div>
<div class="content">
lorem bla bla
<button onclick="document.getElementsByClassName('sidebar')[0].classList.toggle('collapsed')">
toggle Sidebar
</button>
</div>
</div>
CSS
body {
margin:0;
}
.container {
display: flex;
min-height:100px;
}
.sidebar {
position: relative;
left: 0;
width: 200px;
background-color: #ccc;
transition: all .25s;
}
.sidebar.collapsed {
left:-200px;
margin-right:-200px;
}
Codepen here: http://codepen.io/anon/pen/pJRYJb
How can I go from there to a flexible-width sidebar?
Here are the constraints:
The main issue here is that I can't find a way to say margin-right: -100%
where 100%
refers to the width of sidebar
Any help will be greatly appreciated!
Upvotes: 9
Views: 22500
Reputation: 1683
For what it's worth, I do have a partly js solution. The animation itself is done entirely with CSS, it just resolves the width:auto
problem. You just set the width of the sidebar domElement with js, when the element is loaded:
domElement.style.width = `${parseInt(domElement.offsetWidth)}px`;
This resolves the 'unknown' width problem. And you can use your .collapsed
approach just as you like to do. The only adjustment is that you'll need to add !important
to the .collapsed {width: 300px !important;}
width value.
Upvotes: 0
Reputation: 101
Piggy-backing off Pangloss' suggestion re: the transform... you can just apply a negative margin to the content if you know the width of the sidebar. No need to have the sidebar switch to absolute positioning.
@mixin transitionAll() {
transition: all .3s ease-out;
}
html, body {
height: 100%;
}
.container {
display: flex;
width: 100%;
height: 100%;
}
.sidebar {
flex: 1 0 300px;
background: #333;
height: 100%;
@include transitionAll();
&.is-collapsed {
transform: translateX(-100%);
}
}
.content {
width: 100%;
height: 100%;
padding: 1rem;
background: #999;
@include transitionAll();
&.is-full-width {
margin-left: -300px;
}
}
--
<div class="container">
<aside class="sidebar">
</aside>
<section class="content">
<button class="btn btn-primary">Toggle</button>
</section>
</div>
--
$(function() {
$('.btn').on('click', function() {
$('.sidebar').toggleClass('is-collapsed');
$('.content').toggleClass('is-full-width');
});
});
See the Pen LxRYQB by Jason Florence (@JFlo) on CodePen.
Upvotes: 0
Reputation: 78686
How about changing the width
instead of position
on click? I use max-width
in this case, it works almost the same as unknown width. This will probably cause the content reflow on the sidebar, so use white-space:nowrap
if it's acceptable.
body {
margin: 0;
}
.container {
display: flex;
}
.sidebar {
background: #ccc;
transition: all .1s;
max-width: 1000px;
}
.sidebar.collapsed {
max-width: 0;
overflow: hidden;
}
<div class="container">
<div class="sidebar" id="sidebar">SIDEBAR</div>
<div class="content">lorem bla bla
<button onclick="document.getElementsByClassName('sidebar')[0].classList.toggle('collapsed')">toggle Sidebar</button>
</div>
</div>
Another workaround is using transform
width position
together, but the animation effect will be slightly different.
body {
margin: 0;
}
.container {
display: flex;
}
.sidebar {
background: #ccc;
transition: all .1s;
}
.sidebar.collapsed {
transform: translateX(-100%);
position: absolute;
}
<div class="container">
<div class="sidebar" id="sidebar">
<div>SIDEBAR</div>
</div>
<div class="content">lorem bla bla
<button onclick="document.getElementsByClassName('sidebar')[0].classList.toggle('collapsed')">toggle Sidebar</button>
</div>
</div>
Upvotes: 4