-->

11/1/11

Menus desplegable de Matthew James Taylor






Horizontally Centered Drop-Down Menus

by Matthew James Taylor on 31 January 2010

Horizontally Centered Drop-Down Menus with Pure CSS

A lot of people try to customise my horizontally centred menus by adding drop-down sub-menus. This is a great idea but unfortunately it can be a bit tricky because the overflow:hidden; rule chops off the sub-menus and nothing is visible. For a CSS noob this can seem like an impossible problem to fix. I get regular emails about this issue so I've put together this detailed article to explain how it's done.


First, here is an example of a my horizontally centred menus with drop-down sub-menus:







Removing the overflow:hidden;

The secret to centred drop-down menus is removing the overflow:hidden; rule on the centeredmenu div. Unfortunately if we simply delete this rule, horizontal scrollbars may appear on the website. This happens because the invisible ul element sometimes extends off the righthand edge of the visible page. But don't worry, there is a solution to this. Luckily we can prevent the righthand overflow by horizontally flipping the menu elements so the ul extends off the left side of the screen instead. Here are the specific CSS changes we need to make: (bold = added, strikethrough = removed)


#centeredmenu {
   float:left;
   width:100%;
   background:#fff;
   border-bottom:4px solid #000;
   overflow:hidden;
   position:relative;
}
#centeredmenu ul {
   clear:left;
   float:left;

   float:right;
   list-style:none;
   margin:0;
   padding:0;
   position:relative;
   left:50%;
   right:50%;
   text-align:center;
}
#centeredmenu ul li {
   display:block;
   float:left;
   list-style:none;
   margin:0;
   padding:0;
   position:relative;
   right:50%;
   left:50%;

}
#centeredmenu ul li a {
   display:block;
   margin:0 0 0 1px;
   padding:3px 10px;
   background:#ddd;
   color:#000;
   text-decoration:none;
   line-height:1.3em;
}
#centeredmenu ul li a:hover {
   background:#369;
   color:#fff;
}
#centeredmenu ul li a.active,
#centeredmenu ul li a.active:hover {
   color:#fff;
   background:#000;
   font-weight:bold;
}


And here is a diagram of how the altered layout elements are positioned:


Nested element structure of the horizontally centered tabs

Notice how the pink ul element extends off the lefthand edge of the page. When something extends off the left side it's automatically cut off by the browser viewport so we don't need an overflow:hidden; rule anymore. Goodbye overflow:hidden;!


Adding the drop-down sub-menus

That is the hard part out of the way - now for the drop-down menus. Firstly, my drop-down menus use simple semantic HTML in the form of a div containing a nested list (one list within another). Here is the HTML:


<div id="centeredmenu">
   <ul>
      <li><a href="#">Tab one</a>

         <ul>
            <li><a href="#">Link one</a></li>
            <li><a href="#">Link two</a></li>

            <li><a href="#">Link three</a></li>
            <li><a href="#">Link four</a></li>
            <li><a href="#">Link five</a></li>

         </ul>
      </li>
      <li class="active"><a href="#" class="active">Tab two</a>
         <ul>
            <li><a href="#">Link one</a></li>

            <li><a href="#">Link two</a></li>
            <li><a href="#">Link three</a></li>
            <li><a href="#">Link four</a></li>

            <li><a href="#">Link five is a long link that wraps</a></li>
         </ul>
      </li>
      <li><a href="#">Long tab three</a>

         <ul>
            <li><a href="#">Link one</a></li>
            <li><a href="#">Link two</a></li>

            <li><a href="#">Link three</a></li>
            <li><a href="#">Link four</a></li>
            <li><a href="#">Link five</a></li>

         </ul>
      </li>
      <li><a href="#">Tab four</a>
         <ul class="last">
            <li><a href="#">Link one</a></li>

            <li><a href="#">Link two</a></li>
            <li><a href="#">Link three</a></li>
            <li><a href="#">Link four</a></li>

            <li><a href="#">Link five</a></li>
         </ul>
      </li>
   </ul>
</div>

And here is the CSS that makes it all happen. I'm breezing over this bit a little - if you want more info please read the comments in the CSS.



/* Main menu settings */
#centeredmenu {
   clear:both;
   float:left;
   margin:0;
   padding:0;
   border-bottom:1px solid #000; /* black line below menu */
   width:100%;
   font-family:Verdana, Geneva, sans-serif; /* Menu font */
   font-size:90%; /* Menu text size */
   z-index:1000; /* This makes the dropdown menus appear above the page content below */
   position:relative;
}

