Lisa
Lisa

Reputation: 893

Responsive vertical centering list item in navigation menu

I'm working on a responsive website and want to center it's text. I can do this with the line-height, but then it won't be responsive, and when the nav element becomes smaller, the line height stays the same. So, it basically screws up my design.

Is there any way to get that line-height responsive, or any other (responsive) way to place the text in the vertical center? It seems like such a simple thing but I can't figure it out.

Here's a fiddle: http://jsfiddle.net/4zahumwm/

HTML:

<h1 title="test">test</h1>
<nav id="nav-utility">
    <ul>
        <li><a href="#">HOME</a></li>
        <li><a href="#">MY STORY</a></li>
        <li class="mid-left"><a href="#">GALLERY</a></li>
        <li class="mid-right"><a href="#">RATES</a></li>
        <li><a href="#">TERMS</a></li>
        <li><a href="#">CONTACT</a></li>
    </ul>
</nav>

<div id="container"></div>

CSS:

html, body{
    width:100%; height:100%;
    margin:0; padding:0;    
}

html {  
}

div#container{
    width:100%;
    height:95.7%;

    background: url(background/monitor/IMG_5929.jpg) no-repeat center center fixed; 
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;}

h1{
    background-image:url(images/menu/polygon.png);
    display: block;
    height: 71px;
    left: 50%;
    margin:0; padding:0;    
    margin-left: -43px;
    position: absolute;
    text-indent: -9999px;
    top: 0;
    width: 87px;
    z-index: 1;

}

nav{
    width:100%;
    height:4.28%;
    /*min-height:40px;*/

    margin:0; padding:0;    

    background-color:#000000;

    list-style:none;
    text-align:center;
}

li, ul, a{
    margin:0; padding:0;    
    height:100%;
}

#nav-utility li{font-size:110%;color:#2bbfc4;}
#nav-utility li:before{content:'\00B7';padding-right:20px; padding-left:-10px;}
#nav-utility li:first-child:before{content:normal;}
#nav-utility li:last-child{padding-right:0;}
#nav-utility li:first-child{margin-left:-8px;}
#nav-utility li:nth-child(4):before{content:normal;}

nav ul{
}

nav li{
    display: inline-block;
    vertical-align:middle;
}

nav li a{
    font-family:Gotham, "Helvetica Neue", Helvetica, Arial, sans-serif;

    font-size:20px;
    color:white;

    text-decoration:none;
    line-height:4.28%;
}

nav li a:hover{
    border-bottom: 1px solid #196595;
    padding-bottom:1px;
}

nav li a:active{
    font-weight:bold;
}

nav ul li{
    margin: 0 10px 0 10px;
}

nav li.mid-left{
    margin-right: 63px; 
}
nav li.mid-right{
    margin-left: 63px;
}

Upvotes: 12

Views: 3711

Answers (4)

misterManSam
misterManSam

Reputation: 24692

Final Product

My first solution can be found at the bottom of this post.

We are actually making this harder than necessary... Let's make a tasty hamburger!

Wrap the nav and logo in <header>:

<header class="hamburger">
    <h1>Logo</h1>
    <nav></nav>
</header>

They will now be the filling between the hamburger buns which look like this:

header:before, header:after {
    content:'';
    display: block;
    height: 50%;
    background: #000;
    width: 100%;
}

This gives us the equivalent of:

<header class="hamburger">
    <div>:before bun</div>
        <h1>Logo</h1>
        <nav></nav>
    <div>:after bun</div>
</header>
  • The header:before and header:after are each given the same percentage height

  • The <header> container controls the height of the pseudo element (:before,:after) children

  • The <nav> is contained in-between and is perfectly centred vertically.

HTML / CSS / Demo Snippet

html,body {
height: 100%;  
}

body {
  margin: 0;
}

