Nav menu lists not floating as expected

Hi,

I’m trying to create a navigation menu with a subnav containing floated lists. I’m using a floated ul inside an absolute positioned div, inside a floated li with relative positioning. The div needs to be absolutely positioned, I’m using relative positioning on the li because I want the absolute positioned divs to be placed relative to the list items and not the overall page. If I remove position: relative from the li then the lists float side by side in the div (exactly what I want) but the div is then not placed under the relevant menu item. With position: relative the div is placed where I want but the lists are stacked on top of each other. This is all in Firefox and Chrome.

If I explicitly define the width on the div to be big enough to contain both lists side by side, it works properly, but this isn’t much help as the lists will be dynamically generated.

Here’s some test code I’ve been using trying to simplify the problem as much as possible:


<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Home Page</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<link media="all" href="teststyles.css" type="text/css" rel="stylesheet">
</head>
<body>
<ul>
<li class="navli"><a href="listtest.html">item1</a></li>
<li class="navli"><a href="listtest.html">item2</a>
<div class="listcontainer">
<ul class="testlist col1">
	<li><a href="listtest.html">test1</a></li>
	<li><a href="listtest.html">test2</a></li>
	<li><a href="listtest.html">test3</a></li>
	<li><a href="listtest.html">test4</a></li>
	<li><a href="listtest.html">test5</a></li>
	<li><a href="listtest.html">test6</a></li>
</ul>
<ul class="testlist col2">
	<li><a href="listtest.html">2test1</a></li>
	<li><a href="listtest.html">2test2</a></li>
	<li><a href="listtest.html">2test3</a></li>
	<li><a href="listtest.html">2test4</a></li>
	<li><a href="listtest.html">2test5</a></li>
	<li><a href="listtest.html">2test6</a></li>
</ul>
</div>
</li>
<li class="navli"><a href="listtest.html">item3</a>
</li>
</ul>
</body>
</html>


.navli {
	position: relative;
	float: left;
	padding: 10px 20px;
}
.listcontainer {
	background-color: blue;
	position: absolute;
	padding: 5px;
	left: 0px;
	top: 30px;
}
.testlist {
	color: red;
	background-color: orange;
	float: left;
	width: 200px;
}
.col2 {
	color: green;
	background-color: pink;
}

Please help!

The only sure way you can accomplish what you need the child UL elements to do would be to define a static width on the parent DIV as by default absolutely positioned elements don’t inherit any height or width which would cause floats to act like the display property with a value of block. Have a look at the following jsFiddle which i have added the static width to:

The only sure way to to accomplish this would be to use JavaScript and calculate the total width of the child elements and then set it on the parent DIV which is a dirty fix but will work.

Ok thanks for the help. I’ve hacked together some javascript which seems to work ok, is there anything stupid I’ve done here that might break anything? I’m executing it via body onload=.


function setsubnavwidth() {
	//Sets width on container divs for navigation submenus
	var subnavdivs=document.getElementsByClassName("listcontainer");
	for (var i = 0; i < subnavdivs.length; i++) {
		var subnavuls=subnavdivs[i].childNodes;
		var totalWidth=0
		for (var j = 0; j < subnavuls.length; j++) {
			if (subnavuls[j].tagName=="UL") {
				totalWidth = totalWidth+subnavuls[j].offsetWidth
			}
		}
		subnavdivs[i].style.width=totalWidth;
	}
}

Hi,

You can do it quite easily like this without javascript.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Home Page</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<link media="all" href="teststyles.css" type="text/css" rel="stylesheet">
<style>
ul {
	margin:0;
	padding:0;
	list-style:none
}

