WICG / visual-viewport

A proposal to add explicit APIs to the Web for querying and setting the visual viewport
https://wicg.github.io/visual-viewport/
MIT License
177 stars 28 forks source link

Difficult to react to changes in visualViewport #44

Open jakearchibald opened 7 years ago

jakearchibald commented 7 years ago

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 https://github.com/WICG/ViewportAPI/issues/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…
});
buttercookie42 commented 5 years ago

Speaking from a browser perspective, I also found the behaviour of only firing the event when the offset changes somewhat less than useful. In order to persist the current scroll position for session restore, I'm interested in changes of the user-visible scroll position, which means the absolute offset relative to the page = pageLeft/pageTop, so the event as spec'd doesn't really help.

Because I need to throttle my event processing anyway, I don't have any opinion on having separate vs. one common event for the "scroll" and "resize" cases, though - either way is fine.

Of course, working on a browser I can always define my own events anyway (and might also need to for other reasons), but it might still be one more argument for pageLeft/pageTop-related events.