Making CSS-only pop-out menus

Large, informative footers, like the ones at Apple.com and Mozilla.com, are all the rage among web designers nowadays, but for sites with very long pages, like cloudscape, the old, reliable sidebar might be a more practical option. Why inconvenience your reader to scroll all the way to the end of the page?

I decided to go one step further with the sidebar: Why not make a minimal, floating sidebar which would expand only when necessary? Since I planned to make and post many images to cloudscape;, I wanted the area for content to be as wide as possible. Furthermore, I didn’t want a blocky sidebar to grab the glory.

Below, I present my solution (which is also in use right now, if you’re not using IE version 8 or earlier; check out the left side of the screen!). As I promised in an earlier post, my sidebar uses only HTML and CSS; no Javascript is necessary. This ensures that the sidebar will load faster and will work even on browsers with Javascript turned off.

The HTML

There are four basic elements to my CSS-only menu:

CSS-only menus have only 4 basic parts.
  1. #floatnav
    A <div> that contains the entire sidebar.
  2. .floatbutton
    <div>s that each contain one menu icon and one .popoutpanel <div>.
  3. menu icon
    A regular image that you want to use as an icon in your sidebar.
  4. .popoutpanel
    <div>s that pop out upon hover and display content.

So, if we had just two sections in our sidebar, our HTML code looks like this:

<div id="floatnav">

  <div class="floatbutton">
    <img src="img/about.png" height="50" width="50" alt="About" />
    <div class="popoutpanel">
        <!-- your content here -->
    </div>
  </div>

  <div class="floatbutton">
    <img src="img/tags.png" height="50" width="50" alt="Tags" />
    <div class="popoutpanel">
        <!-- your content here -->
    </div>
  </div>

</div>

If you need more sections, you would just insert more .floatbutton <div>s.

The CSS

Right now, we have something like this:

How the menu looks sans CSS.

Quite a mess. But we can fix that, all with CSS.

Firstly, we’ll need to set the dimensions of the elements so that they don’t expand to the width of the browser window. Let’s start on getting .popoutpanel to look good first:

.popoutpanel {
   padding: 10px 20px 15px;
   width: 200px; }
Menu with only width and padding set for .popoutpanel.

Next, I need to style .floatbutton. The interesting thing about this is, the height and width I use in the stylesheet is the same as the menu icon’s height and width.

.floatbutton { 
   padding: 5px 30px 5px 15px;
   height: 50px;
   width: 50px; }

You might think this wouldn’t work, since .floatbutton contains .popoutpanel, and .popoutpanel is an element that I’ve set four times as wide (200px). However, it does work in all modern browsers, since overflow is set to visible by default. (Note that overflow is not supported in IE versions 8 and earlier, and so this sidebar does not work in those versions of IE.)

We now have this huge mess:

Menu with .floatbutton dimensions set.

Not to worry though. First, let’s force .popoutpanel to appear beside the menu icon, by

  1. setting a left margin that is equal to the full width of .floatbutton — that is, the width + margin-left + margin-right. Here, width = 50px, and the left and right margins are each 5px, so the total width of .floatbutton is 60px.
  2. setting a negative top margin that is equal to the height of .floatbutton. A negative top margin is necessary because the .popoutpanel naturally follows the icon, but you need to move it up so it appears at the same level as the icon. Depending on your icons and how you’ve styled your .popoutpanel, you may need a different value for the top margin, but the height of the icon — 50px — works for me here.
.popoutpanel { 
   margin: -50px 0 0 60px; 
   padding: 10px 20px 15px;
   width: 200px;  }
Force panels to appear beside the icons instead of under them.

The menu icons are looking great now, all on their own. All the .popoutpanel <div>s are running into each other, but that’s okay. Remember, only one panel will be showing at any given time once the hover is set up, so we can ignore the current chaotic overlap.

To set up the hover, we first tell the browser to hide the .popoutpanel contained in .floatbutton all the time:

div.floatbutton .popoutpanel { 
    display: none; }

In the next line, we tell the browser that we actually want to see the .popoutpanel contained in the .floatbutton, but only when we hover over .floatbutton.

div.floatbutton:hover .popoutpanel { 
    display: block; }

And tada! We’ve got functional pop-out panels.

