Related
You find plenty of tutorials on menu bars in HTML, but for this specific (though IMHO generic) case, I haven't found any decent solution:
# THE MENU ITEMS SHOULD BE JUSTIFIED JUST AS PLAIN TEXT WOULD BE #
# ^ ^ #
There's an varying number of text-only menu items and the page layout is fluid.
The first menu item should be left-aligned, the last menu item should be right-aligned.
The remaining items should be spread optimally on the menu bar.
The number is varying,so there's no chance to pre-calculate the optimal widths.
Note that a TABLE won't work here as well:
If you center all TDs, the first and the last item aren’t aligned correctly.
If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.
Isn’t it strange that there is no obvious way to implement this in a clean way by using HTML and CSS?
The simplest thing to do is to is to force the line to break by inserting an element at the end of the line that will occupy more than the left available space and then hiding it. I've accomplished this quite easily with a simple span element like so:
#menu {
text-align: justify;
}
#menu * {
display: inline;
}
#menu li {
display: inline-block;
}
#menu span {
display: inline-block;
position: relative;
width: 100%;
height: 0;
}
<div id="menu">
<ul>
<li>Menu item 1</li>
<li>Menu item 3</li>
<li>Menu item 2</li>
</ul>
<span></span>
</div>
All the junk inside the #menu span selector is (as far as I've found) required to please most browsers. It should force the width of the span element to 100%, which should cause a line break since it is considered an inline element due to the display: inline-block rule. inline-block also makes the span possible to block-level style rules like width which causes the element to not fit in line with the menu and thus the menu to line-break.
You of course need to adjust the width of the span to your use case and design, but I hope you get the general idea and can adapt it.
Modern Approach - Flexboxes!
Now that CSS3 flexboxes have better browser support, some of us can finally start using them. Just add additional vendor prefixes for more browser coverage.
In this instance, you would just set the parent element's display to flex and then change the justify-content property to either space-between or space-around in order to add space between or around the children flexbox items.
Using justify-content: space-between - (example here):
ul {
list-style: none;
padding: 0;
margin: 0;
}
.menu {
display: flex;
justify-content: space-between;
}
<ul class="menu">
<li>Item One</li>
<li>Item Two</li>
<li>Item Three Longer</li>
<li>Item Four</li>
</ul>
Using justify-content: space-around - (example here):
ul {
list-style: none;
padding: 0;
margin: 0;
}
.menu {
display: flex;
justify-content: space-around;
}
<ul class="menu">
<li>Item One</li>
<li>Item Two</li>
<li>Item Three Longer</li>
<li>Item Four</li>
</ul>
Ok, this solution doesn't work on IE6/7, because of the lack of support of :before/:after, but:
ul {
text-align: justify;
list-style: none;
list-style-image: none;
margin: 0;
padding: 0;
}
ul:after {
content: "";
margin-left: 100%;
}
li {
display: inline;
}
a {
display: inline-block;
}
<div id="menu">
<ul>
<li>Menu item 1</li>
<li>Menu item 2</li>
<li>Menu item 3</li>
<li>Menu item 4</li>
<li>Menu item 5</li>
</ul>
</div>
The reason why I have the a tag as an inline-block is because I don't want the words inside to be justified as well, and I don't want to use non-breaking spaces either.
Got a solution. Works in FF, IE6, IE7, Webkit, etc.
Make sure you don't put any whitespace before closing the span.inner. IE6 will break.
You can optionally give .outer a width
.outer {
text-align: justify;
}
.outer span.finish {
display: inline-block;
width: 100%;
}
.outer span.inner {
display: inline-block;
white-space: nowrap;
}
<div class="outer">
<span class="inner">THE MENU ITEMS</span>
<span class="inner">SHOULD BE</span>
<span class="inner">JUSTIFIED</span>
<span class="inner">JUST AS</span>
<span class="inner">PLAIN TEXT</span>
<span class="inner">WOULD BE</span>
<span class="finish"></span>
</div>
Works with Opera , Firefox, Chrome and IE
ul {
display: table;
margin: 1em auto 0;
padding: 0;
text-align: center;
width: 90%;
}
li {
display: table-cell;
border: 1px solid black;
padding: 0 5px;
}
yet another solution. I had no option to tackle the html like adding distinguished class etc., so I found a pure css way.
Works in Chrome, Firefox, Safari..don't know about IE.
Test: http://jsfiddle.net/c2crP/1
ul {
margin: 0;
padding: 0;
list-style: none;
width: 200px;
text-align: justify;
list-style-type: none;
}
ul > li {
display: inline;
text-align: justify;
}
/* declaration below will add a whitespace after every li. This is for one line codes where no whitespace (of breaks) are present and the browser wouldn't know where to make a break. */
ul > li:after {
content: ' ';
display: inline;
}
/* notice the 'inline-block'! Otherwise won't work for webkit which puts after pseudo el inside of it's parent instead of after thus shifting also the parent on next line! */
ul > li:last-child:after {
display: inline-block;
margin-left: 100%;
content: ' ';
}
<ul>
<li>home</li>
<li>exposities</li>
<li>werk</li>
<li>statement</li>
<li>contact</li>
</ul>
Make it a <p> with text-align: justify ?
Update: Nevermind. That doesn't work at all as I'd thought.
Update 2: Doesn't work in any browsers other than IE right now, but CSS3 has support for this in the form of text-align-last
For Gecko-based browsers, I came up with this solution. This solution doesn't work with WebKit browsers, though (e.g. Chromium, Midori, Epiphany), they still show trailing space after the last item.
I put the menu bar in a justified paragraph. Problem is that the last line of a justified paragraph won't be rendered justified, for obvious reasons. Therefore I add a wide invisible element (e.g. an img) which warrants that the paragraph is at least two lines long.
Now the menu bar is justified by the same algorithm the browser uses for justifying plain text.
Code:
<div style="width:500px; background:#eee;">
<p style="text-align:justify">
THE MENU ITEMS
SHOULD BE
JUSTIFIED
JUST AS
PLAIN TEXT
WOULD BE
<img src="/Content/Img/stackoverflow-logo-250.png" width="400" height="0"/>
</p>
<p>There's an varying number of text-only menu items and the page layout is fluid.</p>
<p>The first menu item should be left-aligned, the last menu item should be right-aligned. The remaining items should be spread optimal on the menu bar.</p>
<p>The number is varying,so there's no chance to pre-calculate the optimal widths.</p>
<p>Note that a TABLE won't work here as well:</p>
<ul>
<li>If you center all TDs, the first and the last item aren't aligned correctly.</li>
<li>If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.</li>
</ul>
</div>
Remark: Do you notice I cheated? To add the space filler element, I have to make some guess about the width of the menu bar. So this solution is not completely down to the rules.
Text is only justified if the sentence naturally causes a line break. So all you need to do is naturally force a line break, and hide whats on the second line:
CSS:
ul {
text-align: justify;
width: 400px;
margin: 0;
padding: 0;
height: 1.2em;
/* forces the height of the ul to one line */
overflow: hidden;
/* enforces the single line height */
list-style-type: none;
background-color: yellow;
}
ul li {
display: inline;
}
ul li.break {
margin-left: 100%;
/* use e.g. 1000px if your ul has no width */
}
HTML:
<ul>
<li>The</li>
<li>quick</li>
<li>brown</li>
<li>fox</li>
<li class="break"> </li>
</ul>
The li.break element must be on the same line as the last menu item and must contain some content (in this case a non breaking space), otherwise in some browsers, if it's not on the same line then you'll see some small extra space on the end of your line, and if it contains no content then it's ignored and the line is not justified.
Tested in IE7, IE8, IE9, Chrome, Firefox 4.
if to go with javascript that is possible (this script is base on mootools)
<script type="text/javascript">//<![CDATA[
window.addEvent('load', function(){
var mncontainer = $('main-menu');
var mncw = mncontainer.getSize().size.x;
var mnul = mncontainer.getFirst();//UL
var mnuw = mnul.getSize().size.x;
var wdif = mncw - mnuw;
var list = mnul.getChildren(); //get all list items
//get the remained width (which can be positive or negative)
//and devided by number of list item and also take out the precision
var liwd = Math.floor(wdif/list.length);
var selw, mwd=mncw, tliw=0;
list.each(function(el){
var elw = el.getSize().size.x;
if(elw < mwd){ mwd = elw; selw = el;}
el.setStyle('width', elw+liwd);
tliw += el.getSize().size.x;
});
var rwidth = mncw-tliw;//get the remain width and set it to item which has smallest width
if(rwidth>0){
elw = selw.getSize().size.x;
selw.setStyle('width', elw+rwidth);
}
});
//]]>
</script>
and the css
<style type="text/css">
#main-menu{
padding-top:41px;
width:100%;
overflow:hidden;
position:relative;
}
ul.menu_tab{
padding-top:1px;
height:38px;
clear:left;
float:left;
list-style:none;
margin:0;
padding:0;
position:relative;
left:50%;
text-align:center;
}
ul.menu_tab li{
display:block;
float:left;
list-style:none;
margin:0;
padding:0;
position:relative;
right:50%;
}
ul.menu_tab li.item7{
margin-right:0;
}
ul.menu_tab li a, ul.menu_tab li a:visited{
display:block;
color:#006A71;
font-weight:700;
text-decoration:none;
padding:0 0 0 10px;
}
ul.menu_tab li a span{
display:block;
padding:12px 10px 8px 0;
}
ul.menu_tab li.active a, ul.menu_tab li a:hover{
background:url("../images/bg-menutab.gif") repeat-x left top;
color:#999999;
}
ul.menu_tab li.active a span,ul.menu_tab li.active a.visited span, ul.menu_tab li a:hover span{
background:url("../images/bg-menutab.gif") repeat-x right top;
color:#999999;
}
</style>
and the last html
<div id="main-menu">
<ul class="menu_tab">
<li class="item1"><span>Home</span></li>
<li class="item2"><span>The Project</span></li>
<li class="item3"><span>About Grants</span></li>
<li class="item4"><span>Partners</span></li>
<li class="item5"><span>Resources</span></li>
<li class="item6"><span>News</span></li>
<li class="item7"><span>Contact</span></li>
</ul>
</div>
Simpler markup, tested in Opera, FF, Chrome, IE7, IE8:
<div class="nav">
nav item1
nav item2
nav item3
nav item4
nav item5
nav item6
<span class="empty"></span>
</div>
and css:
.nav {
width: 500px;
height: 1em;
line-height: 1em;
text-align: justify;
overflow: hidden;
border: 1px dotted gray;
}
.nav_item {
display: inline-block;
}
.empty {
display: inline-block;
width: 100%;
height: 0;
}
Live example.
try this
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
ul {
list-style: none;
display: flex;
align-items: center;
justify-content: space-evenly;
}
<ul>
<li>List item One</li>
<li>List item Two</li>
<li>List item Three </li>
<li>List item Four</li>
</ul>
This can be achieved perfectly by some careful measurements and the last-child selector.
ul li {
margin-right:20px;
}
ul li:last-child {
margin-right:0;
}
I know the original question specified HTML + CSS, but it didn't specifically say no javascript ;)
Trying to keep the css and markup as clean as possible, and as semantically meaningful as possible to (using a UL for the menu) I came up with this suggestion. Probably not ideal, but it may be a good starting point:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Kind-of-justified horizontal menu</title>
<style type="text/css">
ul {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
}
ul li {
display: block;
float: left;
text-align: center;
}
</style>
<script type="text/javascript">
setMenu = function() {
var items = document.getElementById("nav").getElementsByTagName("li");
var newwidth = 100 / items.length;
for(var i = 0; i < items.length; i++) {
items[i].style.width = newwidth + "%";
}
}
</script>
</head>
<body>
<ul id="nav">
<li>first item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>last item</li>
</ul>
<script type="text/javascript">
setMenu();
</script>
</body>
</html>
I want to place some text to the right of blue ribbon so that it would be on the same line with already existing elements. All my attempts to try doing that causes text occuring on the next line.
What can you recommend?
Here is the code: (JSFiddle)
HTML
<div id='ribbon'>
<ul id='topMenu'>
<li>Thing one</li>
<li>Thing two</li>
<li>Thing three</li>
</ul>
</div>
CSS
#topMenu {
height: 35px;
margin: 0; padding: 0;
}
#topMenu a {
color: black;
}
#topMenu li {
padding: 0 10px 0 10px;
float: left;
list-style-type: none;
}
#topMenu li:hover {
color: white;
background-color: #00D0FF;
}
UPD: But if I need that text not to be <li> element? I mean, not to use general <li> stylesheet.
You can use nth-of-type pseudo and float the elements to the right, for example
#topMenu li:nth-of-type(2), #topMenu li:nth-of-type(3) {
float: right;
}
Demo
Or you can simply use
#topMenu li:last-child {
float: right;
}
To shift the last li to the right. Also make sure you clear your floating elements nested inside ul, you can use a self clearing class like -
.clear_self:after {
content: "";
display: table;
clear: both;
}
So that it doesn't mess up your document flow. Just call that class on the ul element, i.e container element holding floated elements.
Also, you can alternative call classes on the li element which you want to float to the right of the ribbon, but incase if you don't want to increase your markup, you can use pseudo here..
As per your update
Demo 2
Explanation: Float your entire ul element to the left, and this will create an empty space on the right, so that the next div will shift to right cuz we are using float: right;, also make sure you clear your floating elements, else, the next div will sit right in the empty space, for more info on clearing floats, you can read my answer here..
Check out my fiddle. You needed to add float right to the last li. I separated it with a class of .last
#topMenu li.last{float:right;}
http://jsfiddle.net/9GGLE/2/
If you are trying to float another element, sibling of #ribbon, you can check out this jsFiddle
.floated { float:right; margin-top:-30px; /* this is to overcome height+padding of the ribbon */ }
I am trying to center my navigation links inside the div but no matter what I've tried it won't work. I've tried margin-left:auto, margin-right:auto, but nothing...
Here is the section of CSS code:
#nav {
display:block;
background-color:#505050;
height:17.5px;
box-shadow: 0px 0px 15px 5px #CCCCCC inset;
border:1px solid #EEEEEE;
border-radius:20px;
padding:1.5%;
}
#nav li {
padding:0px 20px 0px 20px;
display:inline;
/*float:left;*/
list-style:none;
position:relative;
}
#nav li a {
padding:0px 0px 20px 0px;
color:#FFFFFF;
text-decoration:none;
}
and here is my ul code:
<ul id="nav">
<li>Home</li>
<li>About Us</li>
<li>Current Litters</li>
<li>Gallery
<ul>
<li>Bandi</li>
<li>Studs Used</li>
<li>Test Dog2</li>
<li>Test Dog3</li>
</ul>
</li>
<li>Contact Us</li>
</ul>
Here is the rest of my code
actually without it i noticed that my drop down menu under (gallery) doesn't display correctly, ...here is the rest of that css file...that shows what happens to the drop down...maybe you can tell me why the float screws it all up...
...and the text align did great....but only after removing the float...
#nav li a:hover {
text-decoration:underline;
}
#nav li ul{
padding:10px;
font-size:medium;
display:none;
position:absolute;
left:0px;
top:30px;
background-color:rgba(50,50,50,0.8);
}
#nav li:hover ul {
display:block;
border-radius:20px;
border:1px solid;
width:150px;
}
This is actually quite simple, since your list items are display:inline. Add this style:
#nav {
text-align:center;
}
Demo: http://jsfiddle.net/fH6f5/
There are many other ways to do it, but this appears to be all you need. Just make sure not to float the <li>s (I see you have it commented out).
Adding text-align: center to the nav unordered list seems to work for me in chrome
#nav {
text-align: center;
}
To center a block element, you also need to explicitly set the width to some value, like this:
#nav {
width: 50%;
margin: 0 auto;
}
There are quite a few changes you're going to need to make to your code in order for it to display properly. Your list elements are currently inline elements. inline elements have a lot of restrictions, including not being able to explicitly set their width, height, and their top and bottom margin. Keep in mind that per the W3 spec:
Generally, inline elements may contain only data and other inline elements.
That being said, you can use display: inline-block with no problems for your current code. There is one very important thing to keep in mind about using inline-block elements: whitespace. Any space between inline-block elements in your code will be shown as a space on your browser. So, if you want the elements to be touching, their tags must be touching also:
<!-- Version A: This will produce a gap between the two elements -->
<li>Home</li>
<li>About Us</li>
<!-- Version B: This will not produce a gap between the two elements -->
<li>
Home
</li><li>
About Us
</li>
If you choose Version A from the code above, I'd recommend you float the elements rather than relying on inline-block for positioning. Centering a floated list is a bit more difficult than centering an inline list. Here's a way that I like to center floated elements:
<nav>
<ul>
<li>Home</li>
<li>About Us</li>
</ul>
</nav>
CSS:
nav { overflow: hidden; }
nav ul {
position: relative;
float: left;
left: 50%;
list-style: none;
padding: 0; }
nav ul li {
position: relative;
float: left;
right: 50%;
margin: 0 5px; }
nav ul li a { display: block; }
Preview: http://jsfiddle.net/Wexcode/rsDbY/
You should post the design that you want for your dropdown menu, I don't really know what you want your final result to look like so I can't really help you with that.
You need to set a fixed width on your ul for margin-right:auto and margin-left:auto
Have you tried to add margin: 0 auto; to #nav style? You also have to set the ul width to get this working.
It's a bit more complicated then simply "text-align" as you have the text inside of a . You need to add "margin: 0px auto;" to your element in your css file. This will then center the divider on the screen first, then center the next element within the divider and so on.
My site was working fine across all major browsers right up until the update to Safari 5.1. Now, the primary navigation is busted up. I was using display:table-cell on the anchor element within the list element and was also using the font-size:0 hack to remove the spacing in between menu elements. Has anyone else encountered this issue and have a solution they could offer up?
Before:
After:
CSS:
#navigation {
padding-top: 7px;
}
#navigation ul.links, /* Main menu and secondary menu links */
#navigation .content ul /* Menu block links */ {
margin: 0;
padding: 0;
display: block;
font-size: 0; /* this is a hack so that the spacing between the menu buttons disappear
since they are inline-block elements, this should be unneccessary when
CSS3 is approved */
}
#navigation ul.links li, /* A simple method to get navigation links to appear in one line. */
#navigation .content li {
display: inline-block;
padding-right: 0;
padding-left: 0;
margin: 0;
/* below is a fix for IE7 to get the main navigation items lined up correctly
* in one row
*/
zoom: 1;
*display: inline;
}
#main-menu ul {
width: 100%;
}
#main-menu li {
width: 108px;
text-align: center;
padding-bottom: 7px;
font-size: 11pt;
}
#main-menu a {
display: table-cell;
width: inherit;
text-decoration: none;
font-size: 0.9em;
color: #035B9A;
background-color: white;
height: 30px;
vertical-align: middle;
}
HTML:
<div id="navigation">
<div class="section">
<h2 class="element-invisible">Main menu</h2>
<ul id="main-menu" class="links inline clearfix">
<li class="menu-379 first">About Us</li>
<li class="menu-401">Research</li>
<li class="menu-385">Education</li>
<li class="menu-402">Outreach</li>
<li class="menu-403 active-trail active">News & Events</li>
<li class="menu-439">People</li>
<li class="menu-405">Resources</li>
<li class="menu-406">Publications</li>
<li class="menu-415 last">Partners</li>
</ul>
</div>
</div>
Thanks.
Just a note, this is a Drupal 7 site.
Also I freely and humbly admit I am not the very best at CSS markup. I'm learning a lot right now and am just trying to scrape through.
For those having trouble with Safari and dimensions for elements set to display:table; I was able to fix my problems by removing the padding and adding padding to a child element set to display:table-cell;
Apparently Safari does not like it when you try to add padding to an element set to display:table; In retrospect, this makes sense.
Solved by making the list elements display as block and float them to the left.
#navigation ul.links li, /* A simple method to get navigation links to appear in one line. */
#navigation .content li {
display: block;
float: left;
padding-right: 0;
padding-left: 0;
margin: 0;
/* below is a fix for IE7 to get the main navigation items lined up correctly
* in one row
*/
zoom: 1;
*display: inline;
}
You want border-collapse:collapse on the display:table element to remove cell spacing.
I took your css and html, and added to the css
body {
background-color: gray;
}
and I got the following, which looks correct.
This was run under lion, which has Safari 5.1
You find plenty of tutorials on menu bars in HTML, but for this specific (though IMHO generic) case, I haven't found any decent solution:
# THE MENU ITEMS SHOULD BE JUSTIFIED JUST AS PLAIN TEXT WOULD BE #
# ^ ^ #
There's an varying number of text-only menu items and the page layout is fluid.
The first menu item should be left-aligned, the last menu item should be right-aligned.
The remaining items should be spread optimally on the menu bar.
The number is varying,so there's no chance to pre-calculate the optimal widths.
Note that a TABLE won't work here as well:
If you center all TDs, the first and the last item aren’t aligned correctly.
If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.
Isn’t it strange that there is no obvious way to implement this in a clean way by using HTML and CSS?
The simplest thing to do is to is to force the line to break by inserting an element at the end of the line that will occupy more than the left available space and then hiding it. I've accomplished this quite easily with a simple span element like so:
#menu {
text-align: justify;
}
#menu * {
display: inline;
}
#menu li {
display: inline-block;
}
#menu span {
display: inline-block;
position: relative;
width: 100%;
height: 0;
}
<div id="menu">
<ul>
<li>Menu item 1</li>
<li>Menu item 3</li>
<li>Menu item 2</li>
</ul>
<span></span>
</div>
All the junk inside the #menu span selector is (as far as I've found) required to please most browsers. It should force the width of the span element to 100%, which should cause a line break since it is considered an inline element due to the display: inline-block rule. inline-block also makes the span possible to block-level style rules like width which causes the element to not fit in line with the menu and thus the menu to line-break.
You of course need to adjust the width of the span to your use case and design, but I hope you get the general idea and can adapt it.
Modern Approach - Flexboxes!
Now that CSS3 flexboxes have better browser support, some of us can finally start using them. Just add additional vendor prefixes for more browser coverage.
In this instance, you would just set the parent element's display to flex and then change the justify-content property to either space-between or space-around in order to add space between or around the children flexbox items.
Using justify-content: space-between - (example here):
ul {
list-style: none;
padding: 0;
margin: 0;
}
.menu {
display: flex;
justify-content: space-between;
}
<ul class="menu">
<li>Item One</li>
<li>Item Two</li>
<li>Item Three Longer</li>
<li>Item Four</li>
</ul>
Using justify-content: space-around - (example here):
ul {
list-style: none;
padding: 0;
margin: 0;
}
.menu {
display: flex;
justify-content: space-around;
}
<ul class="menu">
<li>Item One</li>
<li>Item Two</li>
<li>Item Three Longer</li>
<li>Item Four</li>
</ul>
Ok, this solution doesn't work on IE6/7, because of the lack of support of :before/:after, but:
ul {
text-align: justify;
list-style: none;
list-style-image: none;
margin: 0;
padding: 0;
}
ul:after {
content: "";
margin-left: 100%;
}
li {
display: inline;
}
a {
display: inline-block;
}
<div id="menu">
<ul>
<li>Menu item 1</li>
<li>Menu item 2</li>
<li>Menu item 3</li>
<li>Menu item 4</li>
<li>Menu item 5</li>
</ul>
</div>
The reason why I have the a tag as an inline-block is because I don't want the words inside to be justified as well, and I don't want to use non-breaking spaces either.
Got a solution. Works in FF, IE6, IE7, Webkit, etc.
Make sure you don't put any whitespace before closing the span.inner. IE6 will break.
You can optionally give .outer a width
.outer {
text-align: justify;
}
.outer span.finish {
display: inline-block;
width: 100%;
}
.outer span.inner {
display: inline-block;
white-space: nowrap;
}
<div class="outer">
<span class="inner">THE MENU ITEMS</span>
<span class="inner">SHOULD BE</span>
<span class="inner">JUSTIFIED</span>
<span class="inner">JUST AS</span>
<span class="inner">PLAIN TEXT</span>
<span class="inner">WOULD BE</span>
<span class="finish"></span>
</div>
Works with Opera , Firefox, Chrome and IE
ul {
display: table;
margin: 1em auto 0;
padding: 0;
text-align: center;
width: 90%;
}
li {
display: table-cell;
border: 1px solid black;
padding: 0 5px;
}
yet another solution. I had no option to tackle the html like adding distinguished class etc., so I found a pure css way.
Works in Chrome, Firefox, Safari..don't know about IE.
Test: http://jsfiddle.net/c2crP/1
ul {
margin: 0;
padding: 0;
list-style: none;
width: 200px;
text-align: justify;
list-style-type: none;
}
ul > li {
display: inline;
text-align: justify;
}
/* declaration below will add a whitespace after every li. This is for one line codes where no whitespace (of breaks) are present and the browser wouldn't know where to make a break. */
ul > li:after {
content: ' ';
display: inline;
}
/* notice the 'inline-block'! Otherwise won't work for webkit which puts after pseudo el inside of it's parent instead of after thus shifting also the parent on next line! */
ul > li:last-child:after {
display: inline-block;
margin-left: 100%;
content: ' ';
}
<ul>
<li>home</li>
<li>exposities</li>
<li>werk</li>
<li>statement</li>
<li>contact</li>
</ul>
Make it a <p> with text-align: justify ?
Update: Nevermind. That doesn't work at all as I'd thought.
Update 2: Doesn't work in any browsers other than IE right now, but CSS3 has support for this in the form of text-align-last
For Gecko-based browsers, I came up with this solution. This solution doesn't work with WebKit browsers, though (e.g. Chromium, Midori, Epiphany), they still show trailing space after the last item.
I put the menu bar in a justified paragraph. Problem is that the last line of a justified paragraph won't be rendered justified, for obvious reasons. Therefore I add a wide invisible element (e.g. an img) which warrants that the paragraph is at least two lines long.
Now the menu bar is justified by the same algorithm the browser uses for justifying plain text.
Code:
<div style="width:500px; background:#eee;">
<p style="text-align:justify">
THE MENU ITEMS
SHOULD BE
JUSTIFIED
JUST AS
PLAIN TEXT
WOULD BE
<img src="/Content/Img/stackoverflow-logo-250.png" width="400" height="0"/>
</p>
<p>There's an varying number of text-only menu items and the page layout is fluid.</p>
<p>The first menu item should be left-aligned, the last menu item should be right-aligned. The remaining items should be spread optimal on the menu bar.</p>
<p>The number is varying,so there's no chance to pre-calculate the optimal widths.</p>
<p>Note that a TABLE won't work here as well:</p>
<ul>
<li>If you center all TDs, the first and the last item aren't aligned correctly.</li>
<li>If you left-align and right-align the first resp. the last items, the spacing will be sub-optimal.</li>
</ul>
</div>
Remark: Do you notice I cheated? To add the space filler element, I have to make some guess about the width of the menu bar. So this solution is not completely down to the rules.
Text is only justified if the sentence naturally causes a line break. So all you need to do is naturally force a line break, and hide whats on the second line:
CSS:
ul {
text-align: justify;
width: 400px;
margin: 0;
padding: 0;
height: 1.2em;
/* forces the height of the ul to one line */
overflow: hidden;
/* enforces the single line height */
list-style-type: none;
background-color: yellow;
}
ul li {
display: inline;
}
ul li.break {
margin-left: 100%;
/* use e.g. 1000px if your ul has no width */
}
HTML:
<ul>
<li>The</li>
<li>quick</li>
<li>brown</li>
<li>fox</li>
<li class="break"> </li>
</ul>
The li.break element must be on the same line as the last menu item and must contain some content (in this case a non breaking space), otherwise in some browsers, if it's not on the same line then you'll see some small extra space on the end of your line, and if it contains no content then it's ignored and the line is not justified.
Tested in IE7, IE8, IE9, Chrome, Firefox 4.
if to go with javascript that is possible (this script is base on mootools)
<script type="text/javascript">//<![CDATA[
window.addEvent('load', function(){
var mncontainer = $('main-menu');
var mncw = mncontainer.getSize().size.x;
var mnul = mncontainer.getFirst();//UL
var mnuw = mnul.getSize().size.x;
var wdif = mncw - mnuw;
var list = mnul.getChildren(); //get all list items
//get the remained width (which can be positive or negative)
//and devided by number of list item and also take out the precision
var liwd = Math.floor(wdif/list.length);
var selw, mwd=mncw, tliw=0;
list.each(function(el){
var elw = el.getSize().size.x;
if(elw < mwd){ mwd = elw; selw = el;}
el.setStyle('width', elw+liwd);
tliw += el.getSize().size.x;
});
var rwidth = mncw-tliw;//get the remain width and set it to item which has smallest width
if(rwidth>0){
elw = selw.getSize().size.x;
selw.setStyle('width', elw+rwidth);
}
});
//]]>
</script>
and the css
<style type="text/css">
#main-menu{
padding-top:41px;
width:100%;
overflow:hidden;
position:relative;
}
ul.menu_tab{
padding-top:1px;
height:38px;
clear:left;
float:left;
list-style:none;
margin:0;
padding:0;
position:relative;
left:50%;
text-align:center;
}
ul.menu_tab li{
display:block;
float:left;
list-style:none;
margin:0;
padding:0;
position:relative;
right:50%;
}
ul.menu_tab li.item7{
margin-right:0;
}
ul.menu_tab li a, ul.menu_tab li a:visited{
display:block;
color:#006A71;
font-weight:700;
text-decoration:none;
padding:0 0 0 10px;
}
ul.menu_tab li a span{
display:block;
padding:12px 10px 8px 0;
}
ul.menu_tab li.active a, ul.menu_tab li a:hover{
background:url("../images/bg-menutab.gif") repeat-x left top;
color:#999999;
}
ul.menu_tab li.active a span,ul.menu_tab li.active a.visited span, ul.menu_tab li a:hover span{
background:url("../images/bg-menutab.gif") repeat-x right top;
color:#999999;
}
</style>
and the last html
<div id="main-menu">
<ul class="menu_tab">
<li class="item1"><span>Home</span></li>
<li class="item2"><span>The Project</span></li>
<li class="item3"><span>About Grants</span></li>
<li class="item4"><span>Partners</span></li>
<li class="item5"><span>Resources</span></li>
<li class="item6"><span>News</span></li>
<li class="item7"><span>Contact</span></li>
</ul>
</div>
Simpler markup, tested in Opera, FF, Chrome, IE7, IE8:
<div class="nav">
nav item1
nav item2
nav item3
nav item4
nav item5
nav item6
<span class="empty"></span>
</div>
and css:
.nav {
width: 500px;
height: 1em;
line-height: 1em;
text-align: justify;
overflow: hidden;
border: 1px dotted gray;
}
.nav_item {
display: inline-block;
}
.empty {
display: inline-block;
width: 100%;
height: 0;
}
Live example.
try this
*{
padding: 0;
margin: 0;
box-sizing: border-box;
}
ul {
list-style: none;
display: flex;
align-items: center;
justify-content: space-evenly;
}
<ul>
<li>List item One</li>
<li>List item Two</li>
<li>List item Three </li>
<li>List item Four</li>
</ul>
This can be achieved perfectly by some careful measurements and the last-child selector.
ul li {
margin-right:20px;
}
ul li:last-child {
margin-right:0;
}
I know the original question specified HTML + CSS, but it didn't specifically say no javascript ;)
Trying to keep the css and markup as clean as possible, and as semantically meaningful as possible to (using a UL for the menu) I came up with this suggestion. Probably not ideal, but it may be a good starting point:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>Kind-of-justified horizontal menu</title>
<style type="text/css">
ul {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
}
ul li {
display: block;
float: left;
text-align: center;
}
</style>
<script type="text/javascript">
setMenu = function() {
var items = document.getElementById("nav").getElementsByTagName("li");
var newwidth = 100 / items.length;
for(var i = 0; i < items.length; i++) {
items[i].style.width = newwidth + "%";
}
}
</script>
</head>
<body>
<ul id="nav">
<li>first item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>last item</li>
</ul>
<script type="text/javascript">
setMenu();
</script>
</body>
</html>