header {
    position: relative;
    background: #000;
    height: 4.3%;
    min-width: 800px;
}
/* 
   Create a spacer above and below the nav 
   to center the menu between them  
*/
header:before, header:after {
    content:'';
    display: block;
    height: 50%;
    background: #000;
    width: 100%;
}
h1 {
    background-image: url(http://imandragrafie.nl/demo/images/menu/polygon1.png);
    height: 80px;
    margin:0;
    padding:0;
    text-indent: -9999px;
    width: 100px;
    position: absolute;
    top: 0;
    left: 50%;
    margin-left: -40px;
}
nav#mainMenu {
    width:100%;
    text-align: center;
    margin:0;
    padding:0;
    background-color:#000000;
}
nav#mainMenu a {
    font-family:"Gill Sans", "Gill Sans MT", "Myriad Pro", "DejaVu Sans Condensed", Helvetica, Arial, sans-serif;
    font-size:1.2em;
    color: #FFF;
    text-decoration: none;
    vertical-align: middle;
}
/* create a spacer to get those dots */
 nav#mainMenu a:after {
    content:'\00B7';
    color:#2bbfc4;
    display: inline-block;
    width: 0;
    padding: 0 2%;
}
/*remove the dot and give a width to create a space for the image */
 nav#mainMenu a.mid-left:after {
    width: 120px;
    content:'';
}
/* No spacer for the last child */
 nav#mainMenu a:last-child:after {
    display: none;
}
<header>
	<h1 title="IMANDRAGRAFIE">IMANDRAGRAFIE</h1> 
	<nav id="mainMenu"><a href="index.html">HOME</a><a href="story.html">MY STORY</a><a href="gallery.php" class="mid-left">GALLERY</a><a href="rates.html" class="mid-right">RATES</a><a href="terms.html">TERMS</a><a href="contact.html">CONTACT</a></nav>
</header>


Archived Solution

This is very possible with just CSS.

To vertically align the menu, there is a nifty display: inline-block trick using a pseudo element that will pull the text down. In my example it looks like this:

nav:before {
    display: inline-block;
    content: '';
    vertical-align: middle;
    height: 100%;
}

This works because it places an invisible element that positions itself to the left of the <a> links which are then forced to line up in the middle. It will work across all modern browsers and IE8+.

(If you really really need this to work in IE 6 and 7, it can be placed with a real <div>. Personally I would allow IE 6 and 7 to just degrade gracefully and not vertically centre.)

This is a good way to visualise it. The vertical block is nav:before, the horizontal highlight is the ideal position for the current font size.

Screenshot

  • I have simplified your example by removing the unneeded list item elements

  • You can "run code snippet" at the bottom. You can also have a play with this jsBin example.

  • I have stripped your example to the bare bones, but you can easily make changes

As discussed, please note that the vertical centre of the text will be affected by its line-height and the ideal line-height will change dependant upon the typeface. You can also help line your text vertically by slightly increasing the height of nav:before.

Read more about the line-height issue here.

CSS / HTML

html,body {
    height:100%;
    margin:0;
}

/*
 - height as a percentage to keep it flexible
 - max-height so it doesn't get too big
 - min-height so it doesn't get too small
*/
nav {
    background:#000;
    height:4.3%;
    min-height: 2em;
    max-height:8em;
    text-align:center;
    position:relative;
}

/* 
 - line-height will help get text perfectly vertical (or mess it up for you)
 -- line-height will change with each typeface, watch out
 
 more information 
 -> https://stackoverflow.com/questions/14061228/remove-white-space-above-and-below-large-text-in-an-inline-block-element
*/
nav a {
    font-family:Gotham,"Helvetica Neue",Helvetica,Arial,sans-serif;
    color:#FFF;
    text-decoration:none;
    vertical-align:middle;
    line-height:2;
}

/* 
 - pseudo element to pull the text down to center vertically
 - height can be modified if needed to help offset line-height differences between typefaces
*/
nav:before {
    display:inline-block;
    content:'';
    vertical-align:middle;
    height:100%;
}

/*
 - create a spacer to get those dots 
 - percentage right and left padding
*/
nav a:after {
    content:'\00B7';
    display:inline-block;
    width:0;
    padding:0 2%;
}

/* 
 - No spacer for the last child 
 - apply "display: none" to any a:after that shouldn't have a spacer
*/
nav a:last-child:after {
    display:none;
}
<nav id="nav-utility">
    <a href="#">HOME</a>
    <a href="#">MY STORY</a>
    <a href="#">GALLERY</a>
    <a href="#">RATES</a>
    <a href="#">TERMS</a>
    <a href="#">CONTACT</a>
</nav>

Upvotes: 7

Raad
Raad

