How do I *really* justify a horizontal menu in HTML+CSS?
Solution 1:
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><a href="#">Menu item 1</a></li>
<li><a href="#">Menu item 3</a></li>
<li><a href="#">Menu item 2</a></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.
Solution 2:
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>
Solution 3:
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><a href="#">Menu item 1</a></li>
<li><a href="#">Menu item 2</a></li>
<li><a href="#">Menu item 3</a></li>
<li><a href="#">Menu item 4</a></li>
<li><a href="#">Menu item 5</a></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.
Solution 4:
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>
Solution 5:
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;
}