Is it acceptable to post a HTML/CSS file that others may find useful?

I have spent some time trying to figure out why it is so difficult to center a nav bar. I searched the web and downloaded some examples that claimed to be centered. After some checking, everyone I found was not centered as advertised. So, I decided to see if I could figure it out on my own and made good progress.

So, if someone can let me know where to post this info - which BTW, is simply a codepen link, I will do so.

Thanks!

Sure; go post.

Your method is almost guaranteed to not be new; no offense :slight_smile: .

Itā€™s always fun to look at code though so please share!

@RyanReese

Thanks for the quick response. Here is the codepen link.

The only thing that needs tweaking is how to evenly space each menu item within the nav bar. This will become abundantly clear once the borders are removed because most menu items have a different char count.

Hopefully, someone with more experience than I can figure this out.

Thanks.

Thatā€™s a pretty common way. Using margin:0 auto to center things (not just menus) have been around for ā€¦ever since CSS was made. 15ish years maybe? 10? Hard to say when it was introduced (auto margins) since I wasnā€™t around.

Thatā€™s a neat demo though so thank you for posting it.

@RyanReese

Thanks for the feedback.

Do you know of a way to evenly space each nav menu item?

I suspect it would take a language that incorporates logic such as js.

Thanks again.

Do you mean like this?

Glad youā€™ve taken some time to experiment as you learn a lot that way :slight_smile:

However, the approach you have taken is slightly flawed because you have set fixed widths for the nav items which means should a user resize their text it will no longer fit into the width you specified.

An easier approach is to use padding as shown in Ralphs demo (although I would have used display:table-cell instead of inline-block to allow text to wrap within cells if needed and to keep equal cells).

Whenever you find yourself making complicated calculations then most of the time that is the wrong approach. For example what happens when the client says he needs one more menu item or one less menu item you would then need to change all your calculations.

Much better to let the menu flow by itself without fixing the widths on each item.

Mr. Smarty Pants here dorking with our adminā€™s perfectly good code.

This menu will remain the full width of the page as determined by the big red box and its horizontal padding.

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/stylesheet.css">
    <title>equally spaced menu items</title>
<!--
Box with red border is the reference.
Some horizontal padding is desirable.
Width of menu items remains within a 6px "drift range" at each end
  as text size changes and/or width of page changes.
Jumpy, but works :)
-->
    <style type="text/css">

#bigBox {
    width: 90%;
    border: 2px solid red;
    padding: 10px 24px;   /* added some horizontal padding */
    margin: 0 auto;
}

#mainNav {
    list-style: none;
    display:table;
    white-space:nowrap;   /* to prevent list items from wrapping */
    border: 1px solid blue;
    text-align: center;
    padding: 0;
    margin: 0 auto;
}

li {
    display: inline-block;
    vertical-align:top;   /* to prevent white space above list items */
}

#mainNav a {
    display: block;
    color: #000;
    font-size: 11px;
    text-transform: uppercase;
    text-decoration: none;
    border: 1px solid green;
    text-align: center;
    background-color: #E7E7E7;
    padding: 7px 12px;      
}

#mainNav a:hover {
    background-color: #B2F511;
}
    </style>
</head>
<body>

