Opaque the Background When Displaying a Popup

A HunBug Document
Document No.: 11420
Last Updated: 01 Feb 2009
Author: HunBug

To help emphasise a popup element in a web page, it can often help to grey out the background. This highlights the popup and focuses the users’ attention to the area. This example lays an div element on top of the main page when a popup element is displayed, making the popup modal as the user has no control of the main page elements.

We achieve this using Javascript with (as always) a little css and html.

The HTML

This example page contains the greyout functions, along with the popup div code and styling.
It also makes use of dynamic event handling (see: Javascript Dynamic Event Handling) and DOM manipulation to create the greyout div at runtime (see: DOM Append Text and Element Functions)

<html>
  <head>
 
    <style type="text/css">

      .popup {
        border: solid 1px #333;
        font-family: Tahoma, Verdana, Arial, Helvetica, sans-serif;
        font-size: 12px;
        display: none;
        position: absolute;
        width: 300px;
        z-index: 60;
      }

      .popuptitle {
        background: blue;
        color: white;
        font-weight: bold;
        height: 15px;
        padding: 5px;
      }
     
      .popupbody {
        background: #ddd;
        padding: 5px;
        text-align: center;
      }

      #popup { top: 100px; left: 50px; }

    </style>

    <script type="text/javascript">

      //----------

      function addEvent(obj ,evt, fnc)
      {
        if (obj.addEventListener)
          obj.addEventListener(evt,fnc,false);
        else if (obj.attachEvent)
          obj.attachEvent('on'+evt,fnc);
        else
          return false;
        return true;
      }

      function removeEvent(obj ,evt, fnc)
      {
        if (obj.removeEventListener)
          obj.removeEventListener(evt,fnc,false);
        else if (obj.detachEvent)
          obj.detachEvent('on'+evt,fnc);
        else
          return false;
        return true;
      }

      //----------

      function appendElement(node,tag,id,htm)
      {
        var ne = document.createElement(tag);
        if(id) ne.id = id;
        if(htm) ne.innerHTML = htm;
        node.appendChild(ne);
      }

      //----------

      function showPopup(p)
      {
        greyout(true);
        document.getElementById(p).style.display = 'block';
      }

      function hidePopup(p)
      {
        greyout(false);
        document.getElementById(p).style.display = 'none';
      }

      //----------

      function greyout(d,z)
      {
        var obj = document.getElementById('greyout');

        if(!obj)
        {
          appendElement(document.body,'div','greyout');
          obj = document.getElementById('greyout');
          obj.style.position = 'absolute';
          obj.style.top = '0px';
          obj.style.left = '0px';
          obj.style.background = '#111';
          obj.style.opacity = '.5';
          obj.style.filter = 'alpha(opacity=50)';
        }
        if(d)
        {
          var ch = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
          var cw = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth;
          var sh = document.documentElement.scrollHeight ? document.documentElement.scrollHeight : document.body.scrollHeight;
          if(document.body.scrollHeight) sh = Math.max(sh,document.body.scrollHeight)
          var sw = document.documentElement.scrollWidth ? document.documentElement.scrollWidth : document.body.scrollWidth;
          if(document.body.scrollWidth) sh = Math.max(sh,document.body.scrollWidth)
          var wh = window.innerHeight ? window.innerHeight : document.body.offsetHeight;
          if(!z){ z = 50 }
          obj.style.zIndex = z;
          obj.style.height = Math.max(wh,Math.max(sh,ch))+'px';
          obj.style.width  = Math.max(sw,cw)+'px';
          obj.style.display = 'block';
          addEvent(window,'resize',greyoutResize);
        }
        else
        {
          obj.style.display = 'none';  
          removeEvent(window,'resize',greyoutResize);
        }
      }

      function greyoutResize()
      {
        var ch = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
        var cw = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth;
        var sh = document.documentElement.scrollHeight ? document.documentElement.scrollHeight : document.body.scrollHeight;
        if(document.body.scrollHeight) sh = Math.max(sh,document.body.scrollHeight)
        var sw = document.documentElement.scrollWidth ? document.documentElement.scrollWidth : document.body.scrollWidth;
        if(document.body.scrollWidth) sh = Math.max(sh,document.body.scrollWidth)
        var wh = window.innerHeight ? window.innerHeight : document.body.offsetHeight;
        var obj = document.getElementById('greyout');
        obj.style.height = ch+'px';
        obj.style.width  = cw+'px';
        obj.style.height = Math.max(wh,Math.max(sh,ch))+'px';
        obj.style.width  = Math.max(sw,cw)+'px';
      }

      //----------

    </script>

  </head>
  <body>

    <input type="button" value="Show Popup" onClick="showPopup('popup')"/>

    <div id="popup" class="popup">
      <div class="popuptitle">Modal Popup</div>
      <div class="popupbody">
        <p>No links or functionality on the main page should be accessible until this popup is closed.</p> 
        <input type="button" value="Hide Popup" onClick="hidePopup('popup')"/>
      </div>
    </div>

  </body>

