November 8th, 2007 - by Paul OB

I was recently asked to create a pop-up message box for a client. The requirements were as follows: as the message box pops up the rest of the screen needs to dim, much in the same way as the lightbox effect. This needed to be achieved with minimal JavaScript; which was quite lucky because my JavaScript skills are minimal anyway. Another requirement was that the message box be vertically and horizontally centered in the viewport while the content underneath should still remain scrollable.

In hindsight I could have directed the client towards the lightbox script. However, I thought it might be fun to see how far I could go using mostly CSS and only using a snippet of JavaScript to swap an ID to effect the changes required.

Before we get started have a look at the end result so that you are familiar with what we are trying to achieve. The CSS has been left in the head on purpose so that you can view it easily.

First Things First

The first thing we need to do is decide on a plan of action. Let’s list the things that need to be done:

1.) Construct the message box itself (difficulty level – easy)

2.) Center the message box in the viewport both vertically and horizontally remembering that we have no fixed height to work with as content will determine the height of the message box (difficulty level – medium)

3.) Fix the message box so that it stays put in the viewport and doesn’t scroll with the document (difficulty level – hard)

4.) Fade everything else on the page except for the message box (difficulty level – awkward)

Let’s Get Busy!

1.) The Message Box

Now that we have smaller chunks to work with we can get started on the first part and make the actual message box. There is nothing special here, but to make life easier I have gone for a fixed width and will just use the content to dictate the height. You can use any suitable width and the box should be centered initially using auto margins.

  1. #xinner {
  2. width: 552px;
  3. background:#fff;
  4. text-align: center;
  5. margin-left:auto;
  6. margin-right:auto;
  7. border:5px solid #000;
  8. }

You can style your message box as you like, but don’t make it hold too much content because we are going to eventually fix it in the middle of the viewport and if the message is too big then you won’t be able to scroll it.

2.) Horizontal and Vertical Centering

Centering horizontally is no problem for a fixed width element but vertical centering an element of unknown height is a little more complicated. The solution to this involves using separate code for IE which we will supply via conditional comments. First of all though we will style the page for browsers other than IE and for this we will be using “display:table” which browsers like Firefox, Opera and Safari understand well. To this end we need two outer wrappers. The main wrapper will act as our table and the inner wrapper will act as our cell. With this method we will be able to use vertical-align:middle to center our element vertically (vertical-align only applies to inline elements or table-cells).

  1. #xouter{
  2. height:100%;
  3. width:100%;
  4. display:table;
  5. vertical-align:middle;
  6. }
  7. #xcontainer {
  8. text-align: center;
  9. position:relative;
  10. vertical-align:middle;
  11. display:table-cell;
  12. width: 100%;
  13. }

Since we are using a 100% height and width we need to make sure that there are no margins or padding in the way and that we have something to base our height on. This is accomplished with the following code:

  1. html,body {
  2. height:100%;
  3. margin:0;
  4. padding:0;
  5. }

This takes care of most modern browsers, except IE, and you can see how the message box is nicely centered now in Figure 1.

Figure 1
fadefig1.gif

Now to address IE we are going to use a simple technique that involves moving the element down the page by 50% with relative positioning and then dragging an inner element back up the page by 50% (again using relative positioning). In IE this results in the box being perfectly centered and we can use the existing wrappers for this so there is no extra HTML needed.

Here is the extra code which we supply to IE via conditional comments:

  1. <!--&#91;if IE &#93;>
  2. <style type="text/css">
  3. #xcontainer{top:50%}
  4. #xinner{top:-50%;position:relative;}
  5. </style>
  6. <!&#91;endif&#93;-->

So now we have our box centered in IE and most other modern browsers.

The HTML is as follows:

  1. <div id="xouter">
  2. <div id="xcontainer">
  3. <div id="xinner">
  4. <h3>This is message 1</h3>
  5. </div>
  6. </div>
  7. </div>