<div id="bigBox">  <!-- changed to IDs because I don't know how to do this with classes -->
    <ul id="mainNav">
        <li><a href="/index.html">Home</a></li><!--
     --><li><a href="/features/">Features</a></li><!--
     --><li><a href="/experts/">Experts</a></li><!--
     --><li><a href="/quiz/">Quiz</a></li><!--
     --><li><a href="/projects/">Projects</a></li><!--
     --><li><a href="/horoscopes/">Horoscopes</a></li>
     </ul>
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>
<script>
(function(){
    var attachEvent = document.attachEvent;
    var isIE = navigator.userAgent.match(/Trident/);
    var requestFrame = (function() {
        var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
            function(fn) { return window.setTimeout(fn, 20); };
        return function(fn) { return raf(fn); };
    })();

    var cancelFrame = (function() {
        var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
            window.clearTimeout;
        return function(id) { return cancel(id); };
    })();

    function resizeListener(e) {
        var win = e.target || e.srcElement;
        if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
        win.__resizeRAF__ = requestFrame(function() {
            var trigger = win.__resizeTrigger__;
            trigger.__resizeListeners__.forEach(function(fn){
                fn.call(trigger, e);
            });
        });
    }

    function objectLoad(e) {
        this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
        this.contentDocument.defaultView.addEventListener('resize', resizeListener);
    }

    window.addResizeListener = function(element, fn) {
        if (!element.__resizeListeners__) {
            element.__resizeListeners__ = [];
            if (attachEvent) {
                element.__resizeTrigger__ = element;
                element.attachEvent('onresize', resizeListener);
            } else {
                if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
                var obj = element.__resizeTrigger__ = document.createElement('object');
                obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
                obj.__resizeElement__ = element;
                obj.onload = objectLoad;
                obj.type = 'text/html';
                if (isIE) element.appendChild(obj);
                obj.data = 'about:blank';
                if (!isIE) element.appendChild(obj);
            }
        }
        element.__resizeListeners__.push(fn);
    };

    window.removeResizeListener = function(element, fn) {
        element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
        if (!element.__resizeListeners__.length) {
            if (attachEvent) element.detachEvent('onresize', resizeListener);
            else {
                element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
                element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
            }
        }
    }
})();

function fitMenu() {
    var buttons = $('#mainNav a');         // # of button objects
    var padd = parseInt($(buttons[1]).css('padding-right'));
    var menuBox = $('#bigBox').width();
    var navWidth = $('#mainNav').width();
    var drift = 2*$(buttons).length;
    var diff = (menuBox - navWidth);
    if (diff < 0 || diff >= drift) {
        correction = Math.floor(diff/drift);
        padd = padd + correction;
        for (i = 0; i < buttons.length; i++) {
            $(buttons[i]).css('padding-left',padd);
            $(buttons[i]).css('padding-right',padd);
        };
    };
};
var myElement = document.getElementById('bigBox'),
myResizeFn = function(){
    fitMenu();
};
addResizeListener(myElement, myResizeFn);

window.onresize = fitMenu;
window.onload = fitMenu;
</script>

</body>
</html>

@ralphm

Thatā€™s perfect! I will dissect and learn from that.

Thank you so much for your post.

@ronpat

Mr. Smarty Pants, huh. Haha!

Great post. Thanks for tuning up the markup with a dash or two of js. I appreciate the help.

Iā€™m not actually sure it is, as Iā€™ve noticed it has a slight display problem at one end in some browsers. It was just a quick experiment, but @PaulOB will know a better solution.

Edit: hah, heā€™s already spoken in post 7.

Yes, I did that at first, but the spacing was a bit weird. Instead of investigating further, I copped out and used inline-block, but Iā€™m not sure it works too well. I suspect display: flex would work well, but havenā€™t time to figure it out right now.

@PaulOB

Thanks very much for your critique.

I have to agree with all that you have said. As a rookie coder, I know I have a long ways to go. This was done simply as a learning experience for me. That said, with all the help I have received on this forum, my skill level is improving substantially.

Thanks again for all your help.

There are often many ways to do the same thing as shown by the examples above but generally it depends on context as to which is the best method to use.

In your example you seemed to want a menu that wasnā€™t full width but perhaps only 70% wide and then centred which you could have done easily by using display:table and setting a 70% width and margin:auto

Hereā€™s how I would do it.

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
.bigBox{
    border:1px solid red;
    padding:10px;
}
.nav{
    display:table;
    border-collapse:collapse;
    width:75%;
    margin:auto;    
}
.nav a{
    display:table-cell;
    vertical-align:middle;
    text-align:center;
    padding:5px 2px;
    background:red;
    color:#fff;
    text-decoration:none;
    border:1px solid #666;
}
.nav a:hover{background:blue}
@media screen and (max-width:500px){
    .nav a{display:block;}
}

</style>
</head>

<body>
<div class="bigBox">
        <nav class="nav">
                <a href="/index.html">Home</a>
                <a href="/features/">Features</a>
                <a href="/experts/">Experts</a>
                <a href="/quiz/">Quiz</a>
                <a href="/projects/">Projects</a>
                <a href="/horoscopes/">Horoscopes</a>
        </nav>
