Email conversation
From | Philip Whittaker |
To | Me |
Subject | problem with calculating browser window width |
Date | 10 December 2004 17:10 |
Hi Mark,
I was searching the web when I found a page where you discuss the problem
of obtaining the width of the browser window minus the vertical scrollbar.
I've also come across that annoying Mozilla glitch where window.innerWidth
returns the visible bit PLUS the width of the scrollbar. Not 'inner' at all.
I tried your trick of fixing an empty element to the right side of the
window and measuring it - worked fine - then got to wondering if the 'body'
of the document could be used in the same way. So:
body{height:100%;width:100%;margin:0%;}
and now:
w=windowWidth(); alert(w);
seems to return the correct values for the visible width of the window. The
function is as follows.
function windowWidth(){
if (window.innerWidth){
if (document.body.offsetWidth){
if (window.innerWidth!=document.body.offsetWidth)
return document.body.offsetWidth;
}
return (window.innerWidth); // Mozilla
}
if (document.documentElement.clientWidth)
return document.documentElement.clientWidth; // IE6
if (document.body.clientWidth)
return document.body.clientWidth; // IE DHTML-compliant any other
}
[Ed. This is not a perfect solution, see later emails for more details]
The second and third bits are supposed to work with IE6 and IE any other
(as long as it's later than 4) respectively - at least, according to the
literature!
The first part is an attempt at backwards compatibility when - if - the
glitch in Mozilla is corrected (I notice that the latest version of Firefox
has inherited the same inconsistency, so don't hold your breath). The
reasoning - and I am NOT a programmer, so this may require checking! - is
that should the statement if (document.body.offsetWidth) ever become
incomprehensible to the browser, it will skip the next three lines and just
return window.innerWidth. Thus obviating the need to trawl back through a
lot of old sites and re-edit them. Be that as it may! It seems to work OK
in IE6, NN6 and 7, and whatever version of Firefox it is that's on offer at
the moment, though I haven't tested in any further.
All the best,
Phil.
From | Philip Whittaker |
To | Me |
Subject | Correction re: problem with calculating browser window width |
Date | 10 December 2004 18:23 |
Mark,
A slight amendment to my previous e-mail:
body{position:absolute;top:0%;right:0%;height:100%;width:100%;margin:0%;}
If you don't use position:absolute; the trick doesn't seem to work.
Phil.
From | Me |
To | Philip Whittaker |
Subject | Re: problem with calculating browser window width |
Date | 12 December 2004 15:21 |
Phil,
yes, in theory this should work. but we must not break the effect for the
other browsers. Although this will correct the mozilla mistake in some
circumstances, it will not necessarily have the correct effect in the other
browsers. Depending on the doctype, different browsers will have different
defaults for:
html margin
html padding
body margin
body padding
With strict doctypes, the body is no longer the root element, and instead
the HTML element conforms to the viewport. However, the offsetWidth does
not necessarily refer to the available width; depending on the
browser/doctype combination, it can refer to the space being used, not the
space that is available. As a result, what you wrote would not work in all
the various combinations. Safari in particular will suffer when you use
offsetWidth on HTML or body, as it gives incorrect results in many
situations.
That is one of the reasons why this whole section of JavaScript is such a
big problem. It is much easier to simply delete 16 pixels from the width if
a scrollbar is showing.
Note that what you wrote would produce errors in older browsers that do not
support document.body. you should check for that as well if you intend to
use that:
if (document.body&&document.body.offsetWidth){
Mark 'Tarquin' Wilton-Jones - author of http://www.howtocreate.co.uk/
From | Philip Whittaker |
To | Me |
Subject | problem with calculating browser window width |
Date | 24 January 2005 10:20 |
Hi Mark,
Many thanks for your helpful reply. You brought up a number of issues I had
not considered!
Just to explain what I am actually trying to do: I'm designing a page
(DOCTYPE xhtml 1.1) that uses a background image the width of the maximized
window (based on the assumption that if the screen width is less than 50 px
greater than the window width then the window is maximized). In order to set
the image to the correct width I need an accurate way of measuring the width
of the visible part of the window (this value would also be very useful for
centering objects).
The problem seems to be with Mozilla. Using window.innerWidth returns the
same value whether or not there is a vertical scrollbar. They can't both be
right! Would subtracting a nominal value when the scrollbar is present work,
since it is a different width in different browsers?
After reading your comments I set up a number of test pages, which created
various combiations of scrollbars, and tried measuring them using various
methods (objectWidth, clientWidth etc etc). Unfortunately, I was unable to
find any method that returned an accurate value under all circumstances.
I also hit another snag. A page designed in CSS to fit a 1024 x 768 screen
will be too big at 800 x 600, forcing scrollbars to appear. Even if the
width of the visible window (the window up to the left-hand edge of the
vertical scrollbar) could be measured accurately, when the page is resized
the scrollbar will disappear and the value will therefore be wrong. Same
problem when scaling the other way. This is not an issue in IE, since the
space for the vertical scrollbar is reserved whether or not it is needed,
and so is always technically present. Just in Mozilla...damn them!
In the end I resorted to the following browser-safe (well, safeish)
function, derived from the
http://www.quirksmode.org/viewport/compatibility.html page:
function windowWidth(){
if (document.getElementById){
if (window.innerWidth)
return window.innerWidth;
if (document.documentElement&&document.documentElement.clientWidth)
return document.documentElement.clientWidth;
if (document.body.clientWidth)
return document.body.clientWidth;
}
}
[Ed. This is not a perfect solution, see later emails for more details]
and if none of these return anything then the script aborts. It's not ideal,
since when my page is dispayed in Mozilla and a vertical scollbar is
required, it overlays the background image resulting in a completely
pointless horizontal one as well. Which was the problem I was trying to
overcome in the first place. Oh well...
Yours in extreme perplexity,
Phil.
From | Philip Whittaker |
To | Me |
Subject | Calculating Browser Window Width |
Date | 8 May 2005 13:16 |
Hi Mark,
You e-mailed me before with some advice about calculating the true available
width of the browser window. I was trying to find a reliable way of doing
this because I wanted to use a background image which stretched to fit the
visible width of the window (i.e. the width not including the vertical
scrollbar) when the window was maximised.
I've come up with a method that works in NN6, NN7, Firefox, IE5, 5.5 and 6,
though I don't know if it is compatible with other browsers.
I used a container:
#background{position:absolute;top:0px;left:0px;height:1500px;width:800px;
overflow:hidden;}
and filled it with a series of images of the class:
.background{width:100%;display:block;}
This is the default layout for older browsers or people who have turned off
JavaScript. The height of the 'background' div will depend on the page
content (if JavaScript is enabled the content can be measured and the height
adjusted accordingly).
Next I created a couple of variables, 'scrnw' and 'winw', and set them using
something like this:
function scrnwidth(){
if (document.getElementById){
return (screen.width);
}
}
function winwidth(){
if (document.getElementById){
if (window.innerWidth)
return window.innerWidth;
if (document.documentElement&&document.documentElement.clientWidth)
return document.documentElement.clientWidth;
if (document.body&&document.body.clientWidth)
return document.body.clientWidth;
}
}
(I borrowed the second method from
http://www.quirksmode.org/viewport/compatibility.html, by the way.)
To establish whether the browser window was maximised, I subtracted 'winw'
from 'scrnw'. If the result was less than 50 I assumed that it was.
max=(scrnw-winw<50)? 1:0;
In the case of Internet Explorer the function 'winwidth' returns a true
value (that is, the width of the window minus the vertical scrollbar), which
can be used to set the width of the 'background' div. And, because IE
reserves space for the scrollbar whether or not it is required, 'winw'
should not equal 'scrnw', providing a test for IE.
With NN and Firefox, on the other hand, the functions 'winwidth' and
'scrnwidth' return the same value when the window is maximised, whether the
vertical scrollbar is present or not. However, if the width of the
'background' div is set to '100%' it expands to fill the visible area of the
window, whether or not the vertical scrollbar is present.
If the window is not maximised, the width of the 'background' div is set to
the width of the screen.
if (max)
pw=(winw!=scrnw)? winw+'px':'100%';
else
pw=scrnw+'px';
document.getElementById('background').style.width=pw;
Well, that's the theory anyway! I was wondering if you could tell me
whether, in your experience, this method would work with less common
browsers (Opera, Safari etc.). It detects and sets the correct width for the
browsers I mentioned above, but beyond that I don't know how reliable it is.
I've uploaded a test page to [test URL]. A vertical scrollbar appears /
disappears when you click the button. The background image SHOULD adjust
appropriately, without causing a horizontal scrollbar to appear. The DOCTYPE
is XHTML 1.0 Strict, and the imported script is at
[URL].
Many thanks, and all the best!
Phil.
From | Me |
To | Philip Whittaker |
Subject | Re: Calculating Browser Window Width |
Date | 9 May 2005 10:26 |
Phil,
> I was wondering if you could tell me
> whether, in your experience, this method would work with less common
> browsers (Opera, Safari etc.).
I can tell you that it does not work in Opera, there is no horizontal
scrollbar, but the background always looks full width. It's not bad though.
In Safari, it works the first time, then causes the scrollbar to remain,
without readjusting the background. Trying to scroll the scrollbar causes
it to disappear, without readjusting the background. This is almost
certainly a bug in Safari.
If only IE obayed the overflow rules, I could give you a simple:
html, body { width: 100%; margin: 0px; padding: 0px; }
var width = document.body.offsetWidth;
and that would work reliably. but IE will stretch it when the contents are
too wide :(
Tarquin
From | Philip Whittaker |
To | Me |
Subject | Re: Calculating Browser Window Width |
Date | 9 May 2005 13:22 |
Hi Mark,
After reading your comments I downloaded Opera 8 to see what was going on.
There seems to be a 6 pixel expanding tab on the left side of the window,
which means that the window width will never equal the screen width.
Therefore when the window is maximised the 'background' div will be set to
the width of the window plus scrollbar, rather than 100%.
I could change the line
pw=(winw!=scrnw)? winw+'px':'100%';
to
pw=(scrnw-winw>6)? winw+'px':'100%';
This works, but it does seem a bit fussy. I suppose the other way to go
would be to use some form of browser detection to determine whether or not
the browser is IE, but I understand that this is unreliable and generally
frowned upon.
As you mention, Opera (unlike NN and Firefox) does not add a horizontal
scrollbar when there is a vertical one covering a bit of the page. That was
the main annoyance I was trying to work around. The block of text on the
page is centred in the window plus scrollbar, rather than visible window,
but I can live with that!
A quick question: do you know any way of disabling the JavaScript for
Safari, and only Safari, so that users just get the CSS version of the page?
Once again, thanks for the advice.
Phil
From | Me |
To | Philip Whittaker |
Subject | Re: Calculating Browser Window Width |
Date | 9 May 2005 16:46 |
Phil,
> There seems to be a 6 pixel expanding tab on the left side of the window
Yes, the Panel. Something I hated when I first saw it, but have grown to
love it for the features it provides. It does cause a few annoyances
relating to screen.availFoo which I believe should report the workspace
area, not the available screen area, but at the moment, the JS spec demands
that it is done this way, even though that is not so intuitive for browsers
with an MDI.
> A quick question: do you know any way of disabling the JavaScript for
> Safari, and only Safari, so that users just get the CSS version of the
> page?
You would need to sniff. In theory, this can be done by checking if the
userAgent contains Safari, but this can be spoofed by various means. See my
snifer page for more details (and yes, sniffing is best avoided wherever
possible):
http://www.howtocreate.co.uk/tutorials/jsexamples/sniffer.html
Tarquin
From | Philip Whittaker |
To | Me |
Subject | Problem With Background Images On Web Page |
Date | 6 January 2007 10:00 |
Hi Mark,
I was reading a couple of articles on your site this morning. While I
wouldn't say that FF JavaScript checking is totally useless (it finds typos
such as missing brackets quite well), I certainly agree that you have to
take what it says with a fairly hefty pinch of salt! My own gripe is what I
might call the nag effect. For example:
function checkscroll(){
if (window.pageYOffset)
return window.pageYOffset;
else if (document.documentElement && document.documentElement.scrollTop)
return document.documentElement.scrollTop;
else if (document.body)
return document.body.scrollTop;
else
return 0;
}
generates a warning: "function checkscroll() does not always return a
value". Actually it generates the same warning every time the function is
called. This clogs up the info window, obscuring any genuine problems. The
checker would benefit from some kind of filter, so that what it thinks are
problems are not flagged up time after time.
Be that as it may...
I actually got onto your site while looking for some info on background
images, something I've been messing around with for a while. Rather than a
fixed background,, however, I want a background layer consisting of a stack
of images one below the other. The image layer needs to stretch to fill the
width of the viewport, and must be at least the height of the viewport even
when the page content is less. What I have so far is this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"" xml:lang="en" lang="en">
<head>
<title>Background Problem</title>
<style type="text/css">
body {height:100%; width:100%; padding:0; margin:0;}
#pagearea {position:absolute; top:0; left:0; z-index:1; width:100%;
overflow:hidden;}
#background1 {position:absolute; top:0; left:0; z-index:0; height:100%;
width:100%; overflow:hidden;}
#background2 {position:absolute; top:0; left:0; z-index:1; width:100%;}
#displayarea {position:relative; top:0; left:10%; z-index:2; width:80%;
padding-top:3em;}
.bgimage {width:100%;display:block;}
</style>
</head>
<body>
<div id="pagearea">
<div id="displayarea">
[ page content here ]
</div>
<div id="background2">
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
</div>
</div>
<div id="background1">
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
<div><img class="bgimage" src="background.jpg" alt="" /></div>
</div>
</body>
</html>
The idea is, that #pagearea, which contains one relatively and one
absolutely-positioned div, will derive its height from the
relatively-positioned one, and because its overflow is set to "hidden" will
only display as much of #background2 as is required. Should the height of
#pagearea be less than the height of the viewport, there is that other
layer, #background1, to complete the background. And lastly, should anyone
disable styles in their browser, since both the backgrounds are later in the
markup than the content, the content should display first.
However, Firefox (up to and including 2), when it loads the page
occasionally allows the images of #background2 to overflow. If you hit the
reload button it happens all the time (see the example at
[URL]). Forcing the page
to reflow by changing the font-size gets rid of it. Most odd!
Incidentally, this problem only seems to happen when the page content is
greater than the viewport and there is a vertical scrollbar.
Not sure whether this is a FF bug, or something wrong with my markup. The
problem doesn't occur in IE5+, for what that's worth. I was wondering if you
had come across anything like this before.
Many thanks, and a happy 2007!
Phil
From | Me |
To | Philip Whittaker |
Subject | Re: Problem With Background Images On Web Page |
Date | 6 January 2007 18:48 |
Phil,
> I want a background layer consisting of a stack of images one below the
> other.
Ah, roll on CSS 3 multiple backgrounds :)
Be forever before IE supports it, of course.
> However, Firefox (up to and including 2), when it loads the page
> occasionally allows the images of #background2 to overflow.
>
> Not sure whether this is a FF bug
It is a Firefox bug. Nothing with static content should change on reloading.
It seems to be fixed in the Firefox 3 engine, but until then, I do not know
of any workarounds, sorry.
Tarquin
From | Philip Whittaker |
To | Me |
Subject | Re: Problem With Background Images On Web Page |
Date | 9 January 2007 08:11 |
Many thanks for the information. Now I can go out and get a life, instead of
spending my evenings sat in front of a computer looking for a non-existent
solution!
All the best, Phil