Skip to content

Instantly share code, notes, and snippets.

@tim-reynolds
Created June 29, 2012 18:16
Show Gist options
  • Star 35 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save tim-reynolds/3019761 to your computer and use it in GitHub Desktop.
Save tim-reynolds/3019761 to your computer and use it in GitHub Desktop.
Setting scroll to center on an element (jQuery) - Super simple stuff
/*
If you have a horizontal (or vertical) scroll container and want to set the scroll to center a specific
element in the container you can use the following super simple technique.
I'm going to show you how it was derived, because it's important to know why, not just how.
*/
/*
Setup:
[HTML]
<div class="outer">
<div>
<ul>
<li>Alpha</li><li>Beta</li>...<li>Omega</li>
</ul>
</div>
</div>
[CSS]
div.outer {
width: 400px; height: 100px; overflow-x: auto; overflow-y: hidden;
}
div.outer > div {
display: table;
}
ul {
display: table-row;
}
li {
display: table-cell; width: 120px; height: 120px; border: 2px solid gray;
}
*/
/*
With this setup, we should have a nice horizontally scrolling list of items of all the same width.
|--DIV.outer---------------------------------| { Hidden Elements }
||--DIV-and UL------------------------------|/....................................|
|||---LI---||---LI---||---LI---||---LI---||-//LI...||...LI...||...LI...||...LI...||
||| || || || || // || || || ||
||| || || || || // || || || ||
|||--------||--------||--------||--------||-//.....||........||........||........||
||------------------------------------------|/....................................|
|--------------------------------------------|
*/
/*
jQuery provides a function, scrollLeft (and scrollTop) that lets you read or set the scroll bar
position of an element at the pixel level. So, if we call $('.outer').scrollLeft() and it returns
zero (0) we know the scroll bar is all the way to the left.
If the scroll bar is all the way to the right the value of .scrollLeft() will be the width of the
inner element minus the width of the container. We will see how this fits in next.
*/
/*
If we call $('.outer').scrollLeft(($('.outer > div').width() - $)/ 2); it will set the scroll bar half
way.
Lets examine the following code:
*/
var outer = $j('.outer');
var inner = $j('.outer > div');
outer.scrollLeft( (inner.width() - outer.width()) / 2)
/*
This code will set the scroll bar to the center of the inner content.
But lets examine why. We know the minimum value for scrollLeft is zero, and the maximum
is inner.width() - outer.width(). So, half way is easily half the maximum. Simple! Now, this can
still fail. If your inner element has padding or a margin or border then the value of .width()
will be incorrect. You should use .outerWidth(true), which includes the border, padding
and (because we passed true) the margin.
*/
/*
So, how will we get it to center on an arbitrary element in the list. We use a very similar method
to the one above, except we also need the width of the target element.
First, we should setup some variables
*/
var target = $j('li.active'); //Lets assume one element has the class active, it is the one we want to center
var x = outer.width();
var y = target.outerWidth(true);
var z = target.index(); //Tells us what position this is in. Useful in calculations
var r = (x - y) / 2; /*Should be familiar. This is how many pixels the target needs to be to the right
to appear centered. From our CSS we know that x should be 300 and y 120.
So, r= 400-120 /2 = 140 */
var s = y * z; /*z is the index of the target. That means if z=3, there are 3 other elements preceding
our target (the first element is index zero (0) as with most indexing).
y is the width of our target, which from our CSS should be 120. This calculation lets
us know exactly how many pixels preceded our target. 3 * 120 = 360 pixels. */
var t = s - r;
outer.scrollLeft(Math.max(0, t)); /*Our target is now centered. */
/*
So, why does s - r center our target? We know that:
s = 360 -> The total number of pixels between the target's left edge and the left edge of it's container
r = 140 -> The total number of pixels we need to show to the left of the target to center it.
That means we need to hide s - r, or 360 - 140, or 220 pixels off the screen.
I hope this made sense to you. It really is super simple stuff, but good to have down somewhere.
*/
/*
This will of course only work if each element is the same width. If they are not the same the change is
very simple and is in the next file.
If I messed something up let me know on twitter @razialx
Tim Reynolds
*/
function centerItFixedWidth(target, outer){
var out = $(outer);
var tar = $(target);
var x = out.width();
var y = tar.outerWidth(true);
var z = tar.index();
out.scrollLeft(Math.max(0, (y * z) - (x - y)/2));
}
function centerItVariableWidth(target, outer){
var out = $(outer);
var tar = $(target);
var x = out.width();
var y = tar.outerWidth(true);
var z = tar.index();
var q = 0;
var m = out.find('li');
//Just need to add up the width of all the elements before our target.
for(var i = 0; i < z; i++){
q+= $(m[i]).outerWidth(true);
}
out.scrollLeft(Math.max(0, q - (x - y)/2));
}
@hew
Copy link

hew commented Jul 31, 2015

This was invaluable. Thanks.

@joaoalves89
Copy link

Amazing! Thanks

@quickfingers
Copy link

nice! why use Math.max(0, t)?

@dhhiep
Copy link

dhhiep commented Nov 23, 2020

Amazing !!! centerItVariableWidth it's saved my life <3 Thanks ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment