CSS menu bar centered with dropdown - css

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.
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.
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">Home</li>
<li>My Tickets</li>
<li>About</li>
<li>Contact</li>
<li>SirRahal
<ul>
<li>Edit User</li>
<li>Log-out</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;
}

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.

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

Related

How to make an on-hover bottom border overlap div below?

I have a horizontal navigation menu using unordered lists. Under the menu there is a straight gray line which has to have 100% width of the parent container. When hovering the list elements, the part of the line has to be colored blue right under the list element. I can't find any suitable way of doing this. I got it working with position:relative and adding top:14px but it isn't really satisfying me since any changes to the font size or font face will destroy everything. I also thought about changing margins between elements to padding, increasing li's height and giving each one the same gray border and just changing it's color on hover, but I need the line to go all along the parent div's width.
How it has to look:
expected result
My current code:
#container {
width: 80%;
margin: auto;
background-color: white;
}
#container ul {
list-style-type: none;
display: inline-block;
margin: 0;
padding: 0;
margin-top: 5px;
margin-bottom: 10px;
}
#container ul li {
float: left;
margin-left: 20px;
}
#container ul li:first-child {
margin-left: 0;
}
#container ul li a {
text-decoration: none;
color: black;
}
#container ul li a:hover {
color: grey;
}
#container #slider {
display: inline-block;
height: 5px;
background-color: #f1f1f1;
width: 100%;
}
<div id="container">
<ul>
<li>INDEX</li>
<li>HELP</li>
<li>LONG LINK TEXT</li>
</ul>
<span id="slider"></span>
</div>
JSFiddle: https://jsfiddle.net/9fhvyk76/3/
You'll want to use a pseudo element so you have more control over the size/position without really needing to change much. Just add position: relative to the link itself so the pseudo's scale and positioning are associated with it. Let me know if this is what you were looking for!
https://jsfiddle.net/g00jrsqf/
#container ul li a{
position: relative;
}
#container ul li a:after{
content: '';
position: absolute;
display: block;
width: 100%;
height: 4px;
background: #01a2e8;
opacity: 0;
left: 0;
bottom: -29px;
}
#container ul li:hover a:after{
opacity: 1;
}

Inherit width from indirect ancestor

I have the following HTML
<ul id="nav">
<li>
Menu Item 1
<ul class="sub_menu">
<!-- full of <li> sub menu items -->
</ul>
</li>
<li>
Menu Item 2
<ul class="sub_menu">
<!-- full of <li> sub menu items -->
</ul>
</li>
<li>
Menu Item 3
</li>
</ul>
The #nav is 100% the width of the browser window.
Using only CSS I want to float the Menu Items side by side inside a container that has similar CSS:
{ width: 1000px; margin: 0 auto; }
But I want the .sub_menus to be the same width as #nav.
How can this be done without changing the HTML?
You can position: relative the #nav, do your thing with the li and then position: absolute; left: 0; right: 0 the .sub_menu.
This way .sub_menu is the same width as #nav regardless of the width of li. You'll have to add and adjust some more styles to make it look pretty and in position but I'll leave that to you.
An additional requirement is that li will stay position: static as the position of .sub_menu must be relative to #nav.
EDIT: #simon's answer is pretty much an implementation of mine, but OP has left a comment there indicating that it isn't adequate. We're still unsure of what the problem is.
Try the following (jsbin):
* { margin: 0; padding: 0 }
#nav, .sub_menu {
width: 100%;
height: 30px;
position: relative;
background: green;
}
#nav > li > a {
z-index: 1;
position: relative;
}
#nav > li {
float: left;
list-style-type: none;
}
.sub_menu {
position: absolute;
left: 0;
background: red;
top: 30px
}
This puts all the buttons one after another and keeps the submenu 100% width
here you go:
http://codepen.io/anon/pen/YXZQMo
The Subnav UL has now the same width as the parent li
#nav { width: 1000px; margin: 0 auto; }
ul{
margin:0;
padding:0;
list-style:none;
}
ul li{
display:block;
float:left;
padding: 5px 10px;
width:auto;
}
ul li:hover ul{
display:block;
}
ul li ul{
display:none;
width:100%;
background-color:red;
min-height:20px;
transition:all 0.3s;
}
ul li ul li{
display:block;
float:none;
}

Css vertical menu: issue with background color on hover mode

