• Sign in to Neowin Faster!

    Create an account on Neowin to contribute and support the site.

  • 0
Sign in to follow this  

[JS] Center a menu that is floated left.

Question

jordan.    9

I found the following snippet of javascript (uses jQuery) that would allow me to centre a menu/nav that is set to float:left. It seems to work in IE and Opera OK. But in FF and Safari, it works sometimes and other times trips out (keep refreshing the page and it will eventually work/fail). In Chrome it doesn't work at all.

Here is the code:

$(function() {
	var menu_width = $('#nav').css('float', 'left').width();
	$('#nav').css({float : 'none', width : menu_width, margin : '0 auto'});
});

I don't know js so I can't figure out what the problem is. If anyone can help it would be much appreciated.

Here is the page running the code:

http://www.islandrobot.com/vanessa/

Cheers,

Jordan

Share this post


Link to post
Share on other sites

15 answers to this question

Recommended Posts

  • 0
Cupcakes    151

I'm a little confused. You're trying to.. center what? The text? the drop down menu items itself? The entire main navigation?

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

Sorry, yes I am trying to centre the entire navigation on that blue strip. Without the js it would be aligned to the left. With the js it should be centred.

P.s. I made an edit to my above post and then deleted it. If you saw the edit, just ignore it ;)

Share this post


Link to post
Share on other sites
  • 0
Cupcakes    151

Well, your entire menu as it is right now between margin/padding for each list item is 908px width. Why not just set ul#nav to 908px (or whatever it needs to be adjusted to) and margin: 0 auto?

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

That would be the easy way out, yes. But I would rather have it centre automatically since the client may add/remove/rename items from the menu at any time which would mean manually recalculating and changing the width. Since they don't know CSS I wouldn't expect them to have to do that.

Share this post


Link to post
Share on other sites
  • 0
Cupcakes    151

It wasn't the easy way out when I looked over your code but rather the logical solution to your problem based only on your initial post (which didn't say that the menu would actually be dynamic versus static.)

That being said the best bet is to replace float: left for display:inline. Then you can have all list items centered under the unordered list without needing any javascript.

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

That being said the best bet is to replace float: left for display:inline. Then you can have all list items centered under the unordered list without needing any javascript.

I tried this method at first but encountered problems with the drop down menus. I couldn't get them to fall directly under their parent li. Instead, the drop-downs always appeared in the far left corner (beginning of the root ul) regardless of which li you were mousing over (if that makes any sense). I played around with it for a while but couldn't get it to behave the way I wanted.

I also tried using inline-blocks which worked nicely except in FF2 which doesn't support it. -moz-inline-box didn't help either because of the drop-down menus.

JS seems like my last and only resort to have a centred, horizontal menu of unknown width and with drop down menus.

Share this post


Link to post
Share on other sites
  • 0
sweetsam    31

Try this...


$(function() {
        var menu_width = $('#nav').css('float', 'left').width();
        mleft = Math.round(($('#nav').parent().width() - menu_width) * 0.5);
        $('#nav').css('marginLeft', mleft);
});

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

Hi sweetsam. That seems to have helped a little bit. It at least works in Chrome now sometimes where as it didn't work at all before. However, it is still failing on some page loads. If you keep refreshing the page in FF/Chrome/Safari (Opera and IE seem stable) it will eventually get screwed up. Is this a common problem with javascript? Could it be a jQuery issue?

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

An update:

I've almost got it pegged now. Previously I did not have float:left; applied to #nav (which is the ul). I only had it applied to the li's. As I understood it, the .css('float', 'left') part of the script was trying to add the float to #nav for me??? Well I took that part out and just added float:left; to #nav in the css. This made #nav wrap snug around the li's and allowed for the correct width to be determined. Now everything seems stable in FF.

EDIT: FF is still giving the same problem as Chrome and Safari

Chrome and Safari still seem to be having slight problems getting it perfectly centred though. Sometimes its a bit more to the left and other times it's perfect.

I have also simplified the script down to this:

$(function() {
        var mleft = Math.round(($('#nav-wrap').width() - $('#nav').width()) * 0.5);
        $('#nav').css('margin-left', mleft);
});

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

Ok I am pretty sure now that the problem is a simple matter of the calculations being made before the navigation part of the page has been drawn up (if that makes sense). I realize this as some testing showed that occasionally $('#nav-wrap').width() and $('#nav').width() were returning results like 1407 and 1367 respectively. This would also explain why the browsers with faster javascript engines are having the problem more frequently. How can I make sure that the calculations are only made AFTER the html/css has been drawn up by the browser?

Sorry for all these posts, as I said in the beginning I don't know much about js so figuring this out is a whole learning experience :/

EDIT: HOT DAMN.... I guess it was as simple as moving my stylesheet above the javascript. All good now :)

Share this post


Link to post
Share on other sites
  • 0
kyosuken    6

To avoid this kind of problem though you should have done this :


$(document).ready(function() {
$(function() {
 var mleft = Math.round(($('#nav-wrap').width() - $('#nav').width()) * 0.5);
 $('#nav').css('margin-left', mleft);
});});

It ensures any jquery is applied after the dom has been fully parsed, most of the time the effect is instant.

Share this post


Link to post
Share on other sites
  • 0
jordan.    9

I was actually reading up on the .ready() function when I discovered that I could just move the css above the js.

To quote the .ready() page of the jQuery site that tipped me off:

When using scripts that rely on the value of CSS style properties, it's important to reference external stylesheets or embed style elements before referencing the scripts.

Is it still advisable that I also use the .ready any ways?

Share this post


Link to post
Share on other sites
  • 0
sweetsam    31

Yes. But you were using it already. Following pieces of code are equivalent. The problem was being caused by the fact that the styles were being applied after the script swung in to action. Scripts should always be the last to run and more importantly should be included after the stylesheets. Sometimes you will see scripts attached to the end of the document for the same reason.


$(function(){

})

and

$(document).ready(function(){

})

Share this post


Link to post
Share on other sites
  • 0
mattygdot    19

Out of curiosity... what about

text-align: center;

Share this post


Link to post
Share on other sites
  • 0
sweetsam    31

Out of curiosity... what about

text-align: center;

Read previous posts.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.