Absolute positioning and its parent element - css

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;
}

Related

CSS How to Make Horizontal Menu Bar stretch across full page width

I am making a website for a friend and am struggling with the CSS for the menu bar. I've deisgned it as he asked etc., but am having a couple of problems.
1) I can't get it to stretch across the full width of the page. The menu itself should stretch across the whole width of the page, with the width of the page split into 6, and the text in each menu item to be centralised and stay the same size and just add extra black background to accommodate the page width. (Most users who'll be looking at it will be using 1920 x 1080 apparently)
Like so (Ignore the boxes at the top - they were just colour tests):
http://i58.tinypic.com/1z2zkf8.png
2) When I mouseover the menuitems for the submenu, the main menu readjusts itself. How can I stop it doing this, so it stays at a static width for the menu buttons? (i.e. 1/6th of the page width)
3) How can I make it so clicking the main menu will show the relevant submenu and keep it up until there is a click elsewhere on the page (i.e. so you don't have to hold your mouseover to select the submenu)
HTML:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Navigation</title>
<link href="navigation.css" rel="stylesheet" type="text/css">
</head>
<body>
<div class="navbar">
<ul>
<li>Home</li>
<li>Clan
<ul class="subnav">
<li>Really? You made a website for this?</li>
<li>Member Roster</li>
<li>One of us...</li>
</ul>
</li>
<li>Games
<ul class="subnav">
<li>Current Games Rotation</li>
<li>Games You Really Need To Buy</li>
<li>Clan Steam Account</li>
<li>Wargame Decks</li>
<li>Leon's Wheel o' Games</li>
</ul>
</li>
<li>Events
<ul class="subnav">
<li>Thursday Game Night</li>
<li>ILAN</li>
</ul>
</li>
<li>Donate
<ul class="subnav">
<li>Help Us Not Be Poor</li>
<li>Help Us Even If You're Poor</li>
</ul>
</li>
<li>Other Shit
<ul class="subnav">
<li>Links to Shit</li>
<li>Cheap as Shit Games</li>
<li>Stats 'n' Shit</li>
<li>Downloadable Shit</li>
</ul>
</li>
</ul>
</div>
</body>
</html>
CSS:
#import url("AEnigma_Scrawl/stylesheet.css");
.navbar {
font-family: "AEnigma Scrawl";
font-size: 32px;
text-align: left;
height: 80px;
width: 100%;
font-weight: normal;
text-shadow: 1px 1px #000000;
}
.navbar ul {
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
margin-left: 0px;
padding-top: 0px;
padding-right: 0px;
padding-bottom: 0px;
padding-left: 0px;
list-style-type: none;
width: 100%;
}
.navbar ul li {
float: left;
}
.navbar ul li a {
text-decoration: none;
color: #FFFFFF;
padding-top: 5px;
padding-right: 5px;
padding-bottom: 5px;
padding-left: 5px;
margin-top: 0px;
margin-right: 0px;
margin-bottom: 0px;
margin-left: 0px;
background-image: url(bg_navbar.png);
border-top: 1px solid #FFFFFF;
border-bottom: 1px solid #FFFFFF;
}
.navbar ul li a:hover , .navbar ul li a:active, .navbar ul li a:focus{
background-image: url(bg_navbar_hover.png);
}
.navbar ul li a.current {
background-image: url(bg_navbar_current.png);
}
.navbar ul li .subnav {
display: none;
}
.navbar ul li .subnav li {
float: none;
}
.navbar ul li .subnav li a {
font-size: 18px;
}
.navbar ul li:hover ul.subnav {
display: block;
position: static;
}
.navbar ul li:hover ul.subnav a {
display: block;
width: 100%;
}
The reason why your menubar isn't stretching across the page is probably because browsers usually automatically add a margin to the html/body. Try setting this css:
html,
body
{
margin:0;
padding:0;
}
Also the reason why your menu bar is shifting is because you're positioning the .subnav ul as static when it should be positioned as absolute. Like so:
.navbar ul li .subnav
{
position:absolute;
}
Positioning an element as absolute means it takes up no space on page so this means it won't push other elements away.
Try adding min-width: 100% on the navbar.
Also change the menu background from image to color.

CSS menu bar centered with dropdown

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

How do I force nested list items to be the same width as parent list item?

I have a horizontal parent list. Some of the list items display a nested vertical list when clicked. How do I force the items in the vertical sub list to be the same width as the parent list item?
See jsFiddle.
HTML:
<ul class="mainMenu horizontalMenu bulletless fullWidth bold">
<li class="showSubMenu">
<div>Resumes & Cover Letters ▾ </div>
<ul class="mainSubMenu bulletless">
<li><a>Resumes</a></li>
<li><a>Cover Letters</a></li>
<li><a>Interviews</a></li>
</ul>
</li><li><a>Other Link</a>
</li><li><a>Other Link</a></li>
</ul>​
CSS:
.horizontalMenu li{
display: inline-block;
}
.mainMenu > li{
border: 1px solid black;
}
.mainMenu a, .mainMenu div{
display: block;
padding: 10px 20px;
}
.mainSubMenu{
position: absolute;
}
I did the change on your fiddle. http://jsfiddle.net/BXnxc/2/
The parent li needs to have position:relative; and the nested submenu has to have width:100%; and position:absolute;
You can do this by specifying the parent LI as relative and child UL with width: 100%
Demo: http://jsfiddle.net/BXnxc/3/
.horizontalMenu li {
position: relative;
}
.horizontalMenu li ul {
width: 100%;
}
You can also do this by inheriting the width of the containing structures. I set your mainMenu div to width of 200px and then width:inherit for the mainSubMenu.
http://jsfiddle.net/BXnxc/4/
.mainMenu a, .mainMenu div{
display: block;
padding: 10px 20px;
width:200px;
}
.mainSubMenu{
position: absolute;
width:inherit;
}
.mainSubMenu li
{
display: block;
border: 1px solid grey;
width:inherit;
}

IE6 and IE7 float issue on navigation list items

Like many people, I am having trouble with floating elements in IE7 (and 6, but I don't care about that!)
http://www.storybox.co.nz/wordpress/
Looks fine in every other browser, but in IE7 the navigation links sit under each other:
HTML (inline styles are from js dropdown script):
<div id="primary-menu">
<div class="menu">
<ul>
<li>Work.
<ul class="sub-menu" style="float: none; width: 1em; visibility: hidden; display: none;">
<li style="white-space: normal; float: left; width: 100%;">Spatial /</li>
<li style="white-space: normal; float: left; width: 100%;">Web /</li>
<li style="white-space: normal; float: left; width: 100%;">Graphic</li>
</ul>
</li>
<li>Lab.</li>
<li>About.</li>
</ul>
</div>
</div>
CSS:
#primary-menu {
margin:-30px auto 30px;
}
#primary-menu ul {
float:right;
}
#primary-menu li {
float: left;
list-style: none;
margin-left: 10px;
display:inline;
}
#primary-menu ul li a {
float: right;
}
I have tried display:inline on the li items as well as on the a items, but that doesn't work.
Any other tips? Thanks!
the problem is probably width: 100% for li. If ul is 100px, then each of li will also have 100px = they will be displayed as shown. Try to set fixed width for them, but 3x width ( + padding, margins ) should be less than width for ul. You can also try 33%. BT
float: right puts display: block on item and it makes no sense to add display: inline together with float: right. My guess is that IE ignores display: inline. It makes also no sense to put width for inline element. Your CSS simple does not make sense :)
I tested on IE 7 and below is the updated CSS.
#primary-menu {
/* margin:-30px auto 30px;*/ /*Avoid negative margins*/
}
#primary-menu ul {
float:right;
}
#primary-menu li {
float: left;
list-style: none;
margin-left: 10px;
display:inline;
}
#primary-menu ul li a {
/* float: right;*/ /*This caused the issue*/
}
Hope this helps

