I'm trying to detect for devices that do not have support for position:fixed. EDIT: I've fixed the code so it's detecting features rather than browser/OS detection.
I think I was confusing people when I first typed this out. My issue is coming into play when I refresh the page. The height is being incorrectly calculated, which is a completely different issue I know, but am looking for assistance nonetheless.
Updated detection script below:
function fixed() {
var container = document.body;
if (document.createElement && container && container.appendChild && container.removeChild) {
var el = document.createElement('div');
if (!el.getBoundingClientRect) return null;
el.innerHTML = 'x';
el.style.cssText = 'position:fixed;top:100px;';
container.appendChild(el);
var originalHeight = container.style.height,
originalScrollTop = container.scrollTop;
container.style.height = '3000px';
container.scrollTop = 500;
var elementTop = el.getBoundingClientRect().top;
container.style.height = originalHeight;
var isSupported = (elementTop === 100);
container.removeChild(el);
container.scrollTop = originalScrollTop;
return isSupported;
}
return null;
}
//TEST FOR MOBILE, SET TOP IMAGE TO RELATIVE
if(fixed()) {
image_height = jQuery("#outer_homepage_image").height() - 45;
jQuery("#content").css("top",image_height);
jQuery(window).resize(function() {
image_height = jQuery("#outer_homepage_image").height() - 45;
alert(image_height);
jQuery("#content").css("top",image_height);
});
} else {
jQuery("#outer_homepage_image").css("position","relative");
}
This is an extremely brittle and ill-conceived thing to be doing.
if(/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
For example, iOS has fully supported position:fixed properly since iOS 4. We're now on 6. For Android & Blackberry, I'm not sure but would err on the side of "supported".
You need to test for features, not user agent. As I said, you could have one iOS device that doesn't support it and another one that does. Indeed, most do these days.
Here's a helpful link to lead you to moral, godly choices: http://kangax.github.com/cft/#IS_POSITION_FIXED_SUPPORTED
Thanks for all the support guys. I solved it with jQuery(window).load(function() {
it works now because everything else is loaded so I can calculate the proper height.
Related
In messing around with some DeviceOrientation stuff, I came across this page.
When you shake the browser, the site reacts! What API is being used here where the browser movement is detected? I notice it works in the latest versions of Safari, Firefox and Chrome.
I don't see any mention of this in the DeviceOrientation docs, nor on three.js...
They use the window.screenX/screenY properties to get browser window position and window.innerWidth/innerHeight to get window's size.
The Window.screenX read-only property returns the horizontal distance, in CSS pixels, of the left border of the user's browser viewport to the left side of the screen.
The below function is used in that code:
function getBrowserDimensions() {
var changed = false;
if (stage[0] != window.screenX) {
delta[0] = (window.screenX - stage[0]) * 50;
stage[0] = window.screenX;
changed = true;
}
if (stage[1] != window.screenY) {
delta[1] = (window.screenY - stage[1]) * 50;
stage[1] = window.screenY;
changed = true;
}
if (stage[2] != window.innerWidth) {
stage[2] = window.innerWidth;
changed = true;
}
if (stage[3] != window.innerHeight) {
stage[3] = window.innerHeight;
changed = true;
}
return changed;
}
use screen.orientation property.
reference
Here's what StackOverflow looks like on my (huge) work monitor:
That is a lot of white space on either side of the site's actual content.
I get that this is how a very large percentage of websites are designed—so I'm not singling out SO here—but that's actually exactly why I'm asking this question. I'm thinking it'd be really nice if I had some reliable way (say, via JavaScript) of determining the "actual" width of a website, which I could then use to write a quick script that would auto expand any site I'm browsing to fill the available width on my monitor. As it is, I find it absurd that sometimes I still squint before reading tiny text before realizing/remembering to zoom in to take advantage of my enormous screen.
Ahh... much better.
I suspect this is possible, at least to a reasonable degree via some heuristic, as my Android phone appears to do something a lot like this when I double-tap on the screen while browsing the web.
This will do something sorta like that. Though probably misses all kinds of edge cases.
// Assuming jQuery for simplicity
var drillIn = function(node) {
var max = 0;
var windowWidth = $(window).width();
var result = 0;
$(node).children().each(function() {
var $this = $(this);
if ($this.width() > max) {
max = $this.width();
}
});
if (0 < max && max < windowWidth) {
return max;
} else {
$(node).children().each(function() {
var childMax = drillIn(this);
if (childMax > result) {
result = childMax;
}
});
return result;
}
};
drillIn(document.body);
Working Fiddle: http://jsfiddle.net/bdL5b/1/
On SO, I get 960 which is right. Basically it drills into the DOM tree to find the widest node closest to the root which is not 0 or the window width. Because usually, close to the root node there is a container node which holds the site content. Usually.
Not sure you will get a 100% reliable solution though. This is a tricky thing because there are a TON of ways to style websites. I bet crazy stuff like horrible use of absolute positioning could be a serious thorn in your ass.
If you use Firefox, Greasemonkey is awesome. It will run Javascript that you write on any page (I have used it on Stack Overflow's site before).
Just use the browser's built-in "inspect element," to get the id of whatever you want to expand and do this:
document.getElementById("content").style.width = "100%"; // content is just an example
I think the class name of the middle boxes is .container so you could do this:
var boxes = document.getElementsByClassName("container");
for(var i = 0; i < boxes.length; i++)
{
boxes[i].style.width = "100%";
}
As far as a heuristic for doing this arbitrarily, there's probably no good way to do it to all web pages in an unbiased way, without significantly messing up the site's appearance.
That being said, this or something similar might work ok:
var divs = document.getElementsByTagName("div");
for(var i = 0; i < divs.length; i++)
{
divs[i].style.minWidth = "90%";
}
Ha! I've got something close (though I'm also going to try Alex's approach):
The following relies on jQuery and is arguably inefficient (it inspects, I believe, every element in the DOM); but it doesn't take any time on my machine and at least works with SO:
(function($) {
function text($element) {
return $.trim($element.clone().children().remove().end().text());
}
function hasContent($element) {
return $element.is(":visible") && text($element).length > 0;
}
function getExtremeEdges($elements) {
var extremeLeft = null;
var extremeRight = null;
$.each($elements, function(i, el) {
var $element = $(el);
var offset = $element.offset();
if (!extremeLeft || offset.left < extremeLeft) {
extremeLeft = offset.left;
}
if (!extremeRight || (offset.left + $element.width()) > extremeRight) {
extremeRight = offset.left + $element.width();
}
});
return [extremeLeft, extremeRight];
}
var $elementsWithContent = $("*").filter(function(i, el) {
return hasContent($(el));
});
var extremeEdges = getExtremeEdges($elementsWithContent);
var width = extremeEdges[1] - extremeEdges[0];
var desiredWidth = $(document).width() * 0.95;
if (width < desiredWidth) {
$("body").css("zoom", (desiredWidth / width));
}
}(jQuery));
Minified (to use as a bookmarklet):
(function(a){function b(b){return a.trim(b.clone().children().remove().end().text())}function c(a){return a.is(":visible")&&b(a).length>0}function d(b){var c=null;var d=null;a.each(b,function(b,e){var f=a(e);var g=f.offset();if(!c||g.left<c){c=g.left}if(!d||g.left+f.width()>d){d=g.left+f.width()}});return[c,d]}var e=a("*").filter(function(b,d){return c(a(d))});var f=d(e);var g=f[1]-f[0];var h=a(document).width()*.95;if(g<h){a("body").css("zoom",h/g)}})(jQuery);
Time to dogfood this puppy for a while...
I think each website will be too different to have a standard was of auto resizing their content. I belive CSS is the key, by using user defined style sheets. Or something like Stylish. See https://superuser.com/questions/128666/custom-per-site-stylesheet-extension-for-firefox
or https://addons.mozilla.org/en-us/firefox/addon/style-sheet-chooser-ii/
Not much progress but I'm putting what I tried up in case it inspires anyone else:
Works much worse than you would think
Make a bookmarklet that makes all children of body have 100% width. Then, if you click the bookmarklet again, it makes all children of children of body have 100% width. This way, the user can just click until the site becomes more pleasing to them :)
var levels = levels ? levels + 1 : 1;
$('body *:nth-child(' + levels + ')').css({ width: '100%' });
.
First approach to try and figure out where the first meaningful content is
Cool puzzle, I'm employing the awesomeness of jQuery. So I'm approaching it by trying to find the first element which has more non-empty .contents() than .children() because contents also fetches text nodes. Here's what I have so far. It's close, but not quite right because it seems to be searching a bit too deep:
$('body *:visible').filter(function(){
return moreNonEmptyContentThanChildren($(this));
}).first();
function moreNonEmptyContentThanChildren(el) {
var contentCount = 0;
var contents = el.contents();
for (c = 0; c < contents.length; c++) {
elc = contents[c];
if (elc.nodeType != 3 || (elc.nodeType == 3 && $.trim($(elc).text()) != '')) {
contentCount ++;
}
}
return contentCount != el.children().length;
}
I hope someone can help with this quirky issue I am having with the Opera Browser, I have version 11 Beta installed, but I suspect is a common problem in Opera.
The website and page in question is http://www.amigaos.net/index.html.
At the bottom of the body of the html I have the following code which resizes the 3 images you see on this webpage depending on width of the viewport at page load. In Safari and FireFox the code works fine, but in Opera the following lines which involve resizing the width and height of an image do not work:
document.getElementById('img1').width = '475';
document.getElementById('img1').height = '375';
Here is the code in full (sorry, about the layout, stackoverflow hasn't formatted carriage returns correctly)
<script type="text/javascript">
function GetWidth()
{
var x = 0;
if (typeof window.innerWidth != 'undefined')
{
x = window.innerWidth;
}
else if (document.documentElement && document.documentElement.clientHeight)
{
x = document.documentElement.clientWidth;
}
else if (document.body)
{
x = document.getElementsByTagName('body')[0].clientWidth;
}
return x;
}
width = GetWidth();
if (width>=1680)
{
document.getElementById('img1').width = '475';
document.getElementById('img1').height = '375';
document.getElementById('img2').width = '475';
document.getElementById('img2').height = '375';
document.getElementById('img3').width = '475';
document.getElementById('img3').height = '375';
}
else if ((width>800) && (width<=1280))
{
document.getElementById('img1').width = '300';
document.getElementById('img1').height = '235';
document.getElementById('img2').width = '300';
document.getElementById('img2').height = '235';
document.getElementById('img3').width = '300';
document.getElementById('img3').height = '235';
}
else if (width<=800)
{
document.getElementById('img1').width = '225';
document.getElementById('img1').height = '195';
document.getElementById('img2').width = '225';
document.getElementById('img2').height = '195';
document.getElementById('img3').width = '225';
document.getElementById('img3').height = '195';
}
</script>
instead of doing width and height attributes, I think you can just set width: 33% via CSS and have the scaling happen automatically, regardless of the browser window size. Better solution than trying to use javascript, IMHO.
Here's a simple tutorial: http://haslayout.net/css-tuts/CSS-Proportional-Image-Scale
you are making this way too complicated. I don't think your issue is browser-specific, you just need to recode your script.
First. I would recommmend using percentages.. Not sure how you will guess the visitors browser width in pixels.
Let's say that your three resizeable images are 20% width of your browser. So your css would be:
#img1, #img2, #img3 {
width: 20%;
}
now that your css says that your images are 20% of the total with, you're good to add some js. Keep in mind that the percentage will be that of its outer container.
<script type=text/javascript">
function resizeImages() {
document.getElementById('img1').style.height = (document.body.clientHeight - 100) * 0.2;
document.getElementById('img2').style.height = (document.body.clientHeight - 100) * 0.2;
document.getElementById('img3').style.height = (document.body.clientHeight - 100) * 0.2;
}
</script>
and most importantly.. call your function:
add this to your body tag:
<body onresize="resizeImages()">
boom.. you're done.
How do I check if browser supports position:fixed using jQuery. I assume I have to use $.support I think, but how?
Thank you for your time.
The most reliable way would be to actually feature-test it. Browser sniffing is fragile and unreliable.
I have an example of such test in CFT http://kangax.github.com/cft/#IS_POSITION_FIXED_SUPPORTED. Note that the test should be run after document.body is loaded.
I find that mobile safari (specifically iOS 4.2 via the iOS Simulator on OSX) refuses to scroll anywhere unless you wait a few miliseconds. Hence the false positive.
I wrote a quick jquery plugin to work around it:
(function($) {
$.support.fixedPosition = function (callback) {
setTimeout(
function () {
var container = document.body;
if (document.createElement && container && container.appendChild && container.removeChild) {
var el = document.createElement('div');
if (!el.getBoundingClientRect) return null;
el.innerHTML = 'x';
el.style.cssText = 'position:fixed;top:100px;';
container.appendChild(el);
var originalHeight = container.style.height,
originalScrollTop = container.scrollTop;
container.style.height = '3000px';
container.scrollTop = 500;
var elementTop = el.getBoundingClientRect().top;
container.style.height = originalHeight;
var isSupported = !!(elementTop === 100);
container.removeChild(el);
container.scrollTop = originalScrollTop;
callback(isSupported);
}
else {
callback(null);
}
},
20
);
}
})(jQuery);
function fixedcheck () {
var fixedDiv = $('<div>').css('position', 'fixed').appendTo('body');
var pos1 = fixedDiv.offset().top;
$(window).scrollTop($(window).scrollTop() + 1);
var pos2 = fixedDiv.offset().top;
fixedDiv.remove();
return (pos1 != pos2)
}
/* Usage */
$(document).ready(function () {
if (!fixedcheck()) alert('Your browser does not support fixed position!')
});
You could check if position exists by making a code like this:
<html>
<script type="text/javascript">
test = function() {
if(!!document.getElementById("test").style.position) {
alert('true');
}
else{
alert('false');
}
}
</script>
<body>
<p id="test" onclick="test();" style="position:fixed;">Hi</p>
</body>
</html>
Since position exists in all main browser this will always return true. I imagine there isn't a way to check the possible values of position, so you'll have to check which browser and which version the user are viewing your page as Paolo Bergantino said.
position:fixed apparently works for all block elements in Mobile Safari (4.3.2) except body, so the CFT answer (http://kangax.github.com/cft/#IS_POSITION_FIXED_SUPPORTED) should have this in it:
var isSupported = (container.scrollTop === 500 && elementTop === 100);
The feature-test Position fixed support , mentioned above, returns a false-positive on Opera Mini (which does not support position: fixed).
I've created another check if position:fixed is really supported in browser. It creates fixed div and try to scroll and check if the position of div changed.
function isPositionFixedSupported(){
var el = jQuery("<div id='fixed_test' style='position:fixed;top:1px;width:1px;height:1px;'></div>");
el.appendTo("body");
var prevScrollTop = jQuery(document).scrollTop();
var expectedResult = 1+prevScrollTop;
var scrollChanged = false;
//simulate scrolling
if (prevScrollTop === 0) {
window.scrollTo(0, 1);
expectedResult = 2;
scrollChanged = true;
}
//check position of div
suppoorted = (el.offset().top === expectedResult);
if (scrollChanged) {
window.scrollTo(0, prevScrollTop);
}
el.remove();
return suppoorted;
}
This function was tested in Firefox 22, Chrome 28, IE 7-10, Android Browser 2.3.
I have a web page that uses a scrolling div to display table information. When the window is resized (and also on page load), the display is centered and the div's scrollbar positioned to the right of the page by setting its width. For some reason, the behaviour is different under firefox than IE. IE positions/sizes the div as expected, but firefox seems to make it too wide, such that the scrollbar begins to disappear when the window client width reaches about 800px. I'm using the following methods to set the position and size:
function getWindowWidth() {
var windowWidth = 0;
if (typeof(window.innerWidth) == 'number') {
windowWidth=window.innerWidth;
}
else {
if (document.documentElement && document.documentElement.clientWidth) {
windowWidth=document.documentElement.clientWidth ;
}
else {
if (document.body && document.body.clientWidth) {
windowWidth=document.body.clientWidth;
}
}
}
return windowWidth;
}
function findLPos(obj) {
var curleft = 0;
if (obj.offsetParent) {
curleft = obj.offsetLeft
while (obj = obj.offsetParent) {
curleft += obj.offsetLeft
}
}
return curleft;
}
var bdydiv;
var coldiv;
document.body.style.overflow="hidden";
window.onload=resizeDivs;
window.onresize=resizeDivs;
function resizeDivs(){
bdydiv=document.getElementById('bdydiv');
coldiv=document.getElementById('coldiv');
var winWdth=getWindowWidth();
var rghtMarg = 0;
var colHdrTbl=document.getElementById('colHdrTbl');
rghtMarg = parseInt((winWdth - 766) / 2) - 8;
rghtMarg = (rghtMarg > 0 ? rghtMarg : 0);
coldiv.style.paddingLeft = rghtMarg + "px";
bdydiv.style.paddingLeft = rghtMarg + "px";
var bdydivLft=findLPos(bdydiv);
if ((winWdth - bdydivLft) >= 1){
bdydiv.style.width = winWdth - bdydivLft;
coldiv.style.width = bdydiv.style.width;
}
syncScroll();
}
function syncScroll(){
if(coldiv.scrollLeft>=0){
coldiv.scrollLeft=bdydiv.scrollLeft;
}
}
Note that I've cut out other code which sets height, and other non-relevant parts. The full page can be seen here. If you go to the link in both IE and firefox, resize width until "800" is displayed in the green box top-right, and resize height until the scrollbar at the right is enabled, you can see the problem. If you then resize the IE width, the scrollbar stays, but if you resize the firefox width wider, the scrollbar begins to disappear. I'm at a loss as to why this is happening....
Note that AFAIK, getWindowWidth() should be cross-browser-compatible, but I'm not so sure about findLPos().... perhaps there's an extra object in Firefox's DOM or something, which is changing the result??
You are dealing with "one of the best-known software bugs in a popular implementation of Cascading Style Sheets (CSS)" according to Wikipedia. I recommend the Element dimensions and CSS Object Model View pages on Quirksmode.org.
Also: I think you'll find that Safari and Opera behave like Firefox in most circumstances. A more compatible approach to working around these problems is testing for, and making exceptions for, MSIE instead of the other way around.
Ok, I found the problem. Seems to be that firefox does not include the style.paddingLeft value in its style.width setting, whereas IE does, thus the div was ending up exactly style.paddingLeft too wide. That is, if for example style.paddingLeft is 8, IE's style.width value would be 8 more than FireFox's - and thus the inverse when setting the value, for FireFox I needed to subtract the style.paddingLeft value
Modified code with:
if (__isFireFox){
bdydiv.style.width = winWdth - bdydivLft - rghtMarg;
} else {
bdydiv.style.width = winWdth - bdydivLft;
}
As long as you don't include a valid doctype, you can't expect consistent results, due to Quirks Mode. Go add one (HTML 4.01 Transitional is fine), then let us know if it still occurs.
Also see http://en.wikipedia.org/wiki/Quirks_mode.
In your getWindowWidth() function, whenever you grab the width of something, instead of this:
windowWidth = document.documentElement.clientWidth;
try this
windowWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth);
A detail to help optimize some of your code:
function getPos(elm) {//jumper
for(var zx=zy=0;elm!=null;zx+=elm.offsetLeft,zy+=elm.offsetTop,elm=elm.offsetParent);
return {x:zx,y:zy}
}
(jumper is a user who posted this code in Eksperten.dk)