Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collapsible flexible-width sidebar using only CSS

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

So here's the question:

How can I go from there to a flexible-width sidebar?

Here are the constraints:

  • no javascript (I want the browser to deal with the layouting – not me)
  • the sidebar must not overlap the content
  • when collapsed, the sidebar's right border needs to be aligned with the window's left border (to be able to attach an absolutely positioned tab on the right side that's always visible)
  • the width of the sidebar shouldn't change if collapsed to avoid reflows during the transition
  • smooth transition without any sudden jumps
  • modern CSS (flexboxes, calc) is fine

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!

like image 260
Daniel Avatar asked Jun 01 '15 13:06

Daniel


1 Answers

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.

http://jsfiddle.net/dn4ge901/

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.

http://jsfiddle.net/vkhyp960/

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>
like image 68
Stickers Avatar answered Nov 15 '22 04:11

Stickers