Yii 1.1: Creating a CSS Driven Drop Down Menu using CMenu

26 followers

CMenu offers great functionality and the ability to customize just about every aspect of the output. There are many times when I need to create a drop down menu or simply modify the look to make the designers happy. Because this seems to be a common task for me, I figured I would share my code to create a very simple drop down menu that other people could use.

There are many ways to approach this but I wanted to start out very simply so we are going to accomplish this using nothing but CSS.

Here is our desired output:

<div id="menu-top"> 
  <ul id="yw1">
    <li id="itemCompany"><a id="menuCompany" href="/company/index">Company</a>
      <ul>
        <li class="active"><a href="/company/index">Our Mission</a></li>
        <li><a href="/company/aboutUs">About Us</a></li>
        <li><a href="/company/careers">Careers</a></li>
        <li><a href="/company/contactUs">Contact Us</a></li>
        <li><a href="/company/storeLocator">Store Locator</a></li>
      </ul>
    </li>
    <li><a id="menuBlog" href="/blog/post/index">Blog</a></li>
    <li id="itemChange"><a id="menuChange" href="/change/index">Change</a>
      <ul>
        <li><a href="/change/index">Community Involvement</a></li>
        <li><a href="/change/ecoPolicy">Eco Responsibility</a></li>
        <li><a href="/change/responsibility">Responsibility</a></li>
      </ul>
    </li>
    <li><a id="menuBuy" href="/shop">Shop</a></li>
  </ul>
</div>

And here is the code we are going to use to create this output:

<div id="menu-top">
<?php
$this->widget('zii.widgets.CMenu',array(
  'activeCssClass'=>'active',
  'activateParents'=>true,
  'items'=>array(
    array(
      'label'=>'Company',
      'url'=>array('/company/index'),
      'linkOptions'=>array('id'=>'menuCompany'),
      'itemOptions'=>array('id'=>'itemCompany'),
      'items'=>array(
        array('label'=>'Our Mission', 'url'=>array('/company/index')),
        array('label'=>'About Us', 'url'=>array('/company/aboutUs')),
        array('label'=>'Careers', 'url'=>array('/company/careers')),
        array('label'=>'Contact Us', 'url'=>array('/company/contactUs')),
        array('label'=>'Store Locator', 'url'=>array('/company/storeLocator')),
      ),
    ),
    array(
      'label'=>'Blog',
      'url'=>array('/blog/post/index'),
      'linkOptions'=>array('id'=>'menuBlog')
    ),
    array(
      'label'=>'Change',
      'url'=>array('/change/index'),
      'linkOptions'=>array('id'=>'menuChange'),
      'itemOptions'=>array('id'=>'itemChange'),
      'items'=>array(
        array('label'=>'Community Involvement', 'url'=>array('/change/index')),
        array('label'=>'Eco Responsibility', 'url'=>array('/change/ecoPolicy')),
        array('label'=>'Responsibility', 'url'=>array('/change/responsibility')),
      ),
    ),
    array(
      'label'=>'Shop',
      'url'=>array('/shop'),
      'linkOptions'=>array('id'=>'menuBuy')
    ),
  ),
)); ?>
</div>

Let's dig into the code to see what is happening here.

CMenu::activeCssClass is simply the CSS class that will be assigned to the active menu item. The active menu item simply indicates the current page you are viewing by adding some style to that menu link. CMenu::activateParents means that when a child item is activated, the parent of that item will be given the 'active' css class assignment as well.

You will notice that the 'Company' item has another CMenu::items array set under it that will be the items that show up in the drop down when a user hovers over 'Company' in the menu.

Also, in the parent items ( Company, Blog, Affecting Change, Shop ) you will see that we take advantage of the CMenu::linkOptions property in order to add an ID to tag that Yii will output wrapping the label. I needed to do this because the menu I am creating uses sprites which means I need an ID for each menu item to specify the background-position property of each item independently.

Ok so now that we have our PHP setup, let's dig into the CSS part. I am also not going to include the code for the sprites to keep things simple.

#menu-top ul { list-style: none; margin: 0; padding: 0; position: relative; height: 30px; }
 
#menu-top ul li { display: block; height: 28px; float: left; overflow: visible; }
#menu-top ul li:hover > ul { display: block; }
 
#menu-top ul li a { float: left; display: block; }
 
#menu-top ul li ul { display: none; position: absolute; top: 100%;
                    background: #000; color: #fff; height: auto;
}
 
#menu-top ul li ul li a { color: #ccc; padding: 4px 14px; display: block; }
 