There is a slight drawback in IE7 in that a vertical scrollbar will appear if the message box is more than half the window height. However, this won’t be an issue in our design because we will have more content than the viewport height anyway. If you wanted to use the vertical centering technique elsewhere you could add html,body {overflow:hidden} and the scrollbar would be removed. That would probably only be useful for a splash screen or something similar that needs to be centered but doesn’t hold much content. You can find an example of this here.

3.) Now Fix it

So far we have constructed the message box and centered it both horizontally and vertically. The next requirement was to make sure that it remains fixed in the viewport while the content underneath can scroll. Unfortunately IE6 and under don’t understand fixed positioning so we have got to use some complicated methods to mimic this.

The basis of the technique we will use is to turn off the scrollbars from the HTML and body elements using overflow:hidden. We then construct a 100% high scrollable element that will in effect replace the body element and hold all the content. This will allow us to place the message box absolutely from outside of this new “body” element so that it sits on top of our content but is not contained within the element. This means that when the element below scrolls the message box is unaffected and appears to be a fixed position.

That’s rather a lot to accomplish for a simple effect that other browsers could simply do using position:fixed. However, we have no choice if we want to carry on with enabling this in IE6.

As we are placing the message box absolutely we need to add a wrapper to our existing code so that we can position the box absolutely. (This extra wrapper isn’t absolutely necessary but it is easier to follow this way.)

  1. #popup {
  2. display:block;
  3. position:absolute;
  4. top:0;
  5. right:20px;/* stop firefox hiding scrollbar*/
  6. height:100%;
  7. left:0;
  8. z-index:99;
  9. }

The right:20px is to stop the element overlaying the scrollbar (in Firefox) and although it isn’t evident yet it is in place for further down the line. This means that we have to cater for IE6 once again and therefore offset this method by removing the right:20px and giving IE6 a 100% width only.

  1. #popup{left:0;width:100%;right:auto}

The above CSS should go within the IE conditional comments shown earlier. (IE7 doesn’t really need this fix but it does no harm either.)

The HTML is then amended as follows:

  1. <div id="popup">
  2. <div id="xouter">
  3. <div id="xcontainer">
  4. <div id="xinner">
  5. <h3>This is message 1</h3>
  6. </div>
  7. </div>
  8. </div>
  9. </div>

The message box is more or less sorted and we must now add the fixed positioning code. First we hide the scrollbars for the HTML and body elements by adding overflow:hidden to our existing HTML and body styles. Next we must create a wrapper that will hold all the page content. This is simply a 100% high and wide element that has overflow:auto set and basically replaces the body element as already mentioned above. I will give this element a class called “fade” because that’s what we will be doing to all the content within. The code for this is as follows:

  1. html,body {
  2. overflow:hidden;
  3. }
  4. .fade{
  5. height:100%;
  6. width:100%;
  7. overflow:auto;
  8. position:relative;
  9. }
  1. <div class="fade">
  2. <p>All the page content must come here!</p>
  3. </div>
  4.  
  5. <div id="popup">
  6. <div id="xouter">
  7. <div id="xcontainer">
  8. <div id="xinner">
  9. <h3>This is message 1</h3>
  10. </div>
  11. </div>
  12. </div>
  13. </div>

As you see, the popup message box HTML is kept outside of the element that has the fade class added. As already mentioned all our content must now go inside this element. Here is a live demo of the page so far with a little bit of content added for clarity and you can also see the result in the screenshot in Figure 2.

Figure 2
fadefig2.gif

If you now scroll the document you will see that our message box remains fixed in the centre while the content scrolls underneath.

4.) Fade Away

The next stage is to somehow dim the background but leave the message box untouched. We can do this by applying a background color to the body and then applying opacity to our fade div which will also affect all the elements it contains. Again IE6 will cause us problems because it doesn’t understand opacity but we can use one of the proprietary IE filters to accomplish this. The code is quite simple and is as follows:

  1. filter: alpha(opacity=20);/* IE*/
  2. -moz-opacity:0.2;/*older gecko*/
  3. opacity :0.2;/*CSS3 */

