Cross-browser, CSS-only modal box

A modal box — or  “modal window” — is a custom dialog box that grays out the rest of the page when it’s active. it lets a site provide additional content without forcing the user to load a new page.

Clicking on a “Contact us” link might pop up up a modal containing the contact form, rather than taking the user to a separate page. The modal lets the user fill out the form, close the window, and resume browsing the page where they left off.

For example, the image below is what you’ll see if you hover over the “ShareThis” button at the bottom of this post.

Example of a modal window

On a recent project we needed a modal box that would work on all desktop browsers and mobile devices as well. We ran into two mutually-exclusive problems with existing solutions:

  1. Modals that rely on javascript to position themselves don’t always play well with mobile devices. They use javascript to calculate their position in the viewport, and more often than not that means they center themselves in a viewport that is wider than the mobile-phone screen.
  2. Many CSS-only modal boxes use CSS3 properties that are poorly supported on older browsers.

Rather than modify somebody else’s code, we came up with our own.  The result is a modal that uses javascript only for the show/hide work. Everything else is pure HTML/CSS. It works well on all devices and browsers, including older versions of IE.

Since it has no dynamic code, we dubbed it “dumb box.”

The basic HTML:

<div class="dumbBoxWrap">
    <div class="dumbBoxOverlay">
    <div class="vertical-offset">
        <div class="dumbBox">
            Content goes here

The CSS:

.dumbBoxWrap { /* The div that shows/hides. */
    display:none; /* starts out hidden */
    z-index:40001; /* High z-index to ensure it appears above all content */
.dumbBoxOverlay { /* Shades out background when selector is active */
    opacity:.5; /* Sets opacity so it's partly transparent */
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; /* IE transparency */
    filter:alpha(opacity=50); /* More IE transparency */
.vertical-offset { /* Fixed position to provide the vertical offset */
    z-index:40002; /* ensures box appears above overlay */
.dumbBox { /* The actual box, centered in the fixed-position div */
    width:405px; /* Whatever width you want the box to be */
    margin:0 auto;
    /* Everything below is just visual styling */
    border:1px solid black;

The JavaScript:

You just need a simple script that changes “.dumbBoxWrap” to “display:block;” when the “open” link is clicked, and back to “display:none;” when “close” is clicked. In jQuery, it might look something like this:

<script type="text/javascript">
    $(document).ready(function() {
        //Show modal box
            function() {$('.dumbBoxWrap').show();}
        //Hide modal box
            function() {$('.dumbBoxWrap').hide();}
<a id="openModal">Open</a>
<a id="closeModal">Close</a>

How it works

When trying to center things in a browser window, we run up against two issues:

  1. Divs with “position:fixed;” respond to the browser window, but cannot have automatic left-right margins.
  2. Divs with “position:relative;” can have automatic left-right margins, but can’t do automatic vertical margins, and don’t pay attention to the browser window.

The Dumbbox solves that problem by combining a fixed-position div with a relative-position div to center an object in both dimensions.

.dumbBoxWrap is just a div that wraps around everything else so it can be easily shown/hidden all at once. It has a very high z-index to ensure it appears above all other content.

.dumbBoxOverlay is the background shading. By giving it “position:fixed;” and setting its width and height to “100%”, we ensure it fills the entire viewport. We then give it a background color and change its opacity to make it semi-transparent. You could accomplish the same effect by giving it a semi-transparent background image.

.vertical-offset positions the modal box vertically. It’s a fixed-position div with a width of “100%”, so it’s always as wide as the viewport. The vertical offset (“30%” in this case) lets it be more-or-less centered vertically. Adjust the percentage based on the depth of the box you’re using. It has a z-index that is slightly higher than .dumbBoxOverlay to ensure it appears above the overlay.

.dumbBox is the actual modal itself. It’s just a regular div with a fixed width and “margin:0 auto;”. That makes it center itself horizontally within .vertical-offset — and since .vertical-offset is always the full width of the viewport, that means .dumbBox is always perfectly centered in the viewport. The vertical positioning is already taken care of by .vertical-offset.

Where to put it

The dumb box HTML should go inside the <body> tag but outside any other content. I usually put them right before the closing </body> tag, so that loading the modals doesn’t delay showing the rest of the page.

Adding a close icon

To close out, let’s add a jazzy lightbox-style close icon in the upper right corner of the modal.

First, create an icon. We’ll use the one on the left in this example. You can use it too, if you want.  close modal window

Then make it your close link:

    <a id="closeModal"><img src="PATH_TO_modal_close.png"/></a>

Alternatively, you could make it the link’s background image.

Put the <a> tag inside your modal content, and then give it some CSS to position it:

    #closeModal {
        top:-12px; /* Half the icon's height */
        right:-12px; /* half the icon's width */

The center of the icon should now be centered on the upper right corner of the modal.

13 thoughts on “Cross-browser, CSS-only modal box

    1. Rumple4skin

      @Josh, caution using code verbatim.
      Try updating the selectors from .dumbboxWrap to .dumbBoxWrap. js can be finicky when it doesn’t match html/css.
      @ Steven, you may want to add — position:absolute; top: 0;left: 0; — to .dumbBoxWrap to ensure the overlay is placed correctly.

      1. Steven Ray Post author

        @ Rumple, thanks for catching the typo in my jQuery example. It’s now fixed.

        The suggestion to add position:absolute is well-taken, but it’s not foolproof. The best practice, I think — which I did not make clear — is to make sure that the .dumbBoxWrap div isn’t placed inside another div. It should be inside the body tag, but separate from all other content.

    1. Steven Ray Post author

      @Sally: You would assign a unique ID to each popup, and then show/hide popups using that ID instead of the .dumbBoxWrap class. (You’d have to assign unique IDs to the show/hide buttons, too).

      1. Steven Ray Post author

        The buttons have IDs so jQuery knows which button has been clicked. The modals have IDs so jQuery knows which modal to open (the jQuery basically says, “if button #1 is clicked, open modal #1″).

        But jQuery can identify buttons by any attribute you want, including class.

        So yes, the buttons can all open the same modal. Instead of an ID on the buttons, I’d use a class. Then I’d modify the jQuery to use that class. That way, any time a button with that class is clicked, it opens the modal.

  1. Steven Ray Post author

    Yes, that’s the one drawback of this approach. Remember, the goal was a CSS-only modal box. There’s no CSS-only way to automatically adjust to the vertical sweet spot.

    That said, you’re setting the offset as a percentage. So it’s a little dynamic. If your modal boxes are roughly the same depth (and they’re modal boxes; they shouldn’t be very deep), you can set that position so it will more-or-less center itself vertically in the browser window regardless of the depth of the browser window.

  2. jareis

    i would suggest a minor change, if i may.


    then in jQ/js side, something like:
    ‘click': function (){

    This way you will fully separate CSS styles from content.

    1. Steven Ray Post author

      That works if you’re using the same button(s) to show/hide the modal. You could do the same thing with my code, while preserving separate buttons, by adding/removing the “active” class in my jQuery instead of using “show()” and “hide()”. My only criticism is that this seems like unnecessary code. As long as I’m using jQuery to add a class that shows/hides things, why not just have the jQuery do the show/hide directly?

  3. Steven Ray Post author

    Nice extensions of the basic box. Yes, for dynamic content you need to use an ID and clear any existing content before appending the dynamic content. And the ESC key code is a nice touch. Thanks for sharing!


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>