No hover versus hover over the About icon.

Finally, to make the entire sidebar to stay fixed to the edge of the browser window, we fix the position of #floatnav:

#floatnav {
   position: fixed;
   top: 150px;
   left: 0;  }

Remember to not set the top value too large; while most people have pretty high screen resolutions these days, there may still be people working with a screen height of 900px or less. Also, if top is too large, then any super long .popoutpanel‘s will get cut off, and since the sidebar’s position is fixed, the viewer won’t be able to view the part of the .popoutpanel at all:

A fixed menu can get cut off if it is too long or if the screen resolution is small.

Additional features

Changing opacity of menu icons upon hover

Like how we made .popoutpanel appear only upon hover, we can do the same for just .floatbutton. First, we set a low opacity for .floatbutton (10% here):

div.floatbutton { 
   opacity: .1; 
   filter:alpha(opacity=10); }

Then, we instruct the browser to increase the opacity (to 100%) when someone hovers over .floatbutton:

div.floatbutton:hover { 
   opacity: 1; 
   filter:alpha(opacity=100); }

We need two different properties for opacity, because IE only understands filter, not opacity. All the other browsers use opacity.

Scrolling panels

You might’ve noticed my Tags and Archive panels scroll:

These panels have an additional internal sidebar.

I added this functionality to these panels specifically, because I know Tags and Archives sections can both become excessively long. As I’ve mentioned before, overly long .popoutpanel‘s get cut off and become completely unviewable. What you can do for such panels is to limit their height, and allow any overflow to scroll.

Firstly, I add an extra div within the .popoutpanel, called .scrollpanel:

<div class="floatbutton">
  <img src="img/about.png" height="50" width="50" alt="About" />
  <div class="popoutpanel">
      <div class="scrollpanel">
         <!-- content here scrolls -->
      </div>
  </div>
</div>

Then using CSS, I force the .scrollpanel to have a height of 300px. This stops the entire .popoutpanel from expanding to fit the content. I then set overflow-y for .scrollpanel to auto, which forces a scrollbar when the content gets to be a bit too much to fit in a 300px-high box.

.scrollpanel { 
  height: 300px; 
  overflow-y: auto; }

The reason I don’t just set overflow-y to scroll is because this puts a scrollbar in even if your content fits into the box without overflowing. I don’t want a scrollbar showing up if it’s unnecessary.

Setting overflow-y to [scroll] gives you a scrollbar even when it is obvious you do not need one. Thus, use [auto] instead.

Technically, you could just set height and overflow-y for .popoutpanel, but since I had small panels (like About) that I wanted to keep small, I added the extra class .scrollpanel so I could target the Tags and Archives panels separately.

Sidebars: Before or after main content?

Whether you put the menu before or after your content won’t really affect the layout, but it’s preferable to put it after your content. It allows for better SEO, for those using text-only browsers or caret browsing to get to your content without needing to go through all the stuff in your sidebar, and for you to float the sidebar as a footer in IE6-8, because the .popoutpanel <div>s don’t appear in those browsers. (You could also set the sidebar to appear as a normal, static sidebar in IE6-8 too, but I preferred a footer over that.)

Sidebar is set to appear as a footer in IE8.

Recap

Here’s the entire basic stylesheet:

#floatnav {
   position: fixed;
   top: 150px;
   left: 0; }

.floatbutton { 
   padding: 5px 30px 5px 15px;
   height: 50px;    
   width: 50px; }

.popoutpanel { 
   margin: -50px 0 0 60px; 
   padding: 10px 20px 15px; 
   width: 200px; }

div.floatbutton { 
   opacity: .1; 
   filter:alpha(opacity=10); }

div.floatbutton:hover { 
   opacity: 1; 
   filter:alpha(opacity=100); }

div.floatbutton .popoutpanel { 
   display: none; }

div.floatbutton:hover .popoutpanel { 
   display: block; }

.scrollpanel { 
   height: 300px; 
   overflow-y: auto; }

Throw in some colours, fonts, and content, and you’ll have a rocking, interactive sidebar that only relies on CSS. Have fun!

  • Finslap88

    This is perfect, thanks so much!!

  • Eden

    This is just what I was looking for! Took me a while..but you came to my rescue. :)