Simple Vertical Align Plugin for jQuery

Everything in it's right place.
Sometimes you may want to vertically align a block item, but the CSS-only vertical aligning methods don’t make you feel clean.  Personally, I hate having to style items as a table/table cell to get them to vertically align in Internet Explorer.

jQuery to the rescue.  Using a jQuery vertical align snippet as my base code, I modified it to be a jQuery plugin that will allow you to use the function in the jQuery chain.

jQuery Vertical Align Plugin Code

Simply copy this code into your website (if you don’t know where, leave a comment):

(function ($) {
// VERTICALLY ALIGN FUNCTION
$.fn.vAlign = function() {
	return this.each(function(i){
	var ah = $(this).height();
	var ph = $(this).parent().height();
	var mh = Math.ceil((ph-ah) / 2);
	$(this).css('margin-top', mh);
	});
};
})(jQuery);

Now, you can use vAlign as you wish; ie: $('#example p').vAlign();.

Did this make your life easier? Was this information worth a buck?
Donate with PayPal (Much appreciated!)

If it’s not working

If it’s not working, it may be because the script applies a margin to the element, which may not work in all situations. Try changing 'margin-top' to 'padding-top' and see if that helps.

Any questions or comments?

  • http://www.webago.co.uk Webago

    Very usefull love it keep up the good work.

  • Jonas

    Does it work on multiple instances? So far, I can only get it to vAlign on the first named element.

    Thanks.

  • http://www.seodenver.com Zack Katz

    @Jonas – I’ve not had any issues with multiple instances. You may want to try the .each() function and see if that helps.

  • Jonas

    Thanks Zack. I have a sillier question: do you know if there is any way to get it to work if the html section it is applied to is hidden by default on page load and only visible if the user makes it so?

  • Jonas

    Nevermind. I’ll just fire the .each() for the show and hide. Thanks again.

  • http://www.mantratechnology.com Ryan

    Thanks for the code! The code however doesn’t run for each element in the selector. I updated it to fix this issues, here it is:

    return this.each(function() {
    var ah = $(this).height();
    var ph = $(this).parent().height();
    var mh = (ph – ah) / 2;
    $(this).css(‘margin-top’, mh);
    });

  • http://www.seodenver.com Zack Katz

    Hey Ryan,
    Sorry about that – I thought it was working properly. I’ve updated the code in the article. Thanks!

  • Marcel

    Hi,
    could you please be so kind to explain me where and how to code / copy-paste this into a working function? I’m totally blind about jQuery (my bad)

  • Marcel

    nevermind me asking :) got it figured out :)

  • http://trif3cta.com/blog Judd

    Nice little plugin sir, thanks.

    First I stumbled upon the SEO stylesheet, now this? Keep it up, you’re on fire!

  • http://www.seodenver.com Zack Katz

    @Judd – glad you’ve found them helpful.

  • http://www.konspiredesign.com Vasily

    Hey, this is great, successfully tested in IE6, Chrome, Opera, Safari, however it surprisingly does not work in Firefox 2 (I’ve got 2.0.0.19). Any ideas how to make it work in FF2?

  • Jonas

    Hi! Great! Do you know how to center a div in the browser window?

  • http://www.seodenver.com Zack Katz

    @Jonas – That’s done with CSS. The container div should be text-align:center, and the centered div should be margin:0 auto;

  • Pingback: Vertical centering

  • Alexandru Dinulescu

    THANK YOU!!!!!!!!!!!!!!!!!!!!!!!!!! THANK YOU THANK YOU, YOU Just saved me another 3 hours or trying to make a classic Jquery method to work with each function. (I’m kinda clueless to javascript in general, still learning the basics).

    Thanks again

  • http://www.seodenver.com Zack Katz

    @Alexandru – Glad I could help :-)

  • Alexandru Dinulescu

    Anther quick question

    If i set it to the container div will it work?
    (trying to make a new website and i have to make it vertically aligned to the top and bottom sides) so i am wondering does it work by calculating the window height or I have to make another div (and not set everything to it) and slap my container inside said div.

    Thanks :)

  • http://www.stephanpaquet.com Stephan

    wow ! awesome. Just tried with an image and works very well. I added a bind on resize window to replace the image on resize

    $(window).bind(‘resize’, function() {
    $(‘#content img’).vAlign();
    });

    Thanks for your code

  • ajay mishra

    Hey Zack:

    Thanks for doing this plugin as a social service:)

    Unfortunately, I am a technical idiot.. and dont know – where to exactly copy and paste this code of yours :) -> as you guessed ..

    So -> for the technical idiots like me -> would you kindly spill some ink ? and let me know wher to copy and paste : in other words: copy and paste too -> is an art -> you have to know what to copy, where to copy and how much to copy

    and yes.. I dont even know THAT MUCH

    thanks
    ajay mishra
    ceo nomolisa.com

    • Joshua

      Yes, I know this guy, and he’s not kidding about being a technical idiot!  :-)

  • http://www.notion3.com Jesse – Denver Website Design

    Nice clean code there, great article again Zack!

  • Jaap

    I added a way to reposition the stuff when the window is resized.

    (I used this for a full screen document with one div that always should be centered).

    I’m not a jquery king, so I hope it’s all good;

    $(document).ready(function(){
    $(“.content”).vAlign();
    });

    $(window).bind(‘resize’, function(){
    $(“.content”).vAlign();
    });

  • http://herkimermedia.com Steve

    BRILLIANT.
    The IE demon won’t eat THIS afternoon.

  • Medium

    Hi! I seem to be having some trouble with elements that need to be hidden at start. For example if i want to use it as a title that will appear when i hover over an image. It doesnt seem to get “ah” since the element is hidden.

    Ah .. i figured out a solution while i was writing this. I used opacity:0 and opacity:1 as hover. The elemnt is there and its height can be read. But its a side road, any better solutions?

  • Pingback: The Pain of Vertical Alignments with CSS « Ph@ntoM

  • http://www.ericlightbody.com Eric Lightbody

    Thanks for the excellent post. The vertical align function has already helped me out tremendously!

  • Arjan

    We had some discussion on Stack Overflow about issues when (probably) some external CSS was not yet loaded. When not yet loaded then the value for “$(this).height()” may yield zero, or some value that does not match the actual height. Placing the code to load your CSS before the code to load jQuery may help, though things seem to be more complex than I would have imagined. Anyway, see http://stackoverflow.com/questions/1324568/is-document-ready-also-css-ready/

  • Keith

    If you want the item to be vertically aligned to the window (i.e the parent of the element you want to align vertically is BODY), then change:

    $(this).parent().height();
    to
    $(window).height();

    Thats all! (Note that this will make the code only work in this instance though)

  • http://www.materieldepiscine.com Youssef

    Hi Zack,

    I have a problem with my website wich is still in developpement, I’m trying to understand all the basis, the problem is that all my subcatergories are not aligned (click on “piscines” to access the differents subcategories, so you will see that the images are aligned but not the titles. Will your tips work?

    thanks for you help
    Youssef

    • http://www.seodenver.com Zack Katz

      It should, yep. I believe you’ll want to use the following code: $("div.ProductImage img").vAlign();

  • http://www.psdgator.com papaman

    nice function mate.

    I changed my code from:

    $(this).css(‘margin-top’, mh); to
    $(this).css(‘padding-top’, mh);

    because I was having some problems with a UL list. My html code is:

    Blah Blah Blah

    and I use $(“.valign”).vAlign(); on the

  • http://voidstone.com exeQutor

    Nice plugin. Really saved me a lot of trouble.
    I found one similar, although probably a copy/an enhancement based from yours:
    http://cool-javascripts.com/jquery/vertical-alignment-of-contents-inside-an-element-using-jquery.html

  • http://raventools.com Raven Matt

    I am having problems with multiple instances and I’m not that great with jquery. The first element positions but the rest don’t unless I refresh the browser.
    Is where the .each ( ) function would come into play? If so where would it be placed in the code?

  • Rafa Librenz

    Oh my god, this code is delicious!! :-D

    But… I changed it.

    if (mh < 0) {
    	$(this).css('margin-top', mh);
    };
    
    • http://www.katzwebservices.com Zack Katz

      That makes sense. You could also do if(mh != 0)

  • Rogerio Girodo Marques

    This work, but maybe you have the margin collapse issue. If this is the case. Put this line before the margin-top line.
     
    $(this).parent().css(‘padding-top’, ’1px’);

  • Stefan

    thanks. I’m so glad somebody invented this. I went through numerous plugins, but this is the simplest and most solid one. thumbs up!

  • http://phillapier.com Phil

    This is some beautiful code. Very much what I was looking for. Thanks Zack.

  • Jordi

    maybe it would be better to use
    var ah = $(this).outerHeight();

  • Harry Wong

    I wanted to try it and have not figured out how to add this function to my website. Please advice. Sorry about the ignorance.

    • http://www.katzwebservices.com Zack Katz

      @Harry Wong: This code uses the jQuery javascript library. I recommend reading this article: Getting Started with jQuery for an introduction to the world of simple and powerful javascript coding!

  • david

    the code as is, has javaScript errors in it, on the return this.each… line.
    using firefox 3.6.6

  • Matt

    I’m getting a syntax error using jquery 1.4.2 using the code as shown beginning at the line ‘return this.each(function(i)’

    Is this code compatible with 1.4.2?

    • http://www.katzwebservices.com Zack Katz

      @Matt and @David – The code was broken because I have been testing a new version of my WordSpinner plugin…Sorry about that!

      I’ve fixed the issue, and the code is diplaying properly and will work again.

  • http://www.marioaguiar.com Mario

    Thanks man, just what I was looking for, but It’s not working on Chrome, what could that be?

  • http://www.easy-solar-quote.co.uk Solar PV

    The link titled “jQuery vertical align snippet” in the article seems to be broken.

    For this to work do we just need to include JQuery, then include that function and a calll to it? Are there any other base libraries to include also – is that what the link was for?

    Cheers

  • Tufan

    The code is really perfect and it is working smoothly. I just want to know how we can adjust it if I want to vertical-align to the bottom, not the center?

    • http://www.seodenver.com Zack Katz

      I would do CSS for that: make the container position:relative; and the item position:absolute;

  • Ondrej

    Snippet does not work for me in Safari 5.0.2. IE, Firefox, Chrome successfully tested. Any ideas? Thanks.

  • Nate

    Nice.

  • Max

    very usefull

  • http://twitter.com/tnypxl Arik Jones

    Facken awesome! Thanks!

  • http://jonathanlahijani.com/ Jonathan Lahijani

    I added a few tweaks to the code based off of the comments as well as some things I noticed to fix negative margin issues if the browser height is less than the height of the container div. Here is the final result:

    (function ($) {
    // VERTICALLY ALIGN FUNCTION
    $.fn.vAlign = function() {
    return this.each(function(i){
    var ah = $(this).height();
    var ph = $(window).height();
    var mh = (ph – ah) / 2;
    if(mh>0) {
    $(this).css(‘margin-top’, mh);
    } else {
    $(this).css(‘margin-top’, 0);
    }
    });
    };
    })(jQuery);

    Also, I’m using the following to call the function that takes care of both when the page is loaded or the browser is resized:

    $(document).ready(function(){
    $(“#container”).vAlign();
    });
    $(window).bind(‘resize’, function(){
    $(“#container”).vAlign();
    });

    This code is geared for a container div that’s a direct child of the body that needs be to vertically centered in the body.

    – Jonathan Lahijani

  • S K

    Hi there. I found your code useful as a start base, but there is a little problem with it.

    This line:
    var mh = (ph – ah) / 2;
    Should actually be like this:
    Math.ceil((ph-ah) / 2);

    This is because margins/padding, when using pixels, has to be an integer number.

    Then I could argue about using margin-top exclusively. There are time where paddings (top/bottom) should be used instead.

    • http://www.seodenver.com Zack Katz

      Thanks SK; I’ve updated the code snippet with your changes.

  • http://www.facebook.com/davetcoleman Dave Coleman

    Awesome, thanks!

    • A1

      its ok

  • ectype

    This is a great plugin. Thank you! 

    However if you’re centering inline images be sure to have the height and width specified in the tag otherwise it will force the browser to redraw the margins in weird ways each time you refresh the page.

  • Neeraj Bharti

    its not working properly in chrome!!

  • Bobbbby R

    Hi, this not work in chrome :(((

    • http://www.seodenver.com Zack Katz

      It should…could you please link to the page where it doesn’t work?

      Also, try replacing margin-top with padding-top and it might work.

  • Ton Santos

    Thanks man! Works like a charm :)

    I found that if there is an element positioned absolutely inside the wrapper div, you have to change the ‘margin-top’ to ‘padding-top’ (just on IE) .

    So if you have the follow code: 

    $(‘#content’).vAlign();

    Lorem ipsum

    The ‘content’ div goes to the top of the window on ie. To fix it you may use:
    $(this).css(‘padding-top’, mh); 

    instead of:

    $(this).css(‘margin-top’, mh);

    Then it works very well.

    Thanks again for this simple but powerful jquery script.

  • Ronal Sanchez

    Great script! Thank you very much

    For anyone having issues with Chrome replace:

    $(document).ready

    with

    $(window).load

    • http://www.seodenver.com Zack Katz

      The $(document).ready code is the correct way to do things in jQuery. If you need to change this part, it’s likely not the real problem.

  • http://twitter.com/Dean_IconWeb Dean Peterson

    Very helpful script.  But has been mentioned, it only works on elements that have been rendered.  Here is one solution for vertically aligning images that are loaded into the DOM and then when all elements are aligned fire the callback plugin/function.

        $(document).ready(function(){        createPanels();        var $img = $(“img.product_image”),            count = $img.length,            statusCount = 0;        //wait for images to load and aligned before firing tab script        $img.load(function(){            var $this = $(this);            statusCount = statusCount + 1;            $(this).vAlign();            if(statusCount >= count) {                $(“#fpWrap”).idTabs();            }        });    });

  • http://www.thebeautyofknowledge.com/body-surgery-atlanta/liposuction/ liposuction in Atlanta

    It is right that for the success for your blog just create interest for the readers and they will take interest in your product. If your readers get knowledge from your blog, they will introduce your blog in their community.

  • http://peterfodormd.com/2011/01/04/facelift-procedure face lift Los Angeles

    Excellent goods from you, man. I have take note your stuff previous to and you’re just extremely great. I really like what you’ve got here, really like what you are stating and the way in which wherein you are saying it. You make it entertaining and you still care for to stay it smart. I cant wait to learn much more from you. This is actually a tremendous site.

  • bradDI

    Any Ideas about the Chrome issue?  Its working great for me in IE and FireFox, but not in Chrome.  The url of the problem page is: http://legendstaxidermy.com/africangallery.aspx

    Any ideas are greatly appreciated!

  • http://www.firerescue1.com/fire-products/firefighting-gear/ Fire Gear

    whoah this blog is excellent i love studying your posts. Keep up the good paintings! You know, lots of people are hunting round for this information, you can aid them greatly.

  • http://twitter.com/esqew Sean Quinn

    I have plugin-ified this on my GitHub: https://github.com/esqew/jQueryVerticalCenter/

    You can now utilize it as you would any jQuery plugin!

  • David

    Is better with outerHeight().
    This include the padding.

  • Jim5358

    Hi! VERY helpful post, thank you! I have to plead ignorance… I’m not sure where to paste in the code, or how to insert the jQuery in Dreamweaver…!! Sorry to be a pain!

  • Joshua

    Hi,

    mine was giving me no data back for the element I needed the hight from (the outer container of my website), tho, I new what the height was and I changed it to this script:

    (function ($) {
    // VERTICALLY ALIGN FUNCTION
    $.fn.vAlign = function() {
        return this.each(function(i){
           
            var ah = 660;
            var ph = $(window).height();
           
            if(ph > ah) {
                var mh = Math.ceil((ph-ah) / 2);
           
                $(this).css(‘margin-top’, mh);
                $(‘body’).css(‘background-position’, ’0px ‘+mh+’px’);
            }
        });
    };
    })(jQuery);

    In the footer of my webpage I used this script:

        $(document).ready(function() {
            $(‘#wrapper’).vAlign();
            $(window).resize(function() {
                $(‘#wrapper’).vAlign();
            });
        });

    My website is being vertically centered and is being replaced if you decide to change the size of your browser screen! In my case the ’660′ indicates a 660px high website. I added another check (if ph > ah) because otherwise there is the possibility a negative margin is added and thus some text will apear outsite its container.

    Hope this might be of any use. I’ve got absolutely no clue why $(this).height() returned 0 pixels, so there’s a good chance it works for anyone else when using $(this).height() instead of a fixed number!

    Joshua

    • Joshua

      Oh right, before I forget :-) for this specific website the background continued inside the website. Therefor I needed the background to be replaced as well, which explains the line changing the background-position property for the body!

  • Lunalady22

    Hi there – this code is awesome, however it has stopped my image being horizontally center aligned. Previously the image was center aligned by using CSS #div { text-align:center } but after adding in the jquery it is left aligned – thanks in advance for any help!

    • Lunalady22

      #div {text-align: center;}

      • Lunalady22

        ignore me! it works!  THANK YOU!!!!!

  • Eerk

    It does not work in Safari… any ideeas? Seem to be something wrong in the calculation. My images are not centered..

  • Chris

    Nice work ! Worked perfectly.

  • Mauryas

    doesn’t work with chrome, because the way chrome, ie and ff deal with image loads is different. chrome run the code BEFORE the image finishes its load, though, the height, at the moment the reading, is 0, and the code shoudn’t work properly. therefore, it could be used the load() event on the image. but.. the ie doesn’t trigger when the image is loaded.. it DOES LOAD before the code, but it doesn’t like to share it with the world.. so, I created a version of the code, which works with ie, ff AND chrome. it’s based on the assumption that, if the browser loads the image before the code (and, in consequence, has a value for image height() ), it’s because it cares about prevention on dealing with images, so, the load() is unnecessary. if it runs the code BEFORE the load of the image, it should get prepared to respond about when the image load accurs (and, then, the image load() event will trigger). but, as always, there must be a browser who run codes which deal with image without worring with the problems with loading (it means, any time, probably before the image load), AT THE SAME TIME it doesn’t like to report about the load() event. so, it’s not universal.. but, working with ie, chrome AND ff, its kind of.. ps.: paste this code into your js file, and use the class vertical-align-middle in any object you want to vertical-align to middle. ;)

    $(function() {
    $(‘.vertical-align-middle’).each(function() {
    if($(this).height() == 0){
    $(this).load(function(){
    var ah = $(this).height();
    var ph = $(this).parent().height();
    var mh = Math.ceil((ph-ah) / 2);
    $(this).css(‘margin-top’, mh);
    });
    }else{
    var ah = $(this).height();
    var ph = $(this).parent().height();
    var mh = Math.ceil((ph-ah) / 2);
    $(this).css(‘margin-top’, mh);
    }
    });
    });

  • Mauryas

    additionally, I paste this other code, which lies on the fact that the css vertical-align DO work. but only in respect to text (or, more specificaly, the line of the text). to avoid undesired effects on the container of the element you want to vertical-aligning with, related to other textual content that the container can have, it’s appended to this container a span wrap, and, appended to this wrap, the content you have applied the verticalAlignMiddle class in the first place. it aplies on the wrap span the line-height of the original container, and aply on the element you are vertical-aligning the vertical-align: middle configuration. it’s all you need to have a element vertically aligned, without worrying with browser incompatibilities.

    • Mauryas

      $(function() {
      $(“.verticalAlignMiddle”).each(function() {
      var spanContainer = $(“”);
      $(this).parent().append(spanContainer);
      spanContainer.css(“line-height”, $(this).parent().height() + “px”);
      spanContainer.append($(this));
      $(this).css(“vertical-align”, “middle”);
      });
      });

  • Mauryas

    there is this 3rd way to vertically align elements, which is pure css. it’s ugly, but it works.

    you write, in the HTML:

    in CSS:

    .verticalAlignMyGrandchild{ //A FIRST WRAP (USE IT IN A SPAN)
    position: relative;
    display: block;
    top: 50%;
    margin-top: -100px;
    height: 200px;
    text-align: center;
    line-height: 200px;
    }

    .verticalAlignMyGrandchild span{ //A SECOND WRAP (SPAN)
    line-height: 0;
    }

    .grandChildVerticalAligned{ //USE IT IN THE ELEMENT YOU WANT, IN FACT, VERTICAL-ALIGN
    vertical-align: middle;
    }

    AND, it’s done. ;)

    ps.: to horizontal align, the text-align: center, in any of the containers, should work.

    • Mauryas

      well, what a beatiful thing.. the page erased part of my code.. well, here it is (again!):

    • Mauryas

      AND.. it deleted again.. well.. I will not write it again.. you just put inside the container a span (class=”verticalAlignMyGrandchild”), inside you put other span (no need to classified this, the css selector do the job), and, INSIDE it all, you put what you really want to vertical align (class=”grandChildVerticalAligned”). hope this time it works..

  • Francisco

    Nice code. Its very useful. What about using position relative instead of margin?
    Example:

    $(this).css(‘position’, ‘relative’).css(‘top’, mh);

    With position relative you dont have the problem of margins or paddings.

  • Chris Hough

    Thank you for creating this, I appreciate it.

  • http://www.seodenver.com Zack Katz

    In this example, you would be vertical aligning something with the id “content”. That would look something like this:
    <div id="content">
    <p>This is content that will be centered.</p>
    </div>

    The code below should be placed under the <head> tag and above the </head> tag. It will only work if you’re using jQuery and it’s been installed properly.
    <script type="text/javascript">
    // Plugin code goes here
    $(document).ready(function(){
    $("#content").vAlign();
    });
    </script>

  • http://www.seodenver.com Zack Katz

    You may want to use position:absolute; left:-999em; as the “hidden” state; opacity does not have full browser ::cough:: IE ::cough:: support.

    Then on the hover, use position:relative; and whatever other stuff you’re doing in there :-)

  • Medium

    Hmmm yes it would probably be better with hidden positioning, ill give it a try, thanks!

    (regarding IE i used filter:alpha(opacity=0) so its cross-browser but i hate using such “hacks”)