SharePoint Navigation – CSS only accordion on hover effect

Everyone seems to love accordion navigation effects and I love CSS so it was only natural to try to implement an accordion effect for SharePoint navigation using only CSS. Typically folks use JavaScript or jQuery to add in an accordion, but it is possible to do it with pure CSS. When it comes to SharePoint there is only one caveat – you can create a CSS only accordion menu as long as the accordion effect fires on hover and not when the navigation header is clicked. Let’s see why, and let’s see how…
If you want to skip the why and you can go straight to the how.

Pure CSS accordion menu effect, outside of SharePoint

There are lots of demos out there for creating an accordion menu effect using only CSS. All of these techniques have two types of content:

  • What you click/mouse over to toggle the accordion (typically a header)
  • What is hidden/displayed when you toggle the accordion (typically a block of content or a list of navigation items)

These techniques also rely on the presence of one of two HTML elements:

  • Anchors where the href attribute points to a location within the page, for example:  <a href="#section">
  • Form inputs (typically checkboxes)

Once all of these HTML elements are in place you can use CSS to style the headers and to hide the accordion content that should be displayed on toggle.  Then using CSS and the :checked pseudo-class for form inputs or the :target pseudo-class for the anchor,  the hidden accordion content is displayed when the user “checks” the form input or “clicks” the hyperlink (since the link has no real target the user is not taken to a different web page).  It is nice and tidy and widely supported with the exception of IE 6, 7 & 8.  For those browser versions you can use something like Selectivizr to create support.

Why this falls apart in SharePoint

The generated SharePoint navigation, like lots of areas within SharePoint, is locked down and you can’t edit the HTML that is generated for the menu.  Also by default, all of the navigation items are links to different pages so an accordion would be useless because when you selected an item it would not get a chance to show the hidden accordion content before it runs off and changes the page.

Insert custom headings via the Navigation settings

Luckily in SharePoint you can create your own navigation headers that don’t link to anything.  This takes care of the issue of the page changing when you want instead to show accordion content.  But when you don’t specify a target URL for a custom header in the SharePoint navigation settings, you only get the simple SPAN tags in the generated navigation HTML and not the anchor tag.  And unfortunately you can’t specify an in-page anchor like “#” or do other tricks like “javascript:function Z(){Z=''}Z()“. The result is you can’t include the anchor tag in your HTML. So this knocks out one of the two ways to show the accordion content (via clicking an anchor).

Going back to no custom HTML

Lest we forget that we can’t modify the HTML generated for the navigation, so there is no way to use the form input method either for showing accordion content.

The final verdict

Both of these methods…

  • Code includes anchors where the href attribute points to a location within the page, for example:  <a href="#section">
  • Code includes form inputs (typically checkboxes)

…are non-starters for SharePoint.  Hence why you can’t do an accordion menu that is activated via a user clicking navigation header text.

All is not lost, use the :hover pseudo class

One thing I love in CSS is the :hover pseudo-class. It isn’t picky, it doesn’t require an anchor tag.  You can slap that baby on to most anything and when you hover over that element on the page, be it a link, a header, a DIV or a random bulleted list item, it can have a hover effect.  By using the :hover pseudo-class we can find a compromise for an accordion styled navigation menu in SharePoint.

The ugly side of this approach

First off, a JavaScript or jQuery solution for an accordion effect is going to be the more elegant way to go.  You just get the flexibility you need once you move over to scripting.  However, if you need a CSS only solution it is possible.  There is just one burp along the way that creates some jagged usability.  More on that later.