CSS Footer Alignment Issue

I can't get this footer to align and sit on the bottom properly - it should be 3 column and centered on the page. Can anyone help?
/* FOOTER */
#footer {
line-height: 80px;
width:100%;
color: #fff;
height: 80px;
background-color: #111;
padding: 30px 0px 0px 0px;
}
/* column width */
#footer > ul > li {
width: 250px;
list-style:none;
float: left;
border-left: 1px solid #fff;
padding-left: 10px;
}
#footer > ul > li > ul {
font-weight: normal;
list-style:none;
font-size: .80em;
}
#footer a, #footer a:visited, #footer a:active {
color: #ffffff;
}
#footer a:hover {
color: #ffffff;
}
<div id="footer">
<ul>
<li>
<ul>
<li>About</li>
<li>Contact</li>
<li>Spare</li>
</ul> </li>
<li>
<ul>
<li>Terms</li>
<li>Privacy</li>
<li>Disclaimer</li>
</ul> </li>
<li>
<ul>
<li> or content on this website. Full disclaimer</li>
</ul>
</ul>
The padding and margin on the body element needs to be zero if you want elements to be flush against the browser window.
I don't think you can center a group of elements if they're floated. Have you considered applying display:inline-block to the column LIs, instead of float:left?
Set #footer width property to as much as you want (750px min since you set the li width to 250px) and then set margin-left and margin-right to auto. This will center the footer. As far as the bottom position goes you could adjust it by changing the setting/changing the margin-top property of the #footer div ... i don't understand exactly what "sits on the bottom properly" means
Simple, Give each group a width of about 32% then give the footer a padding so the left on is not flush with the edge.
#footer > ul > li {
width: 32%;
list-style:none;
float: left;
border-left: 1px solid #fff;
padding-left: 10px;
}

Resources