Thursday 17 May 2012

Show and hide, simply, using CSS

I was recently laying out a new HTML5 website.  I needed a list in a sidebar to act like a vertical menu, with sub-items hidden until the parent item was hovered over.

In previous situations I would have used javascript to show and hide the items using a unique element id.  This method is a bit passe these days, so here is my CSS solution.

We'll start with a handful of nested lists


<!DOCTYPE html>   <!-- HTML5 document declaration -->
<html lang="en">
   
    <head>      
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>ShowHideDemo</title>
        
      <style type="text/css">
        
       </style>
    </head>

    <body>
        <ul>
            <li>Fruit
                <ul>
                    <li>Apple</li>
                    <li>Orange</li>
                    <li>Banana</li>
                </ul>
            </li>
            <li>Animals
                <ul>
                    <li>Goat</li>
                    <li>Sheep</li>
                    <li>Pig</li>
                </ul>
            </li>
            <li>Paint.NET   
                <ul>
                    <li>Plugins</li>
                    <li>Layers</li>
                    <li>Forum</li>
                </ul>
            </li>
        </ul>
   
    </body>   
</html>


We want to hide the sub-items by default.  We can achieve this with a tiny little bit of CSS.  Place the following snippet in between the style tags in the above document.


                li ul {display: none }


This tells us that any Unordered List (ul) that is a child of a List Item (li) should not be displayed.  Easy.

Now we want to display the hidden items when the parent item receives the focus (hover).  Add this line of CSS below the last one, keeping it inside the style tags.



                   li:hover ul {display: block}



This states that any Unordered List (ul) that is a child of a List Item (li) that has the focus (hover) should be displayed (as a block).

That's it!   Mousing over the parent item, displays the sub-menu.  Just what I wanted.  Of course there is still a little styling to be done, but this doesn't change the core code of the effect.



<!DOCTYPE html>   <!-- HTML5 document declaration -->
<html lang="en">
  
    <head>     
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>ShowHideDemo</title>
        <style type="text/css">
                li ul {
                      display: none;  
                      width: 200px;   
                        -webkit-border-top-right-radius: 8px;
                       -webkit-border-bottom-left-radius: 12px;
                      -moz-border-radius-topright: 12px;
                      -moz-border-radius-bottomleft: 12px;
                      border-top-right-radius: 12px;
                      border-bottom-left-radius: 12px;
                     -webkit-box-shadow: 2px 2px rgba(0,0,0,.6);
                     -moz-box-shadow: 2px 2px 2px rgba(0,0,0,.6);
                     box-shadow: 2px 2px 2px rgba(0,0,0,.6);
                     background: #DFFF8E; 
}
                li:hover ul {
                  display: block;
                  position: relative;
                 margin-bottom: 8px;
                 -webkit-animation: fadeIn 1s;
                 -moz-animation: fadeIn 1s;
                -ms-animation: fadeIn 1s;}
  
    @-webkit-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

@-moz-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}

@-ms-keyframes fadeIn {
    from { opacity: 0; }
      to { opacity: 1; }
}
        </style>
    </head>

    <body>
  
        <ul>
            <li>Fruit
                <ul>
                    <li>Apple</li>
                    <li>Orange</li>
                    <li>Banana</li>
                </ul>
            </li>
            <li>Animals
                <ul>
                    <li>Goat</li>
                    <li>Sheep</li>
                    <li>Pig</li>
                </ul>
            </li>
            <li>Paint.NET  
                <ul>
                    <li>Plugins</li>
                    <li>Layers</li>
                    <li>Forum</li>
                </ul>
            </li>
        </ul>
  
    </body>
     
</html>


Here we're using some color, width, rounded corners and shadowing to style the sub-menu.  All using CSS.  The final touch is a nice little transition which fades the sub-menu in  using the opacity value.

So why didn't I use display:block and display:none instead of the visibility: hidden statement? 

Simple: the visibility:hidden statement does not display the item, but it does display the same amount of whitespace that the content would have taken if it were visible.  This would have spaced out my parent menu items rather than keeping them together.

Note:  I'd always use separate style sheets.  The code shown above includes the styling to make copying and pasting easier.


No comments:

Post a Comment