Create an accordion on hover effect for SharePoint using only CSS

  1. First you need to add the headers to the SharePoint navigation.  For this example I am using the quick launch nav (a.k.a. current navigation, a.k.a. left navigation bar) This can be done in SharePoint 2010 or SharePoint 2013 (managed or structured navigation).  Go to the SharePoint site settings and select Navigation. Create your headers, not specifying a target link.
  2. Organize your links under the newly created headers.  For example:
    Organize links under headers
  3. Now you are ready to move to a custom CSS file. To hide the accordion content, which in this case is the two sets of links under Group Header 1 and 2, use the following CSS code for SharePoint 2013:
    .ms-core-listMenu-verticalBox li.static {
        height: 2em;
        overflow: hidden;
    }

    Or the following code for SharePoint 2010:

    .s4-ql li.static {
        height: 2em;
        overflow: hidden;
    }

    If your headings wrap to multiple lines *consistently*, you will need to adjust the height value. For example if all the headers wrap to two lines.  However if the headings have variable length text and some wrap to multiple lines while others do not, you will need to use different CSS. For this skip to step 5.

  4. Next you need to add a little CSS to show the content when you hover over the group header. For SharePoint 2013 you will add this:
    .ms-core-listMenu-verticalBox li.static:hover {
        height: auto;
    }

    Or for SharePoint 2010 you will add this:

    .s4-ql li.static:hover {
        height: auto;
    }

    If this does the trick for you, you can skip step 5 and go to the next section.

  5. If you have variable length headings, you will need to use different CSS. For SharePoint 2013:
    .ms-core-listMenu-verticalBox li.static ul.static {
        display: none;
    }
    
    .ms-core-listMenu-verticalBox li.static:hover ul.static {
        display: block;
    }

    Or the following code for SharePoint 2010:

    .s4-ql li.static ul.static {
        display: none;
    }
    
    .s4-ql li.static:hover ul.static {
        display: block;
    }

    This code works for structured or managed navigation and for any length heading. What you can’t do with this code is add a CSS3 transition to get an accordion slide effect (last section of this post).

Surprisingly, that is it! Now this CSS does not style your headers and content, it only gives you the hide/show effect. You can keep going to make it fancy.

The burp

Previously I mentioned there was a bit of a burp for usability when you use this method.  If you have more than one heading on your site, mouse over the first heading (and let the accordion content show), then mouse straight down to the next heading.  When you hit heading #2 the accordion content will show and heading #1 content will disappear, thus making heading #2 content slide up to take its place. If you have a short list of content, the heading #2 content will slide right out from under your mouse thus killing the hover state and heading #2 content will also disappear.

Adding more to the styles

From this point forward the code samples will be for SharePoint 2013. However, any of this CSS can be used for SharePoint 2010. Just replace .ms-core-listMenu-verticalBox with .s4-ql in the CSS style statements below.

It is also easier to comment out the CSS code that creates the hide/show for accordion content until you are done styling the menu.

Create basic formatting for the menu

Make the headers appear as links

The header text is just plain text that is not wrapped in an anchor tag. When the user hovers over the text they will not get the typical “hey pal, this is a link” style cursor.  So we need to add to the CSS to change the text to look like a link when you hover over it.

.ms-core-listMenu-verticalBox li > span.menu-item {
    cursor: pointer;
}

Add to the header formatting

You can continue to jazz it up:

/* Format the headers */
.ms-core-listMenu-verticalBox li > span.menu-item {
    cursor: pointer;
    background: #0171C6;
    color: white;
    border: solid #fff;
    border-width: 1px 0;
}

Add style to the accordion content

Next you can add some style to the accordion content:

/* Format the accordion list items */
.ms-core-listMenu-verticalBox a.menu-item {
    color:#000;
    background:#C9D4FF;
    border:1px solid #97C8F7;
    border-bottom:none;
}

Put in a hover effect and style the selected item

/* Format the header hover, list item hover and currently selected item */
.ms-core-listMenu-verticalBox li > span.menu-item:hover, /*Header */
.ms-core-listMenu-verticalBox a.selected, /* Selected */
.ms-core-listMenu-verticalBox a.menu-item:hover /* List item */{
    color:#FFF;
    background:#073D7D;
}

Add a CSS3 transition

If you want to get really fancy you can tweak the hide/show CSS code to include a CSS transition.  Just be aware that it will further accentuate the usability issue previously mentioned.

.ms-core-listMenu-verticalBox ul.root > li.static {
    max-height: 2em;
    overflow: hidden;
    transition: max-height 1s linear;
}

.ms-core-listMenu-verticalBox ul.root > li.static:hover {
    max-height: 500px;
}