Reputation: 4648

There is a simple way of doing this using CSS3 transforms.

You just need an additional container <div class="align-vert"> around your ul:

<h1 title="test">test</h1>
<nav id="nav-utility">
  <div class="align-vert">
    <ul>
        <li><a href="#">HOME</a></li>
        <li><a href="#">MY STORY</a></li>
        <li class="mid-left"><a href="#">GALLERY</a></li>
        <li class="mid-right"><a href="#">RATES</a></li>
        <li><a href="#">TERMS</a></li>
        <li><a href="#">CONTACT</a></li>
    </ul>
  </div>
</nav>

and a new class to go with it:

.align-vert {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}

See http://codepen.io/raad/pen/Evtmi (I bumped the nav sizing up so you can see the vertical alignment more easily).

The downside is you only get native IE support from IE9 onwards (although there may be a way of using the the MS matrix filter - see http://caniuse.com/#feat=transforms2d).

Upvotes: 0

Salman Arshad
Salman Arshad

Reputation: 272006

CSS table display is an effective way to vertically center align content:

#nav-utility ul { display: table; height: 100%; }
#nav-utility li { display: table-cell; vertical-align: middle; }

Because the table cells have variable widths, the border between 3rd and 4th cell might not align with the horizontal center of page. So you need to break the menu into two menus and use absolute positioning:

#nav-utility { position: relative; }
#nav-utility ul { position: absolute; top: 0; }
#nav-utility ul:nth-child(1) { right: 50%; }
#nav-utility ul:nth-child(2) { left: 50%; }

Putting all this together and adding resets, pseudo bullets and decoration you get this stack snippet:

html, body {
    height: 100%;
}
body {
    margin: 0;
    padding: 0;
}
h1 {
    position: absolute;
    top: 0;
    left: 50%;
    z-index: 1;
    margin: 0 0 0 -43px;
    width: 87px;
    height: 71px;
    background-image: url(http://dummyimage.com/87x71/999/000&text=LOGO+87x71);
    text-indent: -9999px;
}
#nav-utility {
    position: relative;
    margin: 0;
    padding: 0;
    height: 4.28%;
    color: #2BBFC4;
    background-color: #000000;
}
#container {
    height: 95.7%;
    background: url(http://lorempixel.com/400/400/sports/1/) no-repeat center center fixed;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
}
#nav-utility ul {
    display: table;
    position: absolute;
    top: 0;
    margin: 0;
    padding: 0;
    height: 100%;
    list-style: none;
}
#nav-utility ul:nth-child(1) {
    right: 50%;
    margin-right: 53px;
}
#nav-utility ul:nth-child(2) {
    left: 50%;
    margin-left: 53px;
}
#nav-utility li {
    display: table-cell;
    vertical-align: middle;
}
#nav-utility li:nth-child(n + 2) {
    padding-left: 10px;
}
#nav-utility li:nth-child(n + 2):before {
    content: "\00B7";
    padding-right: 10px;
}
#nav-utility a {
    font-family: sans-serif;
    font-size: 20px;
    color: #FFFFFF;
    text-decoration: none;
}
#nav-utility a:hover {
    margin-bottom: -1px;
    border-bottom: 1px solid #196595;
}
#nav-utility a:active {
    font-weight: bold;
}
<h1 title="test">test</h1>
<nav id="nav-utility">
    <ul>
        <li><a href="#">HOME</a></li>
        <li><a href="#">MY STORY</a></li>
        <li><a href="#">GALLERY</a></li>
    </ul>
    <ul>
        <li><a href="#">RATES</a></li>
        <li><a href="#">TERMS</a></li>
        <li><a href="#">CONTACT</a></li>
    </ul>
</nav>
<div id="container"></div>

Upvotes: 3

Wissam El-Kik
Wissam El-Kik

Reputation: 2515

I don't think this can be done using CSS. Here's a solution using JS:

You might want to check these too:

"Responsive font-size" isn't supported on all the browsers/devices yet.

Using "responsive font-size" and FlowType, will allow the font to be calculated in a consistent way across all the devices. Next step would be to add "padding-top" and "padding-bottom" to the following selector: "nav li a". You can use "%" or "px" for the padding, and you should get rid of the "line-height" property.

Upvotes: 0

Related Questions