Off Canvas Panels Pattern

In this pattern each section of content (menu, main content, sidebar) is considered to be a panel. On the smallest screens only one panel will show at a given time.

Each panel has a corresponding navigation button to call it. Regardless of which panel is currently showing, clicking the button of another panel brings that panel to the viewport.

The HTML

The html structure has now changed from the previous two patterns. All 3 panels are enclosed in the .wrapper and .inner divs. The subfooter and footer are outside these containers as is the header, which contains the panel buttons.

The click even for the panel buttons are radio buttons. The event works similarly to the checkbox hack, though instead of on and off, we now choose which button is selected and thus which panel will show.

<header>
  <div id="panel-nav">
    <label class="btn btn-1" for="toggle-1" onclick>Menu</label>
    <label class="btn btn-2" for="toggle-2" onclick>Content</label>
    <label class="btn btn-3" for="toggle-3" onclick>More</label>
  </div>
</header>
		
<input id="toggle-1" name="panel" type="radio" />
<input id="toggle-2" name="panel" type="radio" />
<input id="toggle-3" name="panel" type="radio" />

<div class="wrapper">
  <div class="inner">

    <nav>
      <ul id="nav">
        <li><a href="">Back to Post</a></li>
        <li><a href="sidebar-nav.html">Sidebar Nav</a></li>
        <li><a href="sidebar-nav-js.html">Sidebar Nav JS</a></li>
        <li class="current"><a href="panels.html">Panels</a></li>
        <li><a href="sidebar+.html">Sidebar+</a></li>
      </ul>
    </nav>

    <div class="container main-content">
      <div id="content"></div>
    </div>

    <div id="sidebar"></div>
  </div>
</div>

<section class="subfooter"></section>
<div id="footer"></div>
					

The Default CSS

Some of the default css is the same as for the other patterns. What's below is where things differ. First since we have 3 radio buttons all 3 need to be hidden.

The general idea for the rest is the wrapper is set to 100% width and to hide any overflow. The inner div is set to 300% width, with each panel being 1/3 of that 300%.

The .inner div starts our with a margin-left of -100% so the middle panel is displayed.

#toggle-1, #toggle-2, #toggle-3 {
  position: absolute;
  left: -999em;
}

nav {
  float: left;
  padding: 0;
  background: #3b3736;
  height: 100%;
  width: 33.334%
}

.main-content {
  float: left;
  width: 33.333%
}

#sidebar {
  float: left;
  padding: 0 2%;
  height: 100%;
  width: 33.333%
}

.wrapper {
  width: 100%;
  overflow: hidden;
}

.inner {
  width: 300%;
  margin-left: -100%;

  -webkit-transition: margin 0.5s;
     -moz-transition: margin 0.5s;
      -ms-transition: margin 0.5s;
       -o-transition: margin 0.5s;
          transition: margin 0.5s;
}
					

The CSS to Toggle the Panels

Toggling the panels turns out to be quite simple. The left margin of the .inner div is modified depending on which radio button is checked.

#toggle-1:checked ~ .wrapper .inner {
  margin-left: 0%;
}

#toggle-2:checked ~ .wrapper .inner {
  margin-left: -100%;
}

#toggle-3:checked ~ .wrapper .inner {
  margin-left: -200%;
}
					

The CSS in Media Queries

Once the browser is wide enough we can show multiple columns at once. At 48em (~768px) we'll show two columns. On page load we'll show the menu and main content and have the sidebar be offscreen right.

The main content will always show so we'll remove its button. The css below only shows the adjustments made to the width of the divs and the new margins needed depending on which button is currently checked.

@media screen and (min-width: 48em) {
  .inner {
    width: 150%;
    margin-left: 0;
  }
	
  nav {
    width: 25%;
    background: none;
  }

  .main-content {
    width: 40%;
  }
	
  #sidebar {
    width: 25%;
    margin-top: 3em;
  }

  #toggle-1:checked ~ .wrapper .inner {
    margin-left: 0%;
  }
	
  #toggle-2:checked ~ .wrapper .inner {
    margin-left: 0%;
  }
	
  #toggle-3:checked ~ .wrapper .inner {
    margin-left: -37%;
  }
}