.navli {
	position: relative;
	float: left;
	padding: 10px 20px;
}
.listcontainer {
	background-color: blue;
	position: absolute;
	padding: 5px;
	left: 0px;
	top: 30px;
	white-space:nowrap;
}
.testlist {
	color: red;
	background-color: orange;
	display:inline-block;
	width: 200px;
	white-space:normal;
}
* html .testlist{display:inline}
*+html .testlist{display:inline}
.col2 {
	color: green;
	background-color: pink;
}
</style>
</head>
<body>
<ul>
		<li class="navli"><a href="listtest.html">item1</a></li>
		<li class="navli"><a href="listtest.html">item2</a>
				<div class="listcontainer">
						<ul class="testlist col1">
								<li><a href="listtest.html">test1</a></li>
								<li><a href="listtest.html">test2</a></li>
								<li><a href="listtest.html">test3</a></li>
								<li><a href="listtest.html">test4</a></li>
								<li><a href="listtest.html">test5</a></li>
								<li><a href="listtest.html">test6</a></li>
						</ul>
						<ul class="testlist col2">
								<li><a href="listtest.html">2test1</a></li>
								<li><a href="listtest.html">2test2</a></li>
								<li><a href="listtest.html">2test3</a></li>
								<li><a href="listtest.html">2test4</a></li>
								<li><a href="listtest.html">2test5</a></li>
								<li><a href="listtest.html">2test6</a></li>
						</ul>
				</div>
		</li>
		<li class="navli"><a href="listtest.html">item3</a> </li>
</ul>
</body>
</html>

Thanks for the reply, but this doesn’t seem to work for me?

In what way did it not work?

Did I misunderstand what you wanted (quite likely)?

I thought you wanted the nested uls to align in horizontal blocks like the attached image which is what the code produces. Did I miss something important again?

No you understood correctly. I just tried again and see it works in Chrome/Safari but not in Firefox/IE. Here’s what I’m seeing:

Hi,

Strange it’s working more or less everywhere for me except for a bug in IE7 which I’ve addressed in the code below. The version I posted above was working in ie5.5, 1e6, 1e8, 1e9, firefox 3.6, 4, 5, 6,7,8, safari and chrome pc and mac.

It won’t work in Firefox 2 but that’s dead and buried long ago.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Home Page</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<link media="all" href="teststyles.css" type="text/css" rel="stylesheet">
<style>
ul {
	margin:0;
	padding:0;
	list-style:none
}
.navli {
	position: relative;
	float: left;
	padding: 10px 20px;
}
.listcontainer {
	background-color: blue;
	position: absolute;
	padding: 5px;
	left: 0px;
	top: 30px;
	white-space:nowrap;
}
.testlist {
	color: red;
	background-color: orange;
	display:inline-block;
	width: 200px;
}
.testlist li{white-space:normal}
* html .testlist{display:inline}
*+html .testlist{display:inline;}
.col2 {
	color: green;
	background-color: pink;
}
</style>
</head>
<body>
<ul>
		<li class="navli"><a href="listtest.html">item1</a></li>
		<li class="navli"><a href="listtest.html">item2</a>
				<div class="listcontainer">
						<ul class="testlist col1">
								<li><a href="listtest.html">test1</a></li>
								<li><a href="listtest.html">test2</a></li>
								<li><a href="listtest.html">test3</a></li>
								<li><a href="listtest.html">test4</a></li>
								<li><a href="listtest.html">test5</a></li>
								<li><a href="listtest.html">test6</a></li>
						</ul>
						<ul class="testlist col2">
								<li><a href="listtest.html">2test1</a></li>
								<li><a href="listtest.html">2test2</a></li>
								<li><a href="listtest.html">2test3</a></li>
								<li><a href="listtest.html">2test4</a></li>
								<li><a href="listtest.html">2test5</a></li>
								<li><a href="listtest.html">2test6</a></li>
						</ul>
				</div>
		</li>
		<li class="navli"><a href="listtest.html">item3</a> </li>
</ul>
</body>
</html>

Did you change something in my code or have you got a very old browser version?

Sorted it, you left the link to my external stylesheet in, and since I was testing in the same folder that was breaking it. Thanks for the help, now to try and understand why it works :slight_smile:

lol - of course - I should have thought of that :slight_smile:

Thanks for the help, now to try and understand why it works :slight_smile:

The basics are that instead of floating the uls we make them inline-blocks which mean that they align side by side just like words would. They also have the same behaviour as words in that if you set white-space:nowrap then the words won’t wrap to a new line and neither will the inline-block elements and that forces them to stay on the same line.

The problem with absolute elements is that they are a “shrink to fit element” and therefore the floats don’t line up horizontally as there is no actual space to the right of the float above. There was also a solution in setting the parent li to a great big width (or using large negative margins) and then hiding the overflow but would have caused some issues.