Categories
Code jQuery

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?

By Zack Katz

Zack Katz is the founder of GravityKit and TrustedLogin. He lives in Leverett, Massachusetts with his wife Juniper.

94 replies on “Simple Vertical Align Plugin for jQuery”

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?

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);
});

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)

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?

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

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 🙂

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

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

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();
});

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?

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/

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)

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

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

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?

Oh my god, this code is delicious!! 😀

But… I changed it.

if (mh < 0) {
	$(this).css('margin-top', mh);
};

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’);

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

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

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

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?

@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.

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

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?

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

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

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.

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.

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.

Great script! Thank you very much

For anyone having issues with Chrome replace:

$(document).ready

with

$(window).load

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();            }        });    });

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.

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.

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.

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!

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

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!

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!

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

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);
}
});
});

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.

$(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”);
});
});

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.

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..

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.

Comments are closed.