wicg / visual-viewport Goto Github PK
View Code? Open in Web Editor NEWA proposal to add explicit APIs to the Web for querying and setting the visual viewport
Home Page: https://wicg.github.io/visual-viewport/
License: MIT License
A proposal to add explicit APIs to the Web for querying and setting the visual viewport
Home Page: https://wicg.github.io/visual-viewport/
License: MIT License
If the developer has modified the layout viewport size (e.g. meta viewport with width=1024 on a device where device-width would have been 384), pageScale should probably reflect the ratio against that adjusted viewport rather than the ideal viewport.
So I think this should instead use "layout viewport", though I'd be interested to make sure we're on the same page with the nastier cases you called out with wide elements and min-scale.
Currently:
var offsetX = viewport.scrollLeft;
var offsetY = viewport.clientHeight - document.documentElement.clientHeight + viewport.scrollTop;
Should instead be this I think:
var offsetX = viewport.scrollLeft - document.scrollingElement.scrollLeft;
var offsetY = document.documentElement.clientHeight - (viewport.scrollTop - document.scrollingElement.scrollTop) - viewport.clientHeight;
As in stackoverflow, I think of changing visual viewport dynamicly. This will be useful in routings, when user changes its position in a SPA.
As I searched a lot, I found out these parameters are read only (visual viewport height and width) but there are changing according to focus or user behavior. So, changing it by code is necessary.
Thanks for any help, or information.
As per whatwg/webidl#365.
This is less a question about the Visual Viewport API per se, and more about the underlying behaviour of the visual viewport itself, but it came up while investigating a Visual Viewport API web platform test so I thought I'd ask it here.
The test in question sets up a scenario where visualViewport.offsetLeft
and offsetTop
are nonzero, then performs window.scrollTo()
(which has room to perform layout scrolling and does so), and then asserts that offsetLeft
and offsetTop
are unchanged.
The accompanying comment says:
// The visual viewport should be fully scrolled so even if
// scrollTo does normally "push" the layout viewport with the
// visual, there should be no change to either offsetValue
I'm not fully clear on the intended underlying conceptual model. Under what circumstances is window.scrollTo()
expected to preserve the offset of the visual viewport relative to the layout viewport? (The comment suggests to me that it's not "always", though perhaps I'm misreading it.)
In the current Firefox implementation, window.scrollTo()
sets both the layout and visual viewport offsets to the specified location (in other words, collapses the relative offset to zero). We chose this because we figured that a page performing window.scrollTo()
may be trying to bring the user's attention to an element / section header etc. at the specified location, and so keeping that location out of view by preserving a potentially-large relative offset may be unexpected (kind of like how Element.scrollIntoView()
should scroll an element into the visual viewport, which I note is a behaviour Chrome fixed recently).
Before considering a change to the Firefox behaviour, I'd like to understand the underlying conceptual model and the motivation for it better.
cc @bokand
Preface: I am looking into new ways to detect the Desktop browser zoom with visualViewport
. Used to do that efficiently with svg.currentScale
but it's no longer working on Chrome. So I wanted to experiment:
As I am testing in Chrome 59 atm. If I zoom in or out, the current visualViewport scale remains at 1. It seems like it shouldn't be the case, and give the proper Browser zoom scale instead.
Per your formula:
physicalWidth = cssWidth / (visualViewport.scale * window.devicePixelRatio)
However with view.scale
at 1 while zoomed, I do not get a good equivalent of physicalWidth (outerWidth).
I think the interaction of the visual viewport with the window.scrollTo/scrollBy is also worth specifying as part of this proposal. The intuitive (to me, anyway) behaviour from the author's point of view would be that calling window.scrollTo also resets the visual viewport to the top-left of the layout viewport, and that calling window.scrollBy leaves the visual viewport as-is relative to the layout viewport.
My initial draft has scrollLeft and scrollTop as writable but pageScale as read-only. On reflection, a writable scroll offset seems pointless without a writable pageScale. We should either make them all read-only or all writable.
The definition of scrollTop
and scrollLeft
could be interpreted as requiring a negative sign in the normal case, although probably not, given that it says "distance" rather than "location" or "offset", since it's described as from the visual viewport to the layout viewport (rather than the other way around).
However, I'm not 100% sure that we can promise that it always should be a nonnegative number, e.g., with touch overscrolling.
This makes me think that it should be described as an offset or location, but with the "from" and the "to" swapped from the way they currently are.
Noticed while reviewing the spec for w3ctag/design-reviews#128 .
@bokand I wonder if there's an opportunity to align some active proposals with the Visual Viewport API, particularly the Window Segments Enumeration JS API (see also the proposed CSS MQ). +CC @zouhir & @dlibby- Perhaps folds or screen edges within the content area could be exposed as visual viewport information, or general insights from this work could inform that proposal.
Please consider joining our TPAC breakout session to discuss the foldables and multi-screen problem space and alignment opportunities between some active proposals. That will continue discussion from the Second Screen CG meeting; minutes. Thanks!
This would allow CSSOM style smooth-scrolling and passing ScrollToOptions
i.e. Should setting document.documentElement.dir = "rtl"
make scrollLeft
run from 0 to negative values?
Currently a visualviewportchanged listener will trigger on every scroll. If a developer is really only interested in observing the size of the visual viewport, this would be more noisy than intended.
See https://drafts.csswg.org/cssom-view/#events
I could add some hook or something to CSSOM View for this if that would help.
It seems to be more conceptually appropriate under window
and this is some of the common feedback I've heard. The reason we avoided window was to avoid clashing with the app's namespace but maybe this fear is overblown?
The proposal in https://github.com/bokand/URLBarSizing is something that Safari already does and we're likely to switch to shortly. We should be explicit about how the two interact.
In short, I think the real problem here is that when we say "layout viewport" we're actually referring to the "position: fixed viewport". We've often said that the visual viewport is bounded by the layout viewport but in that many cases, the layout viewport doesn't have much to do with layout. In the case of the static-layout URL bar, hiding the URL bar will increase the height of the visual viewport and the position: fixed viewport (what we currently call the layout viewport), but not the initial containing block (the "real" layout viewport"). Perhaps we need a shift in terminology...
The spec does not mention if the Visual Viewport API is restricted to secure contexts only. Currently, in Chrome the Visual Viewport API is available in non-secure contexts. The W3C spec for secure contexts https://w3c.github.io/webappsec-secure-contexts/#new recommends all new features to be restricted to secure contexts. For existing features which are not widely used but widely implemented, the spec suggests applying this restriction and modifying the specs of the existing feature. What do you think about restricting the Visual Viewport API to secure contexts?
I believe the intent of the spec currently is to return lengths/offsets in the layout viewport's coordinate space -- e.g. as I zoom in, the visual viewport's clientWidth and clientHeight properties "shrink".
However, pending the addition of real device-fixed positioning, it's interesting to additionally receive these properties in the coordinate space of the visual viewport (basically just unaffected by pageScale). Since these elements are laid out in the visual viewport's coordinate space, it's more convenient to receive the measurements in the visual viewport's coordinate space directly rather than multiplying by pageScale (and introducing risk of floating point error).
I imagine other scenarios could also benefit from this, but that's the one that immediately pops into my mind for now :)
Our proposal currently has the viewport object on document.documentElement. This may not be the ideal place for it.
The draft spec says e.g. "The user agent must fire an Event named resize on the window.visualViewport object" - but it doesn't provide any details about this event. Does it bubble up to the window? Is it cancelable? Does it have any relatedTarget elements or anything of that nature? Does it extend from UIEvent
or Event
?
This specification doesn't specify whenever resize event on visual viewport is dispatched before or after resize event on window object but it should.
Let's say I wanted to style an element so it appeared "attached" to the visual viewport:
visualViewport.addEventListener('scroll', visualViewportUpdate);
// But it's possible for the viewport to update without scrolling, so
// we need to track resize too:
visualViewport.addEventListener('resize', visualViewportUpdate);
// Neither of those events fire when just pageLeft/pageTop changes
// so we have to listen to something that represents the layout
// viewport too:
window.addEventListener('scroll', visualViewportUpdate);
// Problem: it's now possible for visualViewportUpdate to be called
// three times for a single update, so we need to work around that:
let pendingUpdateHandler = false;
function visualViewportUpdate() {
// Avoid additional calls within the same frame.
if (pendingUpdateHandler) return;
pendingUpdateHandler = true;
// Flip the boolean after we've processed all the events.
requestAnimationFrame(() => {
pendingUpdateHandler = false;
});
// Handle visual viewport change…
}
This seems pretty tough going, and requires a pretty detailed understanding of the event loop to get right.
Initially I was worried that the events may fire across different visual updates, but I stumbled across #25 which cleared that up.
It feels like we need a single event that fires when any of the properties update, including pageLeft
/pageTop
, that would turn the above example into:
visualViewport.addEventListener('update', () => {
// Handle visual viewport change…
});
Should there be a parallel API for layout viewport?
A couple reasons this might be interesting:
This terminology is more in line with what web devs use. Scale
is what we've used internally to distinguish browser and pinch zooms and it leaked out here. Perhaps having it on the visual viewport is distinguishing enough?
https://wicg.github.io/visual-viewport/#extensions-to-the-window-interface says:
If the window has a Browsing Context set, return the VisualViewport object associated with it. Otherwise, return null.
But in the spec windows don't have a browsing context set at all. There's a concept of "document's browsing context" which is affected by discarding, and there's a browsing context stored in the settings object which apparently is not affected by discarding (but maybe should be? I just filed whatwg/html#3846 on that). but nothing on Window.
Even apart from this, though, what happens if a script takes a reference to a VisualViewport
and then the browsing context involved gets discarded?
And separately, what happens if there is no browsing context discarding, but the document of the Window
the VisualViewport
comes from stops being active? Concretely, say I grab a VisualViewport
from site A, then navigate that browsing context to a different-origin site B. Can I use the VisualViewport
I am holding to examine the user's interaction with site B? That would be quite undesirable.
I initially thought these would trigger scroll
events, although I guess they're the result of the scrollingElement
scrolling in addition to the visual viewport.
The spec defers to https://www.w3.org/TR/cssom-view-1/#scrolling-events for the scroll event, which doesn't really make sense.
Code sample specifies that scrollbars should be excluded from the clientWidth/Height measurements. I agree this aligns better with some of the scenarios we've discussed (e.g. "is in view" checks, pseudo-device-fixed, etc.), but this is a divergence from the existing innerWidth/Height API behaviors. Probably worth soliciting input on.
The definitions of scrollTop
, scrollLeft
, pageX
, and pageY
don't say anything about what units they're in. It seems like they should. (Similar properties in cssom-view should too!)
Noticed while reviewing the spec for w3ctag/design-reviews#128
As far as I know, the inert-visual-viewport flag just changes the behavior of properties like window.innerWidth and body.scrollX. Is there any preferable/standard way to feature detect which version of the API is present? Possibly, it is the idea to simultaneously release this API change and the viewport API, in which case one could simply check for the presents of window.viewport; or is the idea to first release the viewport API and later on the inert-visual-viewport stuff?
The definition of the scroll and resize events should be clearer about when, exactly, the scroll event is fired.
In particular, a resize, by definition, changes some edges of the visual viewport. Does the scroll event fire at the same time as a resize event if the resize involves a change to certain edges (the top or left, or something dependent on directionality?) of the viewport, does a scroll event always also fire along with a resize event, or does a scroll event never fire at the same time as a resize event since a resize event implicitly changes some of the edges of the visual viewport?
The proposal suggests firing a visualviewportchanged event to content. With async panning/zooming, this event will necessarily be async and laggy, just like the scroll event. I don't really have any better ideas at the moment but I wanted to raise an issue for it as I think it merits further discussion. If authors start relying on this event to implement scroll-linked effects then it can result in bad-looking behaviour if the main thread is busy or under load.
New things on window typically need to be annotated with [Replaceable]
. The attributes CSSOM View defines on window are, https://drafts.csswg.org/cssom-view/#extensions-to-the-window-interface
Also you could add [SameObject]
to require that the same object is returned every time.
So
partial interface Window {
[SameObject, Replaceable] readonly attribute VisualViewport visualViewport;
};
Creating an issue from dbaron's concern here: w3ctag/design-reviews#128
The names are a hodgepodge of things from other places in the platform (Element and MouseEvent).
Need to consider the relative values of having (1) a sensible API, locally vs. (2) an API whose names share meaning with names elsewhere in the platform.
We're looking at implementing the Visual Viewport API in Firefox. One thing we noticed was that the spec seems to define visualViewport
for iframes as well. Is that useful? My understanding is that iframes don't have distinct notions of visual and layout viewports, since they cannot be zoomed.
And similarly, visualviewportchanged fire when the position changes relative to the document origin rather than just the layout viewport.
Arguments for document origin:
Arguments for layout viewport origin:
I lean towards document origin but can see the pros for each side. I'm guessing you may have had additional reasoning for selecting layout viewport origin in your draft -- anything I'm missing above?
The size returned by the Visual Viewport API excludes any space taken up by scrollbars.
What if a web page wants to know the size including the scrollbars? In Firefox, it can currently use window.innerWidth
. However, if we switch window.innerWidth
to report the size of the layout viewport instead as Chrome has done, that will no longer work; is there a replacement?
We originally changed this the other way in the context of #35 but this has compatibility issues. There's a non-trivial number of pages using a global view
which could cause them to break if we add this. Last I checked visualViewport
was unused in the HTTPArchive and so has much less risk.
The original complaint was that it's cumbersome and "java-like". IMO, it actually fits in well with other window
properties like sessionStorage
, localStorage
, and devicePixelRatio
. Worst-case, authors can always alias it to something more convenient.
I think this is maybe supposed to represent the scrollbar width? If so then it will be incorrect at scale values other than 1.0 (since the scrollbar doesn't scale as the user zooms) and also incorrect for any UAs with scrollbars of differing widths.
Chrome always returns scale 1 for iframes, and this is also covered by viewport-scale-iframe-manual.html. But it's not clear that the spec language at https://wicg.github.io/visual-viewport/index.html#dom-visualviewport-scale implies this. Does this follow from the math given there or do we need to add a special case?
This came up in a WebKit review (https://bugs.webkit.org/show_bug.cgi?id=179385#c7).
In Chrome 61 running on Samsung S7:
window.outerHeight is 310
viewport.height is 310
So I can't set bottom = of my relatively positioned element.
Several Window APIs currently return null when there's no associated browsing context (e.g., this happens when we have a window object corresponding to an iframe element that has been removed from the DOM). See calls to "IsCurrentlyDisplayedInFrame" in LocalDOMWindow.cpp in Blink for examples.
Should window.visualViewport behave the same way? Currently in Blink, it's non-null even when there's no associated browsing context, but the question of whether it should really be null came up in a WebKit code review: https://bugs.webkit.org/show_bug.cgi?id=179385#c7
This specification doesn't specify when resize event on visual viewport is dispatched before or after other pending scroll event targets. Because document itself is a pending scroll event target, even specifying the order relative to document's resize event itself is insufficient; there could be more pending scroll event targets such as other scrollable elements in the same document.
I am experimenting with visualViewport.scale to detect the best resolution needed for bitmap elements (e.g. image or canvas). Currently I multiply the CSS pixel size of an HTML canvas by the factor (visualViewport.scale*window.devicePixelRatio). This accounts for pinch zoom, browser zoom, and physical device pixel ratio. window.devicePixelRatio already contains the physical device pixel ratio multiplied by the browser zoom factor and visualViewport.scale accounts for the pinch zoom. This part works fine on Chrome Canary Win 8.1.
I also use window.innerWidth in order to limit the size of a WebGL canvas (which is an important performance optimization) to the part of the canvas that is actually visible. I tried to replace window.innerWidth by visualViewport.clientWidth, however it turns out that visualViewport.clientWidth is a bit smaller than window.innerWidth (according to the old semantics, i.e. with disabled inert-visual-viewport), which probably accounts for the space of the scroll bar. When pinch zooming-in this difference seems to stay constant and does not scale with the pinch zoom. (Tested emulating a laptop with touch in developer tools on windows 8.1, 54.0.2820.0 canary, enabled enable-experimental-web-platform-features and disabled inert-visual-viewport).
The fixed-to-keyboard.html seems to experience this problem as well: Add a horizontal scroll bar below the red box, (e.g. by increasing the width of the text area in the elements panel of developer tools). Then pinch zooming-in makes the red box move up and no longer stay directly on top of the scroll bar. (Tested emulating a laptop with touch in developer tools on windows 8.1, 54.0.2821.0 canary, enabled enable-experimental-web-platform-features and enabled inert-visual-viewport).
We are about to ship this API in Firefox, and I'm working on coordinating some MDN documentation.
I notice that in this repo, the headline example is emulating position: device-fixed
. I wonder, though -- is this the best use case for this API?
In browsers with asynchronous scrolling, which includes both Chrome and Firefox on Android, updating a position property from script in response to scrolling is going to cause flickering during scrolling. (And indeed, if I open the headline example on Android with either Chrome or Firefox, the red box flickers as you scroll.)
It feels strange to me to be encouraging web developers to author websites with flickering elements. I would feel better about promoting examples that don't involve such artifacts.
(On a related note: if we want users to be able to have position: device-fixed
behaviour, perhaos a better approach would be to actually implement position: device-fixed
, which then doesn't need to cause such a flickering artifact?)
The demo thingy at http://bokan.ca/viewport/index.html was super useful, but going there now triggers a page download in Firefox instead of just loading it. Maybe it's being served with the wrong content-type or content-disposition?
The definition provided for the scale
property is not fully clear to me. That's probably because terms like "device pixel" are not well-defined specially when dealing with things like retina displays and automatic OS-level pixel doubling. An example scenario with both pinch-zoom and browser zoom applied would also help clarify the "note".
Everywhere else on the web platform, viewport means (or will soon mean) the layout viewport. For example:
So it would be very confusing for document.viewport
to mean something different. People will try to use document.viewport.clientWidth
to get the layout viewport width, etc.
Whilst the Chrome team internally uses terminology like layout viewport and visual viewport, and understands the difference, many web developers don't know there are two viewports.
Instead how about:
I guess the standard should prescribe the mitigations, even if they are obvious.
pageScale represents a scale ratio between two viewports (visual and layout), and conceptually isn't wholly owned by either.
Similar concepts would include the ratio between layout viewport and physical resolution (in Edge this is represented by devicePixelRatio). Or ideal viewport and physical resolution (devicePixelRatio in Safari). Or layout viewport and ideal viewport (@Viewport {width: 200%}).
My main concern is that as we find and develop interest in these other ratios we'll need to add more and more member properties to the viewport object. Issue #8 talks about the naming of this property which would become more confusing as well if/when these additional ratios are added.
I think this could be more generally solved by a coordinate space conversion API accepting two objects each defining a coordinate space and return a transformation matrix. A partial solution might just return a scale ratio, and maybe a translation.
outerWidth is not a safe property to use in polyfills since its value varies per each UA's browser chrome. This calculation is wrong on all non-maximized desktop browsers as a result.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.