Google 网上论坛不再支持新的 Usenet 帖子或订阅项。历史内容仍可供查看。

David Mark's Javascript Daily - Volume #33 - Tip #2 - How to Measure the Viewport

已查看 50 次
跳至第一个未读帖子

David Mark

未读,
2011年12月5日 21:35:262011/12/5
收件人
How to Measure the Viewport

As usual, the first question you need to ask is: why do I want to
measure the viewport? Should be immediately followed by: what is going
to happen to my application if I fail to measure the viewport
properly?

Let's consider the task of centering an element in a single document.

var getViewportDimensions;

// May include space taken up by scroll bars (if any)
// No frames or alternate windows
// Degrads in IE 8-

if ('number' == typeof window.innerWidth) {
getViewportDimensions = function() {
return [window.innerWidth, window.innerHeight];
};
}

if (getViewportDimensions) {
var centerElement = function(el) {
// ...
};
}

if (centerElement) {
// Away we go...
}

So again, good riddance to bad baggage: IE 8 and under, all of the
many browsers based on MSHTML circa IE 8 and under and compatibility
modes are left out of the application that insists on centering
elements.

The innerWidth/Height properties date back as far as I can remember,
for everything but the old IE browsers. The catch has always been
that, as commented, the space taken up by scroll bars (if any) may be
included.

I see that these properties have recently been "standardized", but
that is not the reason that it is the first choice. It's simply the
best solution for this particular task (scroll bar area
insignificant). These properties are present in at least some mobile
browsers as well, and their scroll bars don't take up any room. There
is no ambiguity about what these window properties mean.

Speaking of ambiguity, if IE 8- is also to center elements:-

// Last test excludes IE quirks mode

...else if (document.documentElement && 'number' == typeof
document.documentElement.clientWidth &&
document.documentElement.clientWidth) {
getViewportDimensions = function() {
return [document.documentElement.clientWidth,
document.documentElement.clientHeight];
};
}

This one could go in the file that is put inside conditional comments
(for IE less than 9). Doesn't have to be though. If exposed to the
rest of the world, could get wrong numbers in an old version of Safari
(2 IIRC), but that's no tragedy today. I'd be more concerned with
including mobiles that don't have window.innerWidth, as these
properties may represent the entire document, regardless of what the
"viewport" (as they see it) is over.

Should note that code that measures the viewport should be in a load
listener (or "ready" callback).

If you want something more elaborate,

http://www.cinsoft.net/viewport.asp

That one has the Safari 2 fix (oh boy). But it also shows how to
feature test the suspect properties (e.g. documentElement.clientWidth,
body.clientWidth) to determine which pair is representing the
viewport. These properties make sense in IE as the HTML or BODY
element *is* the viewport (with the border part of the chrome). If
the HTML element is not rendered (as in IE quirks mode), you can be
sure the body is the viewport. Unfortunately, a popular object
inference based on the rendering mode was the indicator used by
competing browsers when copying these properties.

Since the primer was written, the mobiles have made the situation
messier, adding additional property pairs (offsetWidth/Height come to
mind) to test. The two paths at this point are to go with the one-
liner (and optionally stash another one-liner for IE 8- in conditional
comments) and work in virtually everything, save for the odd mobile
device. Or add more tests to the more complicated example in the
primer to support a few more devices. One consideration is whether
the extra scroll bar area will be significant (e.g. maximizing
elements); if so, the window.innerWidth/Height solution is right out
(no matter what the "standard" says about scroll bars).

Should point out that it is generally less error-prone to measure the
width of the viewport (as it is less likely to scroll significantly).
So centering horizontally at or near the top (like Macs) is a more
conservative solution. It's also advisable to focus something in the
dialog (or whatever) so that it will be scrolled into view if you
miscalculate badly.

Combined with the previous discussion on scroll position (see the
element measuring tip), you have enough to add getViewportRectangle to
your repository, which isn't particularly useful when getting element
positions relative to the viewport. All you need is the viewport size;
for example:-

if (getViewportDimensions && getElementRectangleRelativeToViewport) {
isElementInViewport = function() {
return
isRectangleInRectangle(getElementRectangleRelativeToViewport(el), [0,
0].concat(getViewportDimensions()));
};
}

Something like that. Method name on an element-related object would
be "isInViewport". The "isRectangleInRectangle" function is browser
agnostic (basic math) and therefore not created conditionally. See
various rectangle examples in My Library.

What sort of logic can you expect of a viewport measuring function in
a typical GP library? God only knows. Would have to delve into its
code to find out, which may raise the question of why you are using
somebody else's idea of a library. Suffice to say, most "frameworks"
used browser sniffing to "solve" this problem, up until recently, and
many still do. Others simply exclude lots of browsers on paper, but
not in the code (e.g. works in iOS and Android, blows up otherwise).

So far, that's queries, select one, viewport, scroll position, sizing,
positioning and HTML, with add/bindEvent, mouse/touch and keyboard
examples readily available. You should be well on your way to writing
your own (really) fast, (really) concise, context-specific jQuery-like
script (if that's what you are into) that is actually fit for public
consumption. If not, keep reading...

http://www.cinsoft.net/
http://twitter.com/cinsoft
http://jsperf.com/browse/david-mark
0 个新帖子