</html>
 

How it Works

When the button is pressed it calls the showPopup function, with the id of the element we wish to display. This function then calls the greyout function.

function greyout(d,z)
{
  var obj = document.getElementById('greyout');

  if(!obj)
  {
    appendElement(document.body,'div','greyout');
    obj = document.getElementById('greyout');
    obj.style.position = 'absolute';
    obj.style.top = '0px';
    obj.style.left = '0px';
    obj.style.background = '#111';
    obj.style.opacity = '.5';
    obj.style.filter = 'alpha(opacity=50)';
  }
  if(d)
  {
    var ch = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
    var cw = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth;
    var sh = document.documentElement.scrollHeight ? document.documentElement.scrollHeight : document.body.scrollHeight;
    if(document.body.scrollHeight) sh = Math.max(sh,document.body.scrollHeight)
    var sw = document.documentElement.scrollWidth ? document.documentElement.scrollWidth : document.body.scrollWidth;
    if(document.body.scrollWidth) sh = Math.max(sh,document.body.scrollWidth)
    var wh = window.innerHeight ? window.innerHeight : document.body.offsetHeight;
    if(!z){ z = 50 }
    obj.style.zIndex = z;
    obj.style.height = Math.max(wh,Math.max(sh,ch))+'px';
    obj.style.width  = Math.max(sw,cw)+'px';
    obj.style.display = 'block';
    addEvent(window,'resize',greyoutResize);
  }
  else
  {
    obj.style.display = 'none';  
    removeEvent(window,'resize',greyoutResize);
  }
}

The greyout function accepts two parameters.

  • d: This is the display parameter, it is boolean and should be true for activating and false for deactivating..
  • z: This is the z-index value for the greyout element, to enable the greyout to be forced to be below the popup. The function defaults the z-index element to 50, if the parameter is omitted, so the popup should have a higher z-index property.

The function first checks whether the greyout element exists. If it does not, it creates it by appending the element to the document body. It then sets the style properties for the new element. This will only happen for the first time the function is called.
There are two style properties to set the opacity of the div, opacity and filter. Safari and Mozilla browsers support "opacity", which requires a fraction value. Internet Explorer does not recognise the "opacity", so we use the filter property with "alpha(opacity=50)" option, which requires a percentage value.

The dynamic creation allows you to use the greyout functionality by simply adding the functions to the page or attached Javascript library, without the need for html or css modifications.

The function then checks to see whether to display or hide the greyout div element. When it is displayed the height and width needs to be set, so that it covers the page. As the page can be larger or smaller than the viewing area we need to always cover the larger value.

As the greyout div has a defined size, it needs to be recalculated should the window be resized. To do this we need to attach an function to the window resize event. When the window is resized we call the greyoutResize function.

function greyoutResize()
{
  var ch = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;
  var cw = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth;
  var sh = document.documentElement.scrollHeight ? document.documentElement.scrollHeight : document.body.scrollHeight;
  if(document.body.scrollHeight) sh = Math.max(sh,document.body.scrollHeight)
  var sw = document.documentElement.scrollWidth ? document.documentElement.scrollWidth : document.body.scrollWidth;
  if(document.body.scrollWidth) sh = Math.max(sh,document.body.scrollWidth)
  var obj = document.getElementById('greyout');
  obj.style.height = ch+'px';
  obj.style.width  = cw+'px';
  obj.style.height = Math.max(wh,Math.max(sh,ch))+'px';
  obj.style.width  = Math.max(sw,cw)+'px';
}

This function is only called from the greyout function and just recalculates the greyout div width and height. The height and width are set twice, as when the window is reduced, the scroll height and width values take into account the size of the greyout div, which are larger than the reduced window size. Here they are reduced before the scroll sizes are checked.
This does not work for Internet Explorer, so scrollbars are sometimes unecessarily added to the window when it is reduced.

When the greyout div is hidden the window resize event function is removed.

In Action

This test is based on the example code above. Press the button to show the greyout div with popup element above.

Further Reading

HunBug: DOM Append Text and Element Functions
HunBug: Javascript Dynamic Event Handling
HunBug Store








Comments are all individually read, none are automatically posted to the site.
Popup Modal Window

No links or functionality on the main page should be accessible until this popup is closed