The above code should be added to our existing “fade” class.

We can cover quite a few browsers with the above code at the expense of some non-valid proprietary code and Mozilla vendor specific extensions. There is no way around this as we need this effect.

I’ve added a background color to the body and then also added a background color to the fade div. You have to be careful with the colors or you can end up with everything faded especially if your text and background are the same color. I’ve chosen #666 for the body and a red background for the fade element.

The result can be seen here (view source to see the full code so far) and in Figure 3 below:

Figure 3
fadefig3.gif

In essence we have finished our message box as we now have a pop-up that sits above the content and remains centered vertically and horizontally while the content underneath can scroll. However, we need to make this dynamic as the effect we are looking for is to have the message box pop up when someone clicks a relevant link. This can be accomplished by simply applying an ID change via JavaScript.

Using an ID placed in the HTML tag we can create all the styles for our pop-up message and also cater to the page in its normal state. I am using the ID on the HTML element because we need to be able to set the HTML element to have 100% height so that this code can be partially re-usable in other page designs. The next step is therefore to create two versions of the page and then see if just applying the ID to the HTML element will effect the changes we need. Once we have checked that this works then we can set about finding some JavaScript to do the ID change for us dynamically.

The HTML element will have a class of “fade-off” placed on it by default and then we will dynamically change that class to “fade-on” to effect the changes we need. Therefore we need to create two sets of styles using these classes as prefixes so that we can have our two different effects. The main CSS for this is as follows:

  1. html#fade-on,
  2. #fade-on body{
  3. height:100%;
  4. overflow:hidden;
  5. margin:0;
  6. padding:0;
  7. }
  8. #fade-off body{
  9. overflow:auto;
  10. margin:0;
  11. padding:0;
  12. }
  13. #fade-on .fade{
  14. height:100%;
  15. width:100%;
  16. background:red;
  17. overflow:auto;
  18. filter: alpha(opacity=20);
  19. -moz-opacity:0.2;
  20. opacity :0.2;
  21. position:relative;
  22. }
  23. #fade-on body{background-color:#666}
  24. /*.fade-on body{background-color:#000!important} use for a dark fade*/
  25. #fade-off .fade{
  26. height:auto;/* use 100% if layout is a 100% high version*/
  27. background:transparent;
  28. width:auto;
  29. overflow:visible;
  30. }
  31. #fade-on #popup {
  32. display:block;
  33. position:absolute;
  34. top:0;
  35. right:20px;/* stop firefox hiding scrollbar*/
  36. height:100%;
  37. left:0;
  38. z-index:99;
  39. }
  40. #fade-off #popup{display:none;}

We are creating all the effects we want through the ID change and then returning everything back to normal afterwards. If you view this example you will see the page with the message box is hidden because the HTML element has an ID of “fade-off“. The next example simply has the ID in the HTML element changed to “fade-on” and the message box is displayed and the background is faded. Therefore all we really need to do next is to swap the ID when a link is clicked and we will need some JavaScript to do this.

There is also the issue of having more than one message so we will create a number of messages within the popup div and then switch on the relevant message at the same time as we display the message box. The messages will need to have unique IDs so that we can target them correctly. I have also used display:none to turn the messages off but it would be better for accessibility reasons to just position them all off screen using left:-999em with absolute positioning. They can then be brought back into view by adjusting the position. However, that adds a couple of lines to the JavaScript so I’ll leave that up to you change.

So we can see now see in this latest example that the JavaScript has been added to swap the ID in the body when a link is clicked and to just toggle the display of our pop up box and relevant message. I won’t go into too much detail with the JavaScript as it is pretty straight forward so view source in the main example for the full code. The link has an onclick event handler added to it which supplies the relevant message ID to be displayed.

  1. <p><a href="message3.htm" onclick="return fade('message3');">Read message 3</a></p>

