Special vertical alignment problem

Seemingly very simple. I’m working on a nav almost identical to the bar of buttons at the top of this site, except the bar itself needs to be set to a fixed height. If you want to have the entire <li> highlighted on mouseover, it’s height needs to be set to 100%. Ordinarily I would just use the padding of the <li> to determine the height of the parent, but that causes variance depending on the font and isn’t easily calculated down to the pixel. It seems if you set the margin/padding to zero it becomes impossible to use vertical-align. I suppose i could use the old +/- 50% relative positioning trick, but that would require extra markup. All my usual tricks seem to break here without doing something ugly…

example:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:dc="http://purl.org/dc/terms/"
    xml:lang="en">

    <head profile="http://dublincore.org/documents/2008/08/04/dc-html/">
        <title>Smorgbox</title>

        <meta http-equiv="X-UA-Compatible" content="chrome=1" />
        <meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
        <meta http-equiv="content-style-type" content="text/css" />

        <meta property="dc:creator" content="Dan Douglas" />
        <meta property="dc:format" content="application/xhtml+xml" />

        <style type="text/css">
            #top
            {
                background-color:#77bb10;
                height:44px;
                margin:0;
                padding:0;
            }

            .menu
            {
                display:inline-block;
                height:100%;
                color:#fff;
                font-family:sans-serif;
                list-style-type:none;
            }

            .menu li
            {
                float:left;
                vertical-align:middle;
                padding:0px 10px;
                height:100%;
            }

            .menu li:hover
            {
                background-color:#acdc55;
            }

        </style>
    </head>

    <body>
        <div id="top">
            <ul class="menu">
                <li>Home</li>
                <li>Messages</li>
                <li>Updates</li>
                <li>Search</li>
                <li>Settings</li>
            </ul>
        </div>
    </body>

</html>

This concept I came up with works just fine, but doesn’t specify an exact height (pretty cool nonetheless):

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

    <head>
        <title>Generated content menu tree</title>

        <meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
        <meta http-equiv="content-style-type" content="text/css" />

        <link rel="stylesheet" href="http://yui.yahooapis.com/3.2.0/build/cssreset/reset.css" type="text/css" />

        <style type="text/css">
            body
            {
                text-align:center;
                margin:40px;
            }
                
            #toplevel li
            {
                display:inline-block;
                position:relative;
                list-style:none;
                list-style-position:inside;
                padding:10px 0px;
            }

            #toplevel, #toplevel ul
            {
                display:inline-block;
                counter-reset:option;
                border-style:solid;
                border-radius:20px;
                -moz-border-radius:20px;
                -webkit-border-radius:20px;
            }

            #toplevel li > ul
            {
                display:none;
                position:absolute;
                width:100%;
                top:100%;
            }

            #toplevel li:hover > ul
            {
                display:block;
            }

            #toplevel li::before
            {
                content:"option " counter(option);
                counter-increment:option;
                padding:10px;
                border-radius:20px;
                -moz-border-radius:20px;
                -webkit-border-radius:20px;
            }

            /* do something different for part of the tree */
            #toplevel li.different li::before, #toplevel li.different::before
            {
                content:"I'm&nbsp;different&nbsp;" counters(option, ".") "&nbsp;";
            }

            #toplevel li:hover::before
            {
                background-color:#f00;
            }

            #toplevel ul ul
            {
                left:100%;
                top:0;
            }
        </style>
    </head>

    <body>
        <ul id="toplevel">
            <li /> <!-- 1 -->
            <li> <!-- 2 -->
            <ul>
                <li />
                <li />
                <li />
                <li>
                <ul>
                    <li />
                    <li />
                    <li />
                    <li />
                    <li />
                </ul>
                </li>
                <li />
            </ul>
            </li>
            <li> <!-- 3 -->
            <ul>
                <li />
                <li>
                <ul>
                    <li>
                    <ul>
                        <li />
                        <li />
                        <li>
                        <ul>
                            <li />
                        </ul>
                        </li>
                    </ul>
                    </li>
                    <li />
                </ul>
                </li>
                <li />
                <li />
                <li />
                <li />
                <li />
            </ul>
            </li>
            <li class="different"> <!-- 4 -->
            <ul>
                <li>
                <ul>
                    <li>
                    <ul>
                        <li>
                        <ul>
                            <li>
                            <ul>
                                <li />
                                <li />
                                <li />
                            </ul>
                            </li>
                            <li />
                            <li />
                        </ul>
                        </li>
                        <li />
                        <li />
                    </ul>
                    </li>
                    <li />
                    <li />
                </ul>
                </li>
                <li />
                <li />
            </ul>
            </li>
            <li> <!-- 5 -->
            <ul>
                <li>
                <ul>
                    <li>
                    <ul>
                        <li />
                    </ul>
                    </li>
                    <li>
                    <ul>
                        <li />
                        <li />
                        <li />
                    </ul>
                    </li>
                </ul>
                </li>
                <li />
                <li>
                <ul>
                    <li />
                    <li />
                    <li />
                </ul>
                </li>
            </ul>
            </li>
        </ul> 
    </body>

</html>

Ah “line-height” is the trick. I didn’t quite understand the description of that one at first. Too bad setting line-height:100%; doesn’t adjust the height to match parents.

I also discovered if you either float or inline-block #top then line-height is inherited and 44px only needs to be defined in one place.


#top
{
    background-color:#77bb10;
    line-height:44px;
    float:left;
}

.menu
{
    color:#fff;
    font-family:sans-serif;
    list-style-type:none;
    margin:0;
    padding:0;
}

.menu li
{
    float:left;
    padding:0 10px;
}

.menu li:hover
{
    background-color:#acdc55;
}

If the text is a single line of text that won;t wrap then you can just set the line-height to the same as the height of the line and it will be perfectly centered and will allow for the font to grow (a bit) without breaking the height.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:dc="http://purl.org/dc/terms/"
    xml:lang="en">
<head profile="http://dublincore.org/documents/2008/08/04/dc-html/">
<title>Smorgbox</title>
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
<meta http-equiv="content-style-type" content="text/css" />
<meta property="dc:creator" content="Dan Douglas" />
<meta property="dc:format" content="application/xhtml+xml" />
<style type="text/css">
#top {
    background-color:#77bb10;
    height:44px;
    margin:0;
    padding:0;
}
.menu {
    color:#fff;
    font-family:sans-serif;
    list-style-type:none;
    margin:0;
    padding:0;
}
.menu li {
    float:left;
    vertical-align:middle;
    line-height:44px;
    margin:0 25px;
}
.menu li:hover {
    background-color:#acdc55;
}
</style>
</head>
<body>
<div id="top">
    <ul class="menu">
        <li>Home</li>
        <li>Messages</li>
        <li>Updates</li>
        <li>Search</li>
        <li>Settings</li>
    </ul>
</div>
</body>
</html>


If you want horizontal alignment then inline-block is a good method as you can center it with text-align:center on the parent.