#menu-top ul li ul li.active a,
#menu-top ul li ul li a:hover { color: #fff; }

An important part to pay attention to is setting the overflow to visible on the '#menu-top ul li' elements. Otherwise, when you mouseover an parent item, the child items will not be visible.

The line that does all the magic is: #menu-top ul li:hover > ul { display: block; }

This simply means that when a user hovers over a parent item ( ul li ), take any child ul elements and switch them from 'display: none;' to 'display: block;' making them visible.

Once you put this all together, you should have a nice little drop down menu with active highlighting.

Total 10 comments

#18604 report it
reburg at 2014/11/29 01:45pm
Submenu disappears when mouse moves over it

Submenues disappeared when mouse moved over them. I could resolve this by changing the height values of the ul and the susequent li element to the same value. If the values are different, the above beahaviour occurs.

And I changed some other values a little, so the look of the submenues is the same as the main menu.

#mainmenu ul { list-style: none; margin: 0; padding: 0; position: relative; height: 26px; }
#mainmenu ul li { display: block; height: 26px; float: left; overflow: visible; }
#mainmenu ul li:hover > ul { display: block; }
#mainmenu ul li a { float: left; display: block; }
#mainmenu ul li ul { display: none; position: absolute; top: 100%; background: #589FC8; color: #fff; height: auto; width: auto; }
#mainmenu ul li ul li a { color: #fff; padding: 4px 14px; display: block; width: 120px;}
#mainmenu ul li ul li.active a, #mainmenu ul li ul li a:hover { color: #589FC8; }
#mainmenu ul li ul li { clear: left;}
#15082 report it
Gustavo Ramírez at 2013/10/05 01:41pm
3rd Level

Hey could you please modify the css for a 3rd level of links?

#14263 report it
Cam C at 2013/07/30 01:12pm
IE offsetting

Thank you BlindMoe for this tutorial.

It worked great for me, except in IE. I was testing in IE8. The drop down menu would be offset to the right.

So I added "right:0%" to this line to fix:

.menu-top ul li ul { display: none; position: absolute; top:100%; right:0%;
                    background: white; color: blue; height: auto;box-shadow: 0px 0px 6px 2px #666; border-radius:4px;
}
#9446 report it
zeroByte at 2012/08/11 05:00pm
works for me

... out of the box. I've modified the code according to my needs this way:

li.disabled a{ color:grey; }
.menu-top ul a, .menu-top ul a:hover{ text-decoration:none;}
.menu-top ul { list-style: none; margin: 0; min-width:150%; position: relative; height: 30px;}
 
.menu-top ul li { display: block; height: 28px;  overflow: visible; }
.menu-top ul li:hover > ul { display: block; }
 
.menu-top ul li a { float: left; display: block; }
 
.menu-top ul li ul { display: none; position: absolute; top:100%;
                    background: white; color: blue; height: auto;box-shadow: 0px 0px 6px 2px #666; border-radius:4px;
}
 
.menu-top ul li ul li a { padding: 4px 14px; display: block; }
 
.menu-top ul li ul li.active a,
.menu-top ul li ul li:hover { background-color:#F2FDFF;}
#7673 report it
The Zohan at 2012/04/08 08:53am
clear cubmenus

I implemented this on a fresh istall, ddn't work initially until i combined it with the default css which then i had the problem of submenus being displayed inline/horizontally next to each other instead of vertical. So i had to add this #top-menu ul li ul li{clear: left;} to make it work like i wanted it to

#7363 report it
rtenny at 2012/03/16 07:41pm
Thanks

Great news, I will try if I get it to work now. Thanks

#7362 report it
blindMoe at 2012/03/16 05:52pm
Updated so it works properly now

It looks like there was one css tag missing and that was a position: relative; on the first UL. It must have got cut off when I pasted in the code.

I also added in a couple of extras like the 'height' attribute on the first UL.

Here is the new line... I will update the article as well:

[css]

menu-top ul { list-style: none; margin: 0; padding: 0; position: relative; height: 30px;}

~~~

Don't forget the pound sign before 'menu-top'.. it was removed in my comment for some reason.

#7361 report it
coasa at 2012/03/16 05:37pm
Not Working

Tried several ways and its not working for me eather. I guess is time for a revision.

I think the problem its with the css, imho.

#6390 report it
rtenny at 2012/01/06 05:21pm
Will try again

thanks blindmoe,

I used another system as I needed something but I will try this again. I will post here if I got it to work.

#6380 report it
fleuryc at 2012/01/05 07:57am
nope

doesn't seem to be working here either...

Leave a comment

Please to leave your comment.

Write new article