I'm having a design issue with my css vertical menu.
It's working but it does not have the effect i would like to have when I do a mouse hover on a category
Below, you will see a simple vertical menu which appears when you hover your mouse over the main category
However I would like to have a small effect :
When the mouse is hover a category, i would like to add a background color (black).
It's working but I would like that the height and the width of the background to stick exactly to the same height and width of the text. Currently, I dont know why; the height of the background is more than the height of my text.
Here is some pictures of how it's right now and how i would like to be be.
How it 's now:
How I would like it to be:
Here is my code Html code
<div id="menu">
<ul id="MenuDeroulant">
<li style="margin-left:-10px;">Main categorie
<ul>
<li><a href="" >Subcat 1</a></li>
<li><a href="" >Subcat 2</a></li>
</ul>
</li>
</ul>
Here is my css code:
#MenuDeroulant
{
margin: 0;
padding: 0
}
#MenuDeroulant li
{
float: left;
list-style: none;
}
#MenuDeroulant li a
{
display: block;
padding: 0px 0px;
text-decoration: none;
color: #000;
white-space: nowrap;
text-align:center;
}
#MenuDeroulant li a:hover
{
background: #000;
color: #FFF;
}
#MenuDeroulant li ul
{ visibility: hidden;
padding: 0px 0px;
}
#MenuDeroulant li ul li
{
float: none;
display: inline;
}
#MenuDeroulant li ul li a
{
width: auto;
padding: 0px 0px;
}
#MenuDeroulant li ul li a:hover
{
background: #0000;
padding: 0px 0px;
}
Thanks in advance for your help and I wish you a very nice day,
Anselme
Use width:100% to all your <li> or li a elements and a fixed width to your <ul>. This will solve your issue.
With that CSS your nested ul is permanently hidden. You'll need something like
#MenuDeroulant li:hover ul {
visibility:visible;
}
to show the nested menu items then maybe display: inline on the #MenuDeroulant li ul li a
You can add a class to your menu hyperlinks giving them a margin-bottom:3px and it should bump up the links in the container.

CSS text-align not working

I have this css code here
.navigation{
width:100%;
background-color:#7a7a7a;
font-size:18px;
}
.navigation ul {
list-style-type: none;
margin: 0;
}
.navigation li {
float: left;
}
.navigation ul a {
color: #ffffff;
display: block;
padding: 0 65px 0 0;
text-decoration: none;
}
What I am trying to do is center my class navigation. I tried using text-align:center; and vertical-align:middle; but neither of them worked.
and here is the HTML Code
<div class="navigation">
<ul>
<li>home</li>
<li>about</li>
<li>tutors</li>
<li>students</li>
<li>contact us</li>
</ul>
</div><!--navigation-->
When I say its not working, I mean the text is aligned to the left.
Change the rule on your <a> element from:
.navigation ul a {
color: #000;
display: block;
padding: 0 65px 0 0;
text-decoration: none;
}​
to
.navigation ul a {
color: #000;
display: block;
padding: 0 65px 0 0;
text-decoration: none;
width:100%;
text-align:center;
}​
Just add two new rules (width:100%; and text-align:center;). You need to make the anchor expand to take up the full width of the list item and then text-align center it.
jsFiddle example
You have to make the UL inside the div behave like a block. Try adding
.navigation ul {
display: inline-block;
}
I try to avoid floating elements unless the design really needs it. Because you have floated the <li> they are out of normal flow.
If you add .navigation { text-align:center; } and change .navigation li { float: left; } to .navigation li { display: inline-block; } then entire navigation will be centred.
One caveat to this approach is that display: inline-block; is not supported in IE6 and needs a workaround to make it work in IE7.

Absolute positioning and its parent element

