Understanding Phantom window.resize Events in iOS

Hero image for Understanding Phantom window.resize Events in iOS. Image by Craig Whitehead.
Hero image for 'Understanding Phantom window.resize Events in iOS.' Image by Craig Whitehead.

Something that I've been dealing with a lot recently whilst working on a web application that relies on displaying data on small screens is seemingly random or 'phantom' window.resize events from iOS devices. Unlike desktop browsers, where resize events are typically triggered by actual changes in window size, iOS Safari appears to exhibit a different behaviour, triggering resize events at random.

As web developers, we will often encounter unusual challenges like this in our line of work. It is fair to say that there must be some method to this madness: Apple isn't just triggering window.resize for fun!


Causes of phantom resize events

So, I did some experimenting, and here is what I think is causing these random events:

Dynamic Browser UI

I'm putting the main one first, because it's actually quite obvious when you think about it. In iOS Safari, the Browser interface is dynamic; the address bar and toolbars both react when a user scrolls the page, showing and hiding again to allow the user more screen real estate for the website itself.

When this happens, window.resize is triggered.

You'll have to excuse a little timehop here: I've returned to this article nearly seven years after it was first published to drop a video in to demonstrate this better. The original diagram I had here was not very good. So, please excuse the fact that this is showing an iOS 17 device, with iOS 10 having only just been released at the time of originally publishing this article.

The issue remains the same: watch the address bar at the bottom of the screen as the page is scrolled up and down. This is the source of our phantom resize events.

Viewport Adjustments

I've found that Safari will often also trigger a resize event when the viewport is adjusted by for example the virtual keyboard being shown or hidden. Again though: that makes sense. What makes less sense is that it also triggers when you switch between tabs...

Orientation Changes

This one should be selfexplanatory: the screen size does change between landscape and portrait. You can listen for this specifically by adding a listener to window:

window.addEventListener('orientationchange', (event) => {  console.warn(`The screen orientation is now ${event.target.screen.orientation.angle}`);});

User Interactions

window.resize triggers when user gestures like pinchtozoom are used.


Mitigating Phantom resize events

For the most part, these random additional events fly under the radar: it doesn't matter to the application or your user experience. However, there are edge cases where for example resize events might trigger additional functionality, whilst you really only intend for it to happen when the physical size of the screen has changed.

There is of course a simple solution: during a resize event, check the width of the window and if it has not changed, then disregard the event. Something like this:

const [windowWidth, setWindowWidth] = useState(window.innerWidth);useEffect(() => {  const handleResize = () => {    const { innerWidth } = window;    if (innerWidth !== windowWidth) {      setWindowWidth(innerWidth);      // The window has resized.  Do your resize stuff here    }    // This is a phantom resize event. Do nothing.  };  window.addEventListener('resize', handleResize);  return () => window.removeEventListener('resize', handleResize);}, [windowWidth])

Here, all we are doing is:

  1. Initialising the windowWidth state with the current window.innerWidth.
  2. Creating a useEffect hook, which sets an event listener for the resize event.
  3. This triggers our handleResize function, which checks the current window.innerWidth against the width stored in state (windowWidth).
  4. If they are different, we then reset our state item to the new window width and continue with whatever functionality we intend to trigger on a genuine resize event.

Wrapping up

And that's it! Some might find it annoying that iOS opts to trigger nonevent resize events so frequently, although I would argue that they do make sense even if the physical size of the screen doesn't change. Fortunately, it is pretty straightforward to detect these phantom events and deal with them accordingly.


Categories:

  1. Adaptive Development
  2. Development
  3. Front‑End Development
  4. JavaScript
  5. Responsive Development