Popup / Modal windows / Dialog boxes made easy

[First post about "teaching what I learned" (as suggested by Move The Web Forward and Louis Lazaris on Smashing Magazine). And first post in English (as suggested by Lea Verou).]

tl;dr: Some code for modal windows. Check the demo and copy the code.

So, modal windows. Or popups. Or dialog boxes. Call them what you like, what I’ll be talking about in this post are those parts of a page that appear “over” the actual content of the rest of the page, somehow hiding it in the background.

Modal window

There are tons of plugins and scripts out there to achieve this, some very big, some very small, and many of them good (my current favorite – for images – is Shadowbox), but in the end you might just want to use a simpler solution that you can easily adapt to your needs.

The simplest code I’ve come down to, by trial and error in various sites, is just a few lines of CSS and a few lines of JavaScript (jQuery).

The CSS:

.behind { 
    overflow: hidden;
 }

.curtain {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    background: #fff;
    background: rgba(255,255,255,.8); 
    z-index: 1001; 
}

.modal {
    position: absolute;
    width: 20%;
    height: 20%;			
    left: 50%;
    top: 50%;
    margin: -10% 0 0 -10%;			
    background: #fff;			
    border: 2px solid brown;
    border-radius: 5px;
    color: #000;
    font-weight: bold;
}

The behind class must be applied to the body through JavaScript, to make its scrollbar disappear (scrolling there wouldn’t make much sense, since the content of the page becomes like a background image when the modal window is open. Also, you might wind up with two scollbars, if the modal window itself is high enough to get its own scrollbar).

The curtain appears when you click on a hook link and just covers the rest of the page with a semi-transparent overlay (for browsers that don’t support rgba there’s a full white fallback background. If transparency is really important you can use a semi-transparent image in the first background declaration.) Of course you’ll need to set a z-index higher than the highest used in the rest of the page. The element is fixed in the page, so when you close it you’ll find the page with the same offset it had before opening it. This is good in case of long pages… I’ve seen code that takes you back to the top of the page, and that’s not cool.

The modal class must be applied to the element with the actual content of the modal window. It can be anything (photo, text, video, whatever), in this case I’m just making it a box, centered both vertically and horizontally throught the usual top/left/margins “trick”. The rest is just cosmetic styling. What’s important to understand here is that it can really be anything, and be positioned anywhere… inside of the curtain. That’s what makes it easy and elegant, the modal is inside the curtain.

In the HTML you only need the hook link:

<a class="go-modal" href="/modal-content.html">Open the modal window</a>.

The href attribute should be real and its value should be the address of a stand-alone page with the same content as the popup. For search engines, for people with disabled JavaScript and also, possibly, for mobile users for whom you might want to disable the popup behaviour entirely since often popups don’t make much sense in small resolutions.

Finally, a few lines of JavaScript:


$('.go-modal').click(function(e) {
    e.preventDefault();
    $('body').addClass('behind').append('<div class="curtain"><div class="modal">Yay, I\'m a modal! I rule!</div></div>');
});

$(document).on('click', '.curtain', function(e) {
    $('body').removeClass('behind');
    $(this).remove();
});

$(document).on('click', '.curtain .modal', function (e) {
    e.stopPropagation();
});

When you click on the hook link the behind class is added to the body and the curtain is appended, with its child modal element, to it. I’ll be using divs in the demo, but you can use whatever makes sense for your page… sections, articles, anything.

Then you need to close the curtain when you click on what now is the “background” of the page, outside of the modal window. When you click there you remove the behind class from the body and remove the curtain (and so its child) completely.

You also need to address propagation… since modal is curtain‘s child, even clicking inside of it would trigger the previous function and close everything and you don’t want that. Luckily you can stop propagation with (you guessed it) stopPropagation. You have to use jQuery’s .on for these functions (and not simply .click) because modal and curtain were added dynamically.

To disable this behaviour on mobile just adding a simple width condition like if ($(window).width() >= 480) around the JavaScript functions should work.

And that’s it! The code being this simple makes it very easy to modify and adapt to your particular needs.

Go check a simple demo page.

Browser support: All modern browsers and IE7+ (maybe IE6 too, I haven’t had the chance to test it. Of course there can be no semi-transparency at all in IE6, but the rest should work).

3 Comments

  1. Hey, Franceso!

    Glad to hear my post inspired you. And good job on this simple solution.

    I’ll just point out one small thing (I recently learned this too): The jQuery “live()” method is now deprecated in jQuery 1.7, so the preferred alternative is “on()” (which you used elsewhere in the code). See:

    http://api.jquery.com/live/

    Of course, I’m not sure why you used both? Does live() have some other function that I don’t know about? I’m not an expert on jQuery, but was curious why you didn’t use on() for both click events?

Leave a Reply

Required fields are marked *.