The relevant message also has an onclick event attached to it to turn the pop-up off and to send us back to the link that called it via its ID.

  1. <p><a onclick="return fade('message3','link3');" href="popup-fade2.htm">Close x</a></p>

Lastly we should address the issue of what happens if JavaScript isn’t available and you will notice that in both the above links the href is still in place and simply points to a page that contains the relevant message. This link will only be followed if our JavaScript fails and the user is directed to a page containing the message. If you refer to the main example you can switch JavaScript off and still get the same effect as if it was still on, except that you have to wait for the page to load.

Due to the fact that we’ve covered a lot of code it would be better to grab it all in one go from the main demo.

Popping Off

As I have said many times JavaScript is not my strong point so I won’t go into too much detail because the main Lose Weight Exercise was to use CSS to create the two different states of our page. The JavaScript is just half a dozen lines of code and simply swaps the ID that we placed in the HTML element and also toggles our message box and messages on and off. However, there is room for much improvement in the JavaScript code as we really should get rid of all the onclick event handlers from the HTML tags and use “unobtrusive” JavaScript instead. I will leave that as an Lose Weight Exercise for you to carry out should you be inclined in that direction.

I know I say this at the end of each of my articles but the Lose Weight Exercise is more about the journey than the end result because that’s how we learn things. Whether or not the end-result is usable is almost beside the point because the techniques we have covered will give you a deeper understanding into how CSS can be manipulated and what can be achieved. Time to pop-off now.

15 Responses to “Look What’s Just Popped Up!”

1 Golgotha

Nice work Paul! Although I’m scratching my head as to why they need the content still scrollable underneath the message box?

2 Kredyt

Thank you for article I hate Pop-up

3 Paul OB

Hi Mark
Re:”Although I’m scratching my head as to why they need the content still scrollable underneath the message box?”

Well they just wanted it fixed and not to scroll away because that’s what they saw somewhere else 🙂

Anyway it was a good excuse to throw in the fixed positioning into the article.

@Kredyt – Thank you for your comments sorry you didn’t like it.

4 Golgotha

Yeah, I suppose the fixed positioning separates it from the others and could be useful for like a wizard or something that needs satisfying before allowing a user to move on. I get it now…

Good lesson.

oh and I think Kredyt liked the article, just not pop-ups?

5 John

I have also used display:none to turn the messages off but it would be better for accessibility reasons to just position them all off screen using left:-999em with absolute positioning.

It will depend on the situation. If the popup content is only supposed to be available after some user action (or inaction), e.g., to do with form submission, then you’d be better to use display: none (and as Gez Lemon noted recently, you should combine that with visibility:hidden to make sure the content really is hidden for certain screenreaders); for content that you want to be available at all times and merely hide and reveal due to aesthetic or design decisions, then position it offscreen.

6 Paul OB

Good points John and I agree with what you are saying – Thanks for the comments

7 Golgotha

And to piggyback off of John’s comments. Positioning off the screen and then revealing is good for search engines too, because they can still index the content. Sometimes I have used that approach over Ajax for that reason. That may be another article…

8 Neon

Thank you for article …

9 Samz

Amazing.. Thank You very much..

10 dogesperoms

Hello

As newly registered user i only wanted to say hi to everyone else who uses this bbs 😀

11 Vince

Thanks for this, but what a wonderful world it would be without IE 😉

12 Jordan Garn

Excellent tutorial, although it would be slightly hard to implement in larger projects.

13 stone crusher

Well they just wanted it fixed and not to scroll away because that’s what they saw somewhere else

14 stone crusher

And to piggyback off of John’s comments. Positioning off the screen and then revealing is good for search engines too, because they can still index the content. Sometimes I have used that approach over Ajax for that reason. That may be another article…

15 Guld Ørestikker

I am looking for a pup up like this, it look great, i will test it to see if i can use it on my magento site 🙂

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators


Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

You need to download the Flash player from Adobe

Blogs Worth Reading