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">
        &nbsp;
    </div>
    <div class="vertical-offset">
        <div class="dumbBox">
            Content goes here
        </div>
    </div>
</div>

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 */
    position:fixed;
    width:100%;
    height:100%;
    background-color:black;
    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 */
    z-index:40001;
}
.vertical-offset { /* Fixed position to provide the vertical offset */
    position:fixed;
    top:30%;
    width:100%;
    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 */
    position:relative;
    margin:0 auto;
    /* Everything below is just visual styling */
    background-color:white;
    padding:10px;
    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
        $('#openModal').click(
            function() {$('.dumbBoxWrap').show();}
        );
        //Hide modal box
        $('#closeModal').click(
            function() {$('.dumbBoxWrap').hide();}
        );
    });
</script>
<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 {
        position:absolute;
        top:-12px; /* Half the icon's height */
        right:-12px; /* half the icon's width */
        z-index:50;
    }

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

32 comments on “Cross-browser, CSS-only modal box

  1. I tried this code verbatim and nothing happens when I click on “open”

    • Steven Ray on said:

      Do you have jQuery installed on the page? The open/close code is in jQuery. You can use the copy hosted by Google at this link:
      https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js

    • Rumple4skin on said:

      @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.

      • Steven Ray on said:

        @ 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.

  2. Angelo on said:

    Nice job! Well written article and the HTML coincides with the css markup so it’s easy to follow.

  3. STUCK! How do you do multiple popups on a single page?

    • Steven Ray on said:

      @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).

      • Is this required even when the modal is the same?

        For example, if I have a sign up link on the top of a page, and a sign up link on the bottom of a page, can they both go to the same modal? Or are unique ID’s necessary?

        In my case, the amount of ‘open’ buttons will de dynamically generated, so depending on the user, there will be a different number of buttons. But they would all open the same modal.

        Help?

        • Steven Ray on said:

          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.

  4. CSS User on said:

    Hi,
    First: Great Modal Box !
    But I found a bug that rather spoiled it for me.
    I set the jquery so it would close the box when the bumbBoxOverlay is clicked.

    However this doesn’t work if clicking on the left or the right off the dumbbox, as the margin 0 auto that centers it also catches the clicks so they go to the dumbbox instead of the overlay.

    Any suggestion to build this up otherwise so it could be working ?

  5. CSS User on said:

    If we always need to set the vertical offset’s top: manually, it isn’t really a Modal Box that automatically adjusts to the vertical sweet-spot.

    • Steven Ray on said:

      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.

  6. cherriemerrie on said:

    Nice. Just a typo in “.dumbBox{}” class where:

    //Everything below is just visual styling */
    should be:
    /*Everything below is just visual styling */

  7. Love this script, easy but smart and works like a charm ….
    Here is couple of notes that might come useful:

    1. to properly overlay existing content with semitransparent background, add left and top properties

    .dumbBoxOverlay {
    left: 0;
    top: 0;
    }

    2. if you want to load dynamic content into modal, the easiest way is to add link into link to modal

    and update javascript with
    //Show modal box
    jQuery(‘.openModal’).click(function() {
    var link = jQuery(this).attr(‘href’);
    jQuery(‘.dumbBox’).html(”); /* delete previous modal content */
    jQuery(‘.dumbBox’).load(link);
    jQuery(‘.dumbBoxWrap’).show();
    return false; /* prevents opening href in full page */
    });

    … as you can see, I have changed openModal from id to class to be able to easily populate it on many elements within one page

    3. to close modal by ESC key add following javascript below existing script (not into $(document).ready… statement. Below.

    // Close modal by ESC key
    jQuery(document).keyup(function(e) {
    if (e.keyCode == 27) {
    jQuery(“.dumbBoxWrap”).fadeOut(500);
    }
    });

    4. if the script didn’t work at all, rewrite all jquery statements starting with dollar sign from
    $(‘.something…
    to
    jQuery(‘.something…

    Anyway, thanks for the script, it saved me lots of time. I hope my notes will do the same for others :)

    • Steven Ray on said:

      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!

    • cheryl on said:

      Thanks both of you for these!

      I did find with my code the ESC function had some trouble so I just needed to change the double quotes in the jQuery(“.dumbBoxWrap”).fadeOut(500); to single quote and it worked perfectly:


      // Close modal by ESC key
      jQuery(document).keyup(function(e) {
      if (e.keyCode == 27) {
      jQuery('.dumbBoxWrap').fadeOut(500);
      }
      })

  8. great.
    i would suggest a minor change, if i may.

    CSS:
    .dumbBoxWrap.active{
    display:block;
    }

    then in jQ/js side, something like:
    $(‘#close-btn’).on({
    ‘click': function (){
    $(‘.dumbBoxWrap’).toggleClass(‘active’);
    }
    });

    This way you will fully separate CSS styles from content.

    • Steven Ray on said:

      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?

  9. Sania Reddy on said:

    Hi,
    I am creating a website for my first time and used the code provided here to create 2 modal windows on one page. In another page where there was only modal window, it worked like a charm. But in this page, only the first modal window gets displayed. I gave different id’s to both the modal windows and to the buttons but it still doesn’t display the second modal window. I placed these code at the bottom of the body tag, one after another. Please, could you explain where I would have gone wrong?

    Regards,
    Moon.

    P.S. Thank you so much for the code. Its awesome. ^-^

    • Steven Ray on said:

      Did you adjust the jQuery? You need it to listen for a click on Button #1, and then open Modal #1. You need a separate listener for a click on Button #2, which opens Modal #2.

  10. Sania Reddy on said:

    May I have your email address to send you the code.?

    • Steven Ray on said:

      Sania, I put up a page with the code you sent me here:
      http://designpoodles.com/avtex/modal_test.php
      It works fine. So I’m wondering if there is something in one of your PHP includes that is breaking your layout — like an unclosed div tag.

      • Sania Reddy on said:

        Thank you for checking the code out for me and no I checked again after your advice and there are no unclosed div tags. Can you tell what other type of errors may block it from executing?

        • Sania Reddy on said:

          Thank you. I figured out where the problem was. Its the content of the modals themselves. I have a table within each modal which has 2 rows and columns of “require_once” code of including other php files. Do you have any advice..?

          • Sania Reddy on said:

            Nevermind. Its working now.
            Again, thank you for all your help. This is an easily understandable code than all the others out there.
            Thank you. ^-^

  11. S Zaman on said:

    if I put modal div just before the closing body tag, the overlay goes down the all other elements. Pls help.

  12. This all seems to be working except the background shader. For some reason it doesn’t black out the background even though I copied the code accurately. Any ideas?

    Thanks for this simplistic approach!

Leave a Reply

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

*

* Copy This Password *

* Type Or Paste Password Here *

102,266 Spam Comments Blocked so far by Spam Free Wordpress

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>