</div>
</body>
</html>

Iā€™m not a fan of bare anchors next to each other but this is a feature of html5 and does make things easier for examples like this.

The table-cell algorithm is in fact more clever than just providing equal space as it distributes the items across the menu but allows more room for longer items which is more pleasing to the eye than having a fixed amount of space on each item no matter how long the text is.

The table-cell algorithm also means that no widths are needed on the cells and will accommodate the text size differences between browsers without upsetting anything.

3 Likes

Good point. I only rejected it because it didnā€™t do what was asked, but it does look better that way imho.

Iā€™d say nav is a feature, but from what I read it doesnā€™t help make bare links any more readable for screen readers ā€¦ unless something has changed.

Even though you can just put bare links next to each other, as they are a list of links, shouldnā€™t they still be in a unordered list? Unless Nav implies an implicit list of links which I donā€™t think it does?

The specs are a little ambiguous on this as they first say:

But then goes on to say without explaining the difference from the first term:

I believe that ā€˜navā€™ describes navigation items rather than a list of things. In my mind either the list is superfluos or the nav is superfluos. :slight_smile: I find it a little pointless to add a new html5 element only to nest superfluous elements inside.

Notwithstanding the above the demo I created cannot have list items holding the anchors because that breaks the table-cell structure (if you always want cells of equal height). It is just impossible to do without the structure I used. If you set the list to display:table-cell and then the anchor to display:block you will find that when text wraps to a new line the other links do not fill the whole cell because anchors are no longer display:table-cell (the list elementis display:table-cell but it cant be a link as well).

Itā€™s one of those occasions when yiu need to bend the rules a little to get what you want :smile:

I believe that Mallory mentioned that modern screen readers have no problems with this. It used to be that they (screen readers) would read links next to each other as a sentence without pausing. It would be easier enough to put a pipe character between each anchor and just move the pipe off screen if this was a real issue.

1 Like

I see what you mean, but in my mind, it generically indicates to a chunk of information which is related to navigation. So an agent could look for the nav block and analyse it for navigational information instead of scanning a whole document and making some sort of guess on what is related to navigation. A bit like <div id="navigationBlock"> but where everyone knows the id terminology that will be used to identify the navigation block.

Iā€™m sure you have a reason why this doesnā€™t work, as you know far more about CSS than me, but it works ok in Chrome!

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<style>
.bigBox{
    border:1px solid red;
    padding:10px;
}
.nav ul {
    display:table;
    border-collapse:collapse;
    width:75%;
    margin:auto;    
}
.nav li {
    display:table-cell;
    vertical-align:middle;
    text-align:center;
    border:1px solid #666;
    padding: 0;
}
.nav a {
    text-decoration:none;
    background:red;
    color:#fff;
    display: block;
    padding:5px 2px;
}
.nav a:hover{background:blue}
@media screen and (max-width:500px){
    .nav li{display:block;}
}

</style>
</head>

<body>
<div class="bigBox">
        <nav class="nav">
            <ul>
                <li><a href="/index.html">Home</a></li>
                <li><a href="/features/">Features</a></li>
                <li><a href="/experts/">Experts</a></li>
                <li><a href="/quiz/">Quiz</a></li>
                <li><a href="/projects/">Projects</a></li>
                <li><a href="/horoscopes/">Horoscopes</a></li>
            </ul>
        </nav>
</div>
</body>
</html>

:slight_smile:

What doesnā€™t work about it? Checked in Chrome, FF, and IE11 and all are identical.

1 Like

Actually that version isnā€™t quite right, because the anchors dont fill the list elements, and the colours are wrong. I edited the code accordingly though so my post is how I meant it to be.

Iā€™m not trying to be difficult, but Chrome/FF/IE11 all have the same colors, all anchors seem to be filling up the spaceā€¦

IE11 is missing borders but you set border-collapse rule soā€¦

What browser? Version? Screenshots? Iā€™m interested; donā€™t see anything off the top of my head thatā€™s wrong with that CSS.

Edit-RT clarified in PM he didnā€™t test other browsers but was just wondering if it was good x-browser. Apologies.