0

Working on a menu bar that has counter active css classes. I need the menu bar centered and the drop downs to be under the proper list item. I can get one or the other but not both to work at the same time. The menu bar changes sizes, so putting a static margin left on it will not work. This is what the menu bar should look like but it's not centered. enter image description here

And this is what happens when i remove the float: left from #mainmenu ul li{}. It's now centered, but the items that belong under the user name are all shifted left.

enter image description here

Why does this happen? and how do i get around it?

html:

<div id="mainmenu">
    <?php
    if(Yii::app()->user->name)
    $display_name = Yii::app()->user->name;
    if(strlen($display_name) > 11){
        $display_name = substr($display_name,0,9);
        $display_name =$display_name.'...';
    }
    ?>
    <?php $this->widget('zii.widgets.CMenu',array(
        'items'=>array(
            array('label'=>'Home', 'url'=>array('/site/index')),
            array('label'=>'My Tickets', 'url'=>array('/ticket/mytickets'), 'visible'=>!Yii::app()->user->isGuest),
            array('label'=>'About', 'url'=>array('/site/page', 'view'=>'about')),
            array('label'=>'Contact', 'url'=>array('/site/contact')),
            array('label'=>'Schools', 'url'=>array('/school'), 'visible'=>Yii::app()->user->id == 'admin'),
            array('label'=>'Teams', 'url'=>array('/team'), 'visible'=>Yii::app()->user->id == 'admin'),
            array('label'=>'Login', 'url'=>array('/site/login'), 'visible'=>Yii::app()->user->isGuest),
            array('label'=>'Games', 'url'=>array('/game'), 'visible'=>Yii::app()->user->id == 'admin'),
            array('label'=>'Users', 'url'=>array('/user'), 'visible'=>Yii::app()->user->id == 'admin'),
            array('label'=>'Tickets', 'url'=>array('/ticket'), 'visible'=>Yii::app()->user->id == 'admin'),
            array('label'=>'Team Placement', 'url'=>array('/tournamentresults'), 'visible'=>Yii::app()->user->id == 'admin'),
            array('label'=>$display_name, 'url'=>array('#'), 'visible'=>!Yii::app()->user->isGuest,
                    'items' => array(
                array('label'=>'Edit User', 'url'=>array('/company/index')),
                array('label'=>'Log-out', 'url'=>array('/site/logout'))
    ),


            ),
        ),
    )); ?>
</div><!-- mainmenu -->

Generated HTML code:

<div id="mainmenu">
   <ul id="yw0">
    <li class="active"><a href="/index.php/site/index">Home</a></li>
    <li><a href="/index.php/ticket/mytickets">My Tickets</a></li>
    <li><a href="/index.php/site/page?view=about">About</a></li>
    <li><a href="/index.php/site/contact">Contact</a></li>
    <li><a href="/index.php/site/#">SirRahal</a>
        <ul>
            <li><a href="/index.php/company/index">Edit User</a></li>
            <li><a href="/index.php/site/logout">Log-out</a></li>
        </ul>
    </li>
    </ul>    
</div>

CSS code:

 #mainmenu
{
height:33px;
margin: auto;
text-align:center;
}

#mainmenu ul li
{
display: inline;
float: left;
margin: auto;
}

#mainmenu ul li a
{
color: #fbf3e1;
font-size:14px;
padding-top:5px;
padding-bottom:5px;
width:217px;
background: #33332c;
}

#mainmenu ul li ul {
display: none;
position: absolute;
margin-left: -20px;
}

#mainmenu ul li:hover > ul {
display: block;
}

#mainmenu ul li a:hover, #mainmenu ul li.active a
{
color: #f5921e;
border-bottom: solid 5px #f5921e;
text-decoration:none;
border-bottom-right-radius: 5px;
border-bottom-left-radius: 5px;
}
Devin
  • 7,690
  • 6
  • 39
  • 54
Sari Rahal
  • 1,897
  • 2
  • 32
  • 53

2 Answers2

1

The biggest key, in my opinion, to building a CSS dropdown/flyout menu is using absolute positioned elements inside relative positioned elements and where to use them. What's even more important is to understand how these two positioning schemes relate to one another. Once you do, you can build all sorts of dropdown/flyout menus.

You will want to set position: relative to all of your menu li whether they contain a submenu or not. Doing so will not affect their position unless you start using top, right, bottom, left CSS properties.

.menu li {
     position: relative;
}

Now you will want to set the position of all ul that are a child of an li in your menu to position: absolute. We also don't want them to show right away so hide them with display: none.

.menu li > ul {
     display: none;
     position: absolute;
}

Applying position relative to the containing element of an absolute positioned element helps contain the absolute positioned element. Not only that but the absolute positioned element will base it's positioning off of the relative positioned parent element, which is what we want. Setting top: 0 and left: 0 will cause a ul that is a child of an li to start in the same upper left hand location as it's parent elements upper left hand corner.

The two rules I have provided so far are the fundamental building blocks of a dropdown/flyout menu in CSS.

From this point forward it will all depend on your design goals as to what else you need to add to your CSS.

I'm going to (mostly) use generic code the rest of the way in the hopes that yourself and others can build off of the basic principles to obtain your own specific results. That said I will base the rest of the code off of what you have supplied. Some superficial styling like borders will be ignored, you can add that later.

HTML

Here is the HTML I'm going to use. Add in anchor elements as needed.

<ul class="menu">
    <li>One</li>
    <li>Two
        <ul>
            <li>Sub Two A</li>
            <li>Sub Two B</li>
        </ul>
    </li>
    <li>Three</li>