I've always heard that when you use absolute positioning that the element you want to act as its parent needs to have a position of relative.
I was trying to build a CSS dropdown menu and I was struggling to get the dropdown menu items stretch beyond the width of the main menu item when I had its parent element I wanted it to use set as relative; the text in the drop down menu items would just wrap.
So I looked around at other example menus to see how they did it and one I found wasn't even using any parent elements with a position of relative even though they were using absolute positioning like I was.
That example is here: http://purecssmenu.com/
So I tried removing my relative positioning and bingo - my problem went away. However now I am using absolute positioning with none of it's parents using relative positioning, they are all set to static.
So I'm wondering how that makes sense - with no relative parents wouldn't it fall back to the browser window?
If need be, here is my HTML:
<div class="navWrapper">
<div class="left"></div>
<div class="nav">
<ul>
<li class="home">Home</li>
<li class="spacer"></li>
<li class="about">About Us</li>
<li class="spacer"></li>
<li class="trademark">Free Trademark Search</li>
<li class="spacer"></li>
<li class="services">
Services
<ul class="sub">
<li>Trademark Search</li>
<li>Prepare & File Trademark</li>
<li>Trademark Infringement</li>
</ul>
</li>
<li class="spacer"></li>
<li class="testimonials">Testimonials</li>
<li class="spacer"></li>
<li class="more">More Information</li>
<li class="spacer"></li>
<li class="contact">Contact Us</li>
</ul>
<div class="contentClear"></div>
</div>
<!-- Nav Ends -->
<div class="right"></div>
</div>
<!-- Nav Wrapper Ends -->
CSS:
#header .navWrapper {
width: 1004px;
}
#header .navWrapper .left {
float: left;
width: 4px;
min-width: 4px;
height: 47px;
min-height: 47px;
background: url('../images/nav-left-bg.png') left top no-repeat;
}
#header .navWrapper .nav {
float: left;
width: 994px;
border-top: 1px solid #e0d0b4;
border-left: 1px solid #e0d0b4;
border-right: 1px solid #e0d0b4;
border-bottom: 1px solid #e8dcc8;
background: url('../images/nav-button-bg.png') left top repeat-x;
}
#header .navWrapper .nav ul {
margin: 0 1px;
display: block;
}
#header .navWrapper .nav li {
float: left;
display: block;
height: 45px;
font-family: OpenSansBold, Arial;
font-size: 16px;
line-height: 2.9;
text-align: center;
color: #646464;
}
#header .navWrapper .nav li.spacer {
width: 2px;
min-width: 2px;
height: 45px;
min-height: 45px;
background: url('../images/nav-button-spacer-bg.png') left top no-repeat;
}
#header .navWrapper .nav li a,
#header .navWrapper .nav li a:visited
{
display: block;
height: 45px;
padding: 0 20px;
color: #646464;
text-decoration: none;
}
#header .navWrapper .nav li a:hover,
#header .navWrapper .nav li a:active,
#header .navWrapper .nav li a:focus
{
color: #fff;
background: url('../images/nav-button-bg.png') left bottom repeat-x;
}
#header .navWrapper .nav li.home {
max-width: 86px;
text-indent: -1px;
}
#header .navWrapper .nav li ul.sub {
position: absolute;
}
#header .navWrapper .nav li ul.sub li {
float: none;
display: block;
font-family: OpenSansSemibold, Arial;
font-size: 14px;
line-height: 2.3;
height: auto;
text-align: center;
background-color: #f4771d;
color: #fff;
}
#header .navWrapper .nav li ul.sub li a,
#header .navWrapper .nav li ul.sub li a
{
color: #fff;
height: auto;
}
#header .navWrapper .nav li ul.sub li a:hover,
#header .navWrapper .nav li ul.sub li a:focus,
#header .navWrapper .nav li ul.sub li a:active
{
background: #d66627;
}
#header .navWrapper .right {
float: right;
width: 4px;
min-width: 4px;
height: 47px;
min-height: 47px;
background: url('../images/nav-right-bg.png') left top no-repeat;
}
It falls back to the nearest ancestor element that has position defined as relative, absolute, or fixed -- not just relative, but any value other than static (the default).
Generally, you'd want to position the item absolutely according to a grid established by its parent. However, sometimes it makes sense to have it positioned to a grid established by a higher up element.
For example:
HTML
<body>
<div id="div1">
<div id="div2-A">[some content]</div>
<div id="div2-B">
<div id="div3">[more content]</div>
</div>
</div>
</div>
CSS
#div1{
width:1024px;margin:auto;
position:relative
}
#div3{
position:absolute;
bottom:0px; left:0px;
}
In this case, div3 will be positioned all the way to the left & bottom of div1 -- its grandfather -- because its immediate parent (div2) has the default position:static, and so does not establish as an absolute positioning context/grid for its children. But div3 will not (necessarily) go all the way to the left of the viewport or the page body because the next higher up element (div1) has position defined as relative.
UPDATE
In the case you provided (http://purecssmenu.com/), the position:relative declaration is being applied on the :hover pseudo-class, so you won't see it immediately in the styles listed for Google Developer Tools or Firebug.
You can inspect this in Google developer tools by inspecting the parent element, then in the right-hand side of the "Styles" panel, click the "Toggle Element State" button, (looks like a box with dotted border and an arrow pointing in it), then check the box next to ":hover". I'm sure Firebug has something similar.
You'll see this declaration added to the list:
ul.cssMenu li:hover { position: relative; }
This works because when you're not hovering on the parent <li>, the sub-menu <ul> is hidden with display:none, so it doesn't matter where it's positioned.
Another note on the nearest ancestor when an element is being positioned.
Three years later after the OP, CSS3 properties like transform are more widely being used, which implicitly creates a new containing block, forcing the element to have position: relative/absolute;
So to make sure intermediary parent elements have no effect in the positioning of a child element, you need check it has position: static and no transforms set.
Example
<div id="one">
<div id="two">
<div id="three"></div>
</div>
</div>
#one {
position: relative;
}
#two {
position: static;
transform: none;
}
#three {
position:absolute;
}

Resources