New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add iOS support to position:fixed sample code #167
Comments
matt, i'd be curious if you tried out this code: if it rectifies the iOS false positive. cheers |
Hi Paul, sorry for the delay. Just tested that code and it returns the same false positive on both iPhone and iPad :( |
Just a note that Marc Grabanski told me he spent 7 hours trying to solve this one without a successful resolution. :/ |
// Tested on iphone with IOS 5 beta and IOS 4
var IOS_FIXED_POSITION;
window.onload = function () { // Should be addEventListener etc...
if (typeof document.body.scrollIntoViewIfNeeded === 'function') {
(function () {
var container = document.body,
el = document.createElement('div'),
originalHeight = container.style.height,
originalScrollTop = window.pageYOffset;
testScrollTop = 20;
el.style.cssText = 'position:fixed;top:0px;height:10px;';
container.appendChild(el);
container.style.height="3000px";
window.addEventListener('scroll', testScrollTop, false);
window.setTimeout(testScroll, 20); // ios 4 does'n publish the scroll event on scrollto
window.scrollTo(0,testScrollTop );
function testScroll() {
if (IOS_FIXED_POSITION === undefined) {
el.scrollIntoViewIfNeeded();
if (window.pageYOffset === testScrollTop) {
IOS_FIXED_POSITION = true;
} else {
IOS_FIXED_POSITION = false;
}
}
window.removeEventListener('scroll', testScroll, false);
container.style.height=originalHeight;
container.removeChild(el);
window.scrollTo(0,originalScrollTop);
}
}());
} else {
IOS_FIXED_POSITION = false;
}
} |
Fixed it a bit, and used the original positionfixed test from the docs for regular browsers, it could be cleaned up a bit more, but it works. 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;
}); EDIT: Here's a gist of them both: https://gist.github.com/1221602 |
I did the timeout/eventlistener to test on Android devices for scrollIntoViewIfNeeded. If testScroll() is called right after scrollTo() and it works, the timeout and eventlistener is not needed. I will test this later. I don't have an Android available right now. I found out after publishing my code here, that we need to test further on Android devices with user-scalable set to "yes". My test returns true if the timeout is set to a higher number, but Android doesn't render posistion fixed on scalable viewports. |
Very good to know. My test on android was with user-scalable set to "no". |
Just tested on an IOS beta 5. The eventlistener is necessary for iPhone IOS5 to return true. Calling testScroll() directly will return false. |
It is also necesarry to do the test onload. |
torbs, is your code above final? we should start a pull request if so |
paulirish, this works for ios: var mno = {};
mno.features = (function () {
var features = {
positionFixed: function (callback) {
if (typeof fixed.vaule === 'undefined') {
fixed.callbacks.push(callback);
} else {
callback(fixed.value);
}
}
},
fixed = {
value:undefined,
callbacks:[]
};
function runFixedCallbacks() {
for (var i = 0; i < fixed.callbacks.length;i++) {
fixed.callbacks[i](fixed.value);
}
}
$(window).load(function () {
var test = document.createElement('div'),
control = test.cloneNode(false),
root = document.body,
oldCssText = root.style.cssText;
if (typeof root.scrollIntoViewIfNeeded === 'function') {
var testScrollTop = 42,
originalScrollTop = window.pageYOffset;
root.appendChild(test);
test.style.cssText = 'position:fixed;top:0px;height:10px;width:100%;background:#900';
root.style.height="3000px";
/* avoided hoisting for clarity */
var testScroll = function() {
window.removeEventListener('scroll', testScroll, false);
if (fixed.value === undefined) {
test.scrollIntoViewIfNeeded();
fixed.value = (window.pageYOffset === testScrollTop);
}
root.removeChild(test);
root.style.cssText = oldCssText;
window.scrollTo(0, originalScrollTop);
runFixedCallbacks();
};
window.addEventListener('scroll', testScrollTop, false);
window.scrollTo(0, testScrollTop);
window.setTimeout(testScroll, 15); // ios 4 doesn't publish the scroll event on scrollto
} else {
root.style.cssText = 'padding:0;margin:0';
test.style.cssText = 'position:fixed;top:42px';
root.appendChild(test);
root.appendChild(control);
fixed.value = test.offsetTop !== control.offsetTop;
root.removeChild(control);
root.removeChild(test);
root.style.cssText = oldCssText;
runFixedCallbacks();
}
});
return features;
}()); |
So this is part of jQuery 1.7. Cool. Is it worth programming Modernizr to detect jQuery and use the result from its tests (and vice versa) where they overlap and one is loaded before the other? Or is it faster to mess with the DOM twice over for this feature-detect than it would be to test for an existing result? |
the detect in jquery 1.7 gives a false positive for mobile webkit. |
BUMP! BUMP! ;) |
if anyone wants to try torb's latest code.. and test it against some ios/android/op mobile devices.. that'd be great. then we can bring it in. its all you, rob. :) |
I sort of half tested it, but achieved !victory. |
torbs code needs a small correction before one can test it, at line 5 it says 'vaule' instead of 'value':
After the correction I tested it on Chrome v16 and the iOS simulator (iOS v5.0 and v4.3), but unfortunately all returned a false value, while iOS v4.3 is the only non-supportive. |
So I ran in to a problem where it was ok for position: fixed not to work but if it did I made some layout calculations based on that. There was an issue with browsers that did not support position fixed as they would still effect the document layout rather than acting like a position fixed element. I was able to write a test that allowed me to see if a position fixed element was taken out of the document flow. I tested on: Mac chrome, FF, and safari, Windows IE, Blackberry Torch, Android 2.2.3 and iOS 5. I don't have easy access to an iOS4 device. Dunno if this helps anyone out or maybe I am being foolish but just thought i'd share: http://jsfiddle.net/s7TUs/4/ |
@RyanS: I tested your script on my Android 2.3.3 phone and iOS 4.3 and 5.0 simulator, all resulted in true values, while iOS 4 is not supporting position: fixed |
bummer. Thanks for the heads up |
While it worries me, this is actually something I'm currently sniffing the user agent for. It sucks, but it seems really tricky to come up with a true feature-detect for this. Is it possible to feature-detect for iOS via iOS-specific JavaScript features/values (to help guard against spoofed user agents) and then trust the user agent to be reporting the correct version? How about if we use 2 different tests that together have 100% coverage, and then just detect when it is appropriate to use one test instead of the other? |
The Filament Group published a sort of proof of concept for a similar problem, cross platform support of the CSS overflow property. The partially ua sniffing part of this script might be of any help, see http://filamentgroup.com/lab/overthrow/. |
You don't need two tests.. let me see if I can do a pull request... |
attention to people who want a pos:fixed test.. mr @grandecomplex has a draft ready in #539 but is stuck with some iOS4 scroll logic. could you take a look and see if we can get this squared away? |
If anyone's interested, I'm playing with an alternative method that works for ios 4, android 2.2, and desktop chrome. I haven't had time to test on ios 5 yet. |
@Kee-Yip iOS5 supports position fixed but your script appears to report ‘false’ ten times and then set givingUp to ‘true’. |
The pull request I proposed also works outside of Modernizr. In a nutshell, the problem is Modernizr doesn't like async (including timeouts) stuff. Do you think that your script can work without timeouts? |
I'll test it out some more, but sadly I think the scrolling/timeout is necessary. Android, for example, takes roughly 400ms to finish the detection. |
Thoughts on why this has died? Is it because of issue #539 ? |
Mr. Irish can touch on this more maybe. I think it died because Modernizr needs async testing ability similar to async tests in jQuery's qunit in order for position fixed to be tested. Happy new year! |
Am curious if people are using UA-sniffing for this, or are avoiding position:fixed in situations where you'd need some sort of code-branching because they're an "undetectable"? My (probably naive) takeaway was that in the proposed tests, the "hack" they were using needed to be patched up and became very specific to certain browsers, and then still reported false-positives/negatives. If a feature-detect is unreliable and would require a lot of maintenance as new browsers/devices come out, aren't you getting most of the same downsides of UA-sniffing anyway? http://caniuse.com/css-fixed - Appears the support is getting much better in the very latest mobile versions. And I think you could UA-sniff only to "blacklist" the categories of UA's that don't pretty easily using regex similar to how the filament group did as part of their solution. One line and you can knock out a whole group of them (e.g. iOS <= 5). That probably isn't in-line with Modernizr, but any feature detect just seems like it would have to be "overly-elegant" at best. |
@americanyak - the async stuff's being done "properly" in the big AMD re-rub (Modernizr v3.0) - see #622 and #713 - so I guess this is blocked by those. @ChrisWojcik - tbh there are a few Modernizr tests which give false positives/negatives; in some places, Modernizr covers these with UA sniffing itself. In this particular case, I gather the consensus is that @grandecomplex's test does the trick in all browsers(?) if run after a timeout - but Modernizr doesn't support that properly... yet. If I was desperate to use In the words of @aFarkas - "innovative frontend development is hacky and always will be hacky!" |
@stucox Thanks for the clarification. I was under the impression that the creator of Modernizr was against including UA sniffing into the library as a rule. (Only because feature-detection is intended to be the alternative). I thought I heard Paul Irish say that at some point, but I may just be misremembering. The issue I'm working on involves javascript and not just styles, but it's not the most complex thing ever. |
It's a last resort really, usually to filter out buggy implementations which can't otherwise be detected. |
Another reminder, because I keep forgetting myself, @grandecomplex has a pull request for this in #539, and are just waiting for an update to the code style before we finally close out this ancient bug :D |
Last week was Thanksgiving so it moved to my todos this week. I plan to On Sun, Dec 1, 2013 at 3:41 PM, patrick kettner notifications@github.comwrote:
|
Oh, sorry, that was a reminder for me, not for you. I keep on forgetting there is an open pull request, spend 10 minutes hacking on it, then remember to scroll up. |
@grandecomplex hows it goin? :] |
@grandecomplex hiya :D any luck? |
The sample code provided in the addTest() documentation for detecting support for position:fixed reports a false positive in Mobile Safari. (This browser correctly positions objects with that style applied, but does not keep them fixed in the viewport when the page scrolls.)
The text was updated successfully, but these errors were encountered: