Detect full screen using Javascript

Detect full screen using Javascript

Why would you want to detect if the browser is full screen? In my case, I made a dashboard that is configurable with different controls, but it is expected to be in “production” when the browser goes full screen and by then the controls would just be clutter and should be hidden. I found it to be not-as-simple-as-you-may-think.

Even with two different approaches, I have something working, but it is not optimal. My approach – when I detect the browser is full screen I add the class fullscreen to the <body>-element otherwise the class should be removed from the body-element.

First try: Compare the dimensions of the window and the screen.

The Javascript object screen can tell you about the visitors screen – things such as dimensions. So ask for screen.height and you may get 1200 back or ask for screen.availHeight and get 1175 back. availHeight tells you how much is available if you subtract the height of menus on the Mac or the Taskbar in Windows. Compare this to the height of say the window-object (window.innerHeight) and you will know if the size of the window is equal to (or close to being) as tall as the screen and thereby you know if the window is full screen (or almost).

Why this is not good enough

One assumption is that a visitor has only one screen. As i write this, I work on a laptop connected to one and sometimes two external monitors. Dragging my browser from one screen to another screen will rarely mean a new value for screen.height even though the number of pixels differ between screens. This may change in the future, but not as I am writing this.

Another assumption that breaks this approach surfaces if you try to zoom in or out in your browser using CTRL/CMD with plus or minus. window.innerHeight increases as you zoom out – so it will no longer represent the number of physical pixels and comparing it to screen.height is suddenly like comparing apples and oranges. You had better stick to window.outerHeight, BUT if you are not sure that screen.height actually represents the height of the screen showing the browser, it seems this approach was a bad idea from the beginning.

Second try: Detect if the use requested full screen using a button

So I added a Show full screen-button to the screen with a click-handler like:

$(function() {
  $('.reqfullscreen').click(function() {
    elem = this;
    if (elem.requestFullscreen) {
      elem.requestFullscreen();
    } else if (elem.msRequestFullscreen) {
      elem.msRequestFullscreen();
    } else if (elem.mozRequestFullScreen) {
      elem.mozRequestFullScreen();
    } else if (elem.webkitRequestFullscreen) {
      elem.webkitRequestFullscreen();
    }
  });
});

That way most browsers should go to full screen, when the button is clicked. I could just add the fullscreen class to the <body>-element directly here, but I would really like to detect when the browser leaves full-screen again, to remove the class and show the controls again, so this function is called on every window.onresize-event:

function showHero() {
    elems = document.querySelectorAll('body');
    var fs = isFullScreen();
    if (fs === true) {
      for (var i = 0; i < elems.length; i++) {
        elems[i].classList.add('fullscreen');
      }
    } else {
      for (var i = 0; i < elems.length; i++) {
        elems[i].classList.remove('fullscreen');
      }
    }
  }

The only thing I need is to implement the isFullScreen()-function. Browser api’s are available – implemented somewhat differently across browsers. Safari has document.webkitCurrentFullScreenElement which resolves to the element that initiated the full screen mode (if the browser is in fullscreen mode). For cross-browser compatibility, this would be sufficient:

  // Check if browser is full screen
  function isFullScreen() {
    // Safari?
    if (typeof(document.fullscreenElement) === 'undefined') {
      if (document.webkitCurrentFullScreenElement == null) return false;
    }
    if (document.fullscreenElement == null) return false;
    return true;
  }

Is there a snag? Of course there is. In order for the code above to return true, the browser window MUST be put in full-screen mode by an element on the page. If the browser was put in full-screen mode from the browser menu or from a command-line argument when the browser was started, there is no document.webkitCurrentFullScreenElement and the function will return false and my controls are still visible on the page.

Third try: Look at window position

I stumbled across this post on Stackoverflow with the bold intro: This works on all new browsers. Being desparate i gave it a go:

// Check if browser is full screen
  function isFullScreen() {
    return (!window.screenTop && !window.screenY);
  }

Crossing fingers… and getting close. In Google Chrome, both the button on the page and the menu action makes this function return true. The menu action to return from full-screen mode however seems to trigger no window.resize-event, hence the controls remain hidden when I leave full-screen mode from the browser menu. Digging further into this, it seems the resize is triggered, but window.ScreenTop and/or window.screenY are. updated with a delay. So by adding a one second delay after the resize-event is triggered, before checking if the browser is full-screen with the function above everything seems to work!

So the code to it’s full extend ended up as:

  function showHero() {
    elems = document.querySelectorAll('body');
    var fs = isFullScreen();
    if (fs === true) {
      for (var i = 0; i < elems.length; i++) {
        elems[i].classList.add('fullscreen');
      }
    } else {
      for (var i = 0; i < elems.length; i++) {
        elems[i].classList.remove('fullscreen');
      }
    }
  }

  // Check if browser is full screen
  function isFullScreen() {
    return (!window.screenTop && !window.screenY);
  }

  showHero();
  window.onresize = function() {
    // wait 300ms to allow for the window positions to update
    setTimeout(showHero, 300);
  };

Timing was tested on MacOS with Safari, Chrome and Firefox – tried lowering it to 100ms, but Firefox did not finish animating/updating the window.screenTop and window.screenY so a 300ms delay seems to do the trick.

One thing i can live with for now: The check also triggers when the window is maximized – not just full-screen.

Maybe I should just show the controls if there is mouse or keyboard activity and hide them after 30 seconds of inactivity?