Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Modernizr position fixed check
;(function(Modernizr, window) {
Modernizr.addTest('positionfixed', function () {
var test = document.createElement('div'),
control = test.cloneNode(false),
fake = false,
root = document.body || (function () {
fake = true;
return document.documentElement.appendChild(document.createElement('body'));
}());
var oldCssText = root.style.cssText;
root.style.cssText = 'padding:0;margin:0';
test.style.cssText = 'position:fixed;top:42px';
root.appendChild(test);
root.appendChild(control);
var ret = test.offsetTop !== control.offsetTop;
root.removeChild(test);
root.removeChild(control);
root.style.cssText = oldCssText;
if (fake) {
document.documentElement.removeChild(root);
}
return ret;
});
Modernizr.addTest('iospositionfixed', function () {
var test = document.createElement('div'),
ret,
fake = false,
root = document.body || (function () {
fake = true;
return document.documentElement.appendChild(document.createElement('body'));
}());
if (typeof document.body.scrollIntoViewIfNeeded === 'function') {
var oldCssText = root.style.cssText,
testScrollTop = 20,
originalScrollTop = window.pageYOffset;
root.appendChild(test);
test.style.cssText = 'position:fixed;top:0px;height:10px;';
root.style.height="3000px";
/* avoided hoisting for clarity */
var testScroll = function() {
if (ret === undefined) {
test.scrollIntoViewIfNeeded();
if (window.pageYOffset === testScrollTop) {
ret = true;
} else {
ret = false;
}
}
window.removeEventListener('scroll', testScroll, false);
}
window.addEventListener('scroll', testScrollTop, false);
window.setTimeout(testScroll, 20); // ios 4 does'nt publish the scroll event on scrollto
window.scrollTo(0, testScrollTop);
testScroll();
root.removeChild(test);
root.style.cssText = oldCssText;
window.scrollTo(0, originalScrollTop);
} else {
ret = Modernizr.positionfixed; // firefox and IE doesnt have document.body.scrollIntoViewIfNeeded, so we test with the original modernizr test
}
if (fake) {
document.documentElement.removeChild(root);
}
return ret;
});
})(Modernizr, window);
@creativeprogramming

This comment has been minimized.

Copy link

@creativeprogramming creativeprogramming commented Jul 21, 2013

Awesome!

@timohanninen

This comment has been minimized.

Copy link

@timohanninen timohanninen commented Jul 23, 2013

Looking great. I like the IOS position:fixed -check especially, great work.

One thing baffles me though:

You start the file with ";(function(Modernizr, window) {" - What's the semicolon's function in there? I am not yet very proficient with JS syntax.

May I use this in various commercial projects?

@jtangelder

This comment has been minimized.

Copy link

@jtangelder jtangelder commented Sep 5, 2013

Great, i modified it a bit to use it in a project. I just return false for Android 2 and iOS4, the support of these operating systems are fixed and will not change anymore. It makes the iospositionfixed plugin unnecessary.

;(function(Modernizr, window) {
    Modernizr.addTest('positionfixed', function () {
        var ret;

        // no (solid) support on <Android2 and <iOS4
        var ua = navigator.userAgent;
        if(ua.match(/android [0-2]/i) || ua.match(/(iphone|ipad|ipod).+(OS [0-4])/i)) {
          return false;
        }

        var test  = document.createElement('div'),
            control = test.cloneNode(false),
                fake = false,
                root = document.body || (function () {
                fake = true;
                return document.documentElement.appendChild(document.createElement('body'));
            }());

        var oldCssText = root.style.cssText;
        root.style.cssText = 'padding:0;margin:0';
        test.style.cssText = 'position:fixed;top:42px';
        root.appendChild(test);
        root.appendChild(control);

        ret = test.offsetTop !== control.offsetTop;

        root.removeChild(test);
        root.removeChild(control);
        root.style.cssText = oldCssText;

        if (fake) {
            document.documentElement.removeChild(root);
        }

        return ret;
    });
})(Modernizr, window);
@cbfranklin

This comment has been minimized.

Copy link

@cbfranklin cbfranklin commented Jan 10, 2015

@timohanninen As far as I know, the leading semi-colon is intended to make sure any JS statements in preceding scripts are properly ended.

@KrisJanssen

This comment has been minimized.

Copy link

@KrisJanssen KrisJanssen commented Apr 2, 2017

@bobslaede, @timohanninen, @jtangelder

Recently, I have been seeing an issue on OSX and iOS as described here.

In short, on Safari 10.1.1 (12603.2.1) a style="height: 3000px; is being added to the <body> tag whereas this is not the case on e.g. Safari 10.0.1 (12602.2.14.0.7) or 10.0.3

Could it be some sites might be using the code in this Gist but that it might be causing issues on newer versions of Safari?

The site I am seeing issues with seems to implement the code from this Gist:

http://onlinelibrary.wiley.com/enhanced/static/common/js/vendor/modernizr.custom.js

@WebStew

This comment has been minimized.

Copy link

@WebStew WebStew commented Apr 12, 2017

@KrisJanssen - Thank you for logging this. I have just debugged our app on Online Library and tracked it down to this piece of code. It looks as though the iospositionfixed test is creating a duplicate body element with the 3000px height which is why we are seeing a big blank space before the actual content - we are currently patching.

@WebStew

This comment has been minimized.

Copy link

@WebStew WebStew commented Apr 24, 2017

Hi @jtangelder.

It's worth noting that it looks as though with the recent release of OS 10 the UA string will match the regex ua.match(/(iphone|ipad|ipod).+(OS [0-4])/i) eg iPhone OS 10_3_1

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