</ul>
  • Your top level menu is inline so let's use float: left to do that.
  • They're also fixed width. You're doing this through your anchor tags <a> which is fine, I'm going to use the li.
  • Your text is centered.
.menu li {
     float: left;
     position: relative;
     text-align: center;
     width: 100px;
}

**SEE EDIT BELOW FOR VARIABLE LI ANSWER**

Since you are using fixed width navigation elements you can center your navigation with margin: 0 auto. Using auto for margin left and right to center an element requires a width to be set! Just add up the full width of your top level li and you'll have your width you'll need to center the navigation. Don't forget to include any padding, margin, border etc. in the width calculation.

My example uses three li at 100px width.

.menu {
    width: 300px; /* width of the 3 li */
    margin: 0 auto; /* centers ul when width is specified */
}

Now we will position the submenu ul.

  • For top you need to push the submenu ul down the height of the containing li. I'm going to assume 25px is the height of the li.
  • For left you want it to start at the same edge as the containing li so use 0.
.menu li > ul {
     display: none;
     left: 0;
     position: absolute;
     top: 25px;
}

Now let's display the submenu ul when the parent li is hovered.

.menu li:hover > ul {
    display: block;
}

CSS

The final CSS.

.menu {
    width: 300px; /* width of the 3 li */
    margin: 0 auto; /* centers ul when width is specified */
}
.menu li {
    float: left;
    line-height: 25px; /* assumed height of li */
    position: relative;
    text-align: center;
    width: 100px;
}
.menu li > ul {
    display: none;
    left: 0;
    position: absolute;
    top: 25px;
}
.menu li:hover > ul {
    display: block;
}

Here is a jsFiddle with some basic styling that wraps it all together.

There you go! A primer to CSS dropdown/flyout menus. As usual your needs will require some modifications or additions to what I have supplied. If you understand the fundamentals you'll go a long way in developing more in-depth and robust solutions.

**EDIT**

Just noticed you have variable number of li in your navigation. Make the changes where appropriate. It is a combination of relative positioning with percentage positions.

.menu {
    float: left;
    position: relative;
    left: 50%;
}
.menu li {
    float: left;
    line-height: 25px; /* assumed height of li */
    position: relative;
    right: 50%;
    text-align: center;
    width: 100px;
}
/* undo the right positioning for submenu li so it aligns properly */
.menu li > ul li {
    right: auto;
}

Here is an updated jsFiddle.

hungerstar
  • 21,206
  • 6
  • 50
  • 59
0

Replace your CSS like this, using your LI elements for styling rather than your A elements:

body {
    width:100%;
}
#mainmenu {
    display: block;
    width:100%;
}
#mainmenu ul {
    width:100%;
}
#mainmenu ul li {
    display: inline-block;
    position:relative;
    margin: auto;
    width:19%;
    background: #33332c;
    padding-top:5px;
    padding-bottom:5px;
}
#mainmenu ul li a {
    color: #fbf3e1;
    font-size:14px;
}
#mainmenu ul li ul {
    display: none;
    position: absolute;
}
#mainmenu ul li:hover > ul {
    display: block;
    width:auto;
    position:absolute;
    top:30px;
    left:0;
    background: #33332c;
    padding:10px;
}
#mainmenu ul li:hover > ul li {
    display: block;
    width:150px;
    height:auto;
}
#mainmenu ul li a:hover, #mainmenu ul li.active a {
    color: #f5921e;
    border-bottom: solid 5px #f5921e;
    text-decoration:none;
    border-bottom-right-radius: 5px;
    border-bottom-left-radius: 5px;
}

You may need some additional adjustments, but there you have the basics

See fiddle here

Devin
  • 7,690
  • 6
  • 39
  • 54
  • yes the menu drops below the menu bar, but the menu bar as a whole isn't centered. Remember that the menu bar changes and there can be more/less items in the menu. With your css, after the user logs out, there are only 4 elements and it becomes left justified. Also the hover affect for the drop down is extremely buggy. – Sari Rahal Sep 29 '14 at 19:06
  • 1
    errrr.... I'm posting code based on your very poor information, but even then, you can simply adjust for your needs. For example, I see a full width menu, so I used a 100% width. You don't want 100% width? use whatever you want, that's why I used inner elements with percentages (as opposed to yours with fixed sizes), so if you adjust the outer element's with to any width, the menu inner elements will respond because I made it responsive. – Devin Sep 29 '14 at 19:12
  • @Fabio your solution does not correct itself for a variable number of `li`. If there are 5 `li` at 20% width then the menu changes to 4 `li` they are still 20% width and the menu does not center. @SirRahal55 my answer provides an answer on how to handle a variable number of `li`. – hungerstar Sep 29 '14 at 19:30
  • as I said, I was working with limited information, and I didn't make 1 million edits, I prefer to give him the tools to develop knowledge. Also, he can simply replace width of those li elements with min-width and it will gracefully degrade to a centered 4 li ul menu. I didn't expect to cause such controversy in such a trivial question, so if the OP wants to change the approved mark to your question to make you happy, by all means he can, I really don't care and I'm giving you a +1 for all your effort and nice answer – Devin Sep 29 '14 at 19:49
  • No controversy, just clarifying requirements. Tried `min-width` and couldn't get it to work. If you wouldn't mind, could you provide I jsFiddle so I can see where I went wrong? Thanks! – hungerstar Sep 29 '14 at 20:29