/* Top menu items */
#centeredmenu ul {
   margin:0;
   padding:0;
   list-style:none;
   float:right;
   position:relative;
   right:50%;
}
#centeredmenu ul li {
   margin:0 0 0 1px;
   padding:0;
   float:left;
   position:relative;
   left:50%;
   top:1px;
}
#centeredmenu ul li a {
   display:block;
   margin:0;
   padding:.6em .5em .4em;
   font-size:1em;
   line-height:1em;
   background:#ddd;
   text-decoration:none;
   color:#444;
   font-weight:bold;
   border-bottom:1px solid #000;
}
#centeredmenu ul li.active a {
   color:#fff;
   background:#000;
}
#centeredmenu ul li a:hover {
   background:#36f; /* Top menu items background colour */
   color:#fff;
   border-bottom:1px solid #03f;
}
#centeredmenu ul li:hover a,
#centeredmenu ul li.hover a { /* This line is required for IE 6 and below */
   background:#36f; /* Top menu items background colour */
   color:#fff;
   border-bottom:1px solid #03f;
}

/* Submenu items */
#centeredmenu ul ul {
   display:none; /* Sub menus are hiden by default */
   position:absolute;
   top:2em;
   left:0;
   right:auto; /*resets the right:50% on the parent ul */
   width:10em; /* width of the drop-down menus */
}
#centeredmenu ul ul li {
   left:auto;  /*resets the left:50% on the parent li */
   margin:0; /* Reset the 1px margin from the top menu */
   clear:left;
   width:100%;
}
#centeredmenu ul ul li a,
#centeredmenu ul li.active li a,
#centeredmenu ul li:hover ul li a,
#centeredmenu ul li.hover ul li a { /* This line is required for IE 6 and below */
   font-size:.8em;
   font-weight:normal; /* resets the bold set for the top level menu items */
   background:#eee;
   color:#444;
   line-height:1.4em; /* overwrite line-height value from top menu */
   border-bottom:1px solid #ddd; /* sub menu item horizontal lines */
}
#centeredmenu ul ul li a:hover,
#centeredmenu ul li.active ul li a:hover,
#centeredmenu ul li:hover ul li a:hover,
#centeredmenu ul li.hover ul li a:hover { /* This line is required for IE 6 and below */
   background:#36f; /* Sub menu items background colour */
   color:#fff;
}

/* Flip the last submenu so it stays within the page */
#centeredmenu ul ul.last {
   left:auto; /* reset left:0; value */
   right:0; /* Set right value instead */
}

/* Make the sub menus appear on hover */
#centeredmenu ul li:hover ul,
#centeredmenu ul li.hover ul { /* This line is required for IE 6 and below */
   display:block; /* Show the sub menus */
}

Highlighting the active menu

To highlight a top menu item simply include the class="active" on the corresponding li element.


Flipping the last sub-menu


As a nice little extra I have flipped the last menu item so it doesn't extend off the page. To do this across all common browsers you need to add the class="last" on the last submenu ul element. You can remove this class if you don't want that layout option.


F*cking Internet Explorer 6

Of course IE 6 always ruins the party. In old versions of IE the hover pseudo-class does not work on non-link elements. But don't worry I have a very simple fix for this ugly, ugly browser! I use IE conditional comments to expose a small piece of JavaScript that fixes the hover issue. The good news about this fix is all the standards-compliant browsers never see the JavaScript so only IE has to do this extra work. Here is the line of code required. It should be placed towards the end of the page or at least after the menu HTML.


<!--[if lt IE 7]><script type="text/javascript" src="iehoverfix.js"></script><![endif]-->

And here is the JavaScript. It simply adds a 'hover' class to li elements in the menu when they are hovered. We use this class in the CSS the same way we use the hover pseudo-class (refer to CSS comments).


function addhover() {
   var navli,i;
   // loop through all elements in the nav
   navli = document.getElementById('centeredmenu').getElementsByTagName('li')
   for(i=0;i<navli.length;i++) {
      // add the hover functions to the li onmouseover and onmouseout
      navli[i].onmouseover=function(){hover(this,'hover');};
      navli[i].onmouseout=function(){hover(this,'');};
   }
}
function hover(o,sClass) {
   if (o) {
      o.className = sClass;
   }
}
addhover();

That's it!




Check out the horizontally centred drop-down menus demo page and don't forget to check out my original centered menu article for the finer points on the centering process.


Handy file links


Other notes about this layout...


No CSS Hacks


There is never any need for CSS hacks. This centered menu uses hack-free CSS and is 100% valid.


Valid XHTML strict markup

The HTML in these centered menus validates as XHTML 1.0 strict. Please note that my blog has some XHTML errors so if you want to do a W3C validation please use my demo page.


Resizable text compatible

These centered tabs are fully compatible with resizable text. Resizable text is important for web accessibility. People who are vision impaired can make the text larger so it's easier for them to read. It is becoming increasingly important to make your website 'resizable text' compatible because people are expecting higher levels of web accessibility.


Full cross-browser compatibility

The horizontally centered drop-down menus have been tested on the following browsers:


iPhone and iPod Touch

  • Safari

Mac

  • Safari
  • Firefox 2 and 3
  • Opera

Windows

  • Firefox 2 and 3
  • Safari
  • Opera
  • Google Chrome
  • Internet Explorer 5.5, 6 and 7


Enjoy this article?

If you find my website useful, feel free to donate any amount you wish. It will help pay for my hosting! =)






Matthew James Taylor




No hay comentarios:

Publicar un comentario