Support centering an element when scrolling into view
w3c issue: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152 Original code from http://jsbin.com/ilecok/16/
////////////////////////////////////////////////////////////////////////////////
// Author: Thaddee Tyl 2012.
// The following work is under CC0.
void function() {
// Hook the polyfill.
Element.prototype._scrollIntoView = function scrollIntoView(options) {
if( !this.ownerDocument )return;
var _window = this.ownerDocument.defaultView;
// Traditional scrollIntoView.
if( !arguments.length || typeof options != "object" ) {
return this.scrollIntoView.apply(this, arguments);
}
// Fetch positional information.
//
// The following are always from the {top, bottom, left, right}
// of the viewport, to the {top, …} of the box.
// Think of them as geometrical vectors, it helps.
// The axes are directed downwards and towards the right.
var rect = this.getBoundingClientRect(),
topToBottom = rect.bottom,
bottomToTop = rect.top - _window.innerHeight,
leftToRight = rect.right,
rightToLeft = rect.left - _window.innerWidth,
xAllowed = true, // We allow one translation on the x axis,
yAllowed = true; // and one on the y axis.
// Read options.
//
// We have the following options:
// - float vertical = 0.5 (from 0 to 1).
// - float horizontal = 0.0 (from 0 to 1).
// - boolean notIfViewed = true
if (options.vertical === undefined) options.vertical = 0.5;
if (options.horizontal === undefined) options.horizontal = 0.5;
if (options.evenIfViewed === undefined) options.evenIfViewed = false;
// Whatever `horizontal` and `vertical` are,
// the behavior is the same if the box is (even partially) visible.
if (topToBottom > 0 && topToBottom <= this.offsetHeight) {
if (yAllowed) {
_window.scrollBy(0, topToBottom - this.offsetHeight);
yAllowed = false;
}
}
else if (bottomToTop < 0 && bottomToTop >= -this.offsetHeight) {
if (yAllowed) {
_window.scrollBy(0, bottomToTop + this.offsetHeight);
yAllowed = false;
}
}
if (leftToRight > 0 && leftToRight <= this.offsetWidth) {
if (xAllowed) {
_window.scrollBy(leftToRight - this.offsetWidth, 0);
xAllowed = false;
}
}
else if (rightToLeft < 0 && rightToLeft >= -this.offsetWidth) {
if (xAllowed) {
_window.scrollBy(rightToLeft + this.offsetWidth, 0);
xAllowed = false;
}
}
// If we want it positioned in the viewport,
// and the box is completely hidden,
// then we position it explicitly.
if( yAllowed
&& (options.evenIfViewed ? true : (topToBottom <= 0 || bottomToTop >= 0))
) {
_window.scroll(
_window.scrollX
, _window.scrollY + rect.top - (_window.innerHeight - this.offsetHeight) * options.vertical
);
}
if( xAllowed
&& (options.evenIfViewed ? true : (leftToRight <= 0 || rightToLeft <= 0))
) {
_window.scroll(
_window.scrollX + rect.left - (_window.innerWidth - this.offsetWidth) * options.horizontal
, _window.scrollY
);
}
if (_window.parent !== _window) {
// We are inside a scrollable element.
var frame = _window.frameElement;
scrollIntoView.call(frame, options);
}
};
}.call(this);