Modal CSS Dialogs
Modal CSS dialogs require rather more effort than simply floating a few HTML elements. However, this article is very useful for placing into context a number of issues discussed upto this point - positioning, the display attribute and CSS floats.
We are all familiar with modal dialog boxes. They are used in graphical environments, such as Windows, to provide information or to seek user input while temporarily blocking access to the rest of the user interface. In this article we explain how the power of CSS can be used to deliver modal dialogs in a web browser.
Introduction Why bother? How it works CSS .overlay .diadiv .diaframe .diacapt .diacapt a .capt .diabody .diaimg .diatxt .diapara .diaclose JavaScript ShowDialog MakeDialog AdjustSizes CloseDialog
Why Bother?
The showModalDialog function in IE6 provides a rudimentary modal dialog capability. However, quite apart from the fact that it is IE specific it has become increasingly difficult to rely on it owning ot the fact that users can configure browsers to block popup dialogs from opening. Even when this is not done, some firewalls provide such functionality by default.How It Works
To deliver a pseudo modal dialog using CSS we make use of positioned and floated div elements, modify backgrounds, sizes and display types to create what to all intents and purposes is a modal dialog box.
It is possible to create a modal dialog using CSS alone. Indeed, if you want to be sure that the contents of your dialog are seen by search engine spiders you should do this and merely hide the dialog when it is not required by adjusting the display attribute of the parent division inside which the dialog is generated - see .diaframe. However, if you need to show several dialogs and/or dynamically change the contents of the dialogs you will need to use some JavaScript. We discuss this latter technique.
Download our CSS & JavaScript source for creating modal dialogs from the download link below. Open the .css and .js files in your favorite editor and then read the rest of this article. From time-to-time you might want to click on the Show Dialog button below and look at the sample dialog in order to place the discussion that follows in context.
The .overlay Selector
We need to accomplish two things when the popup dialog is on show- The underlying text and form controls must appear dimmed to give the viewer an indication of the fact that they are currently disabled.
- Attempts by the user to interact with form controls on the parent page should be blocked.
overlay and adjust its height and width so it covers the entire visible area of the HTML document on display.We use the document.body.clientHeight/clientWidth properties for the purpose. overlay is the CSS selector defined at the top of dlg.css. We use the appendChild method to make this newly created HTML division a child of the division with the id main used to display page content on every page on this site.
The .diadiv Selector
The overlay layer we have created has an opacity setting of 0.6. If we were to create the modal dialog as a child of this layer, all of its HTML elements would inherit this opacity setting - not desirable since we do not want the dialog box to appeardimmed. This can be fixed in many ways, the easiest being to create another HTML division identical to the overlay created above in all respects except that it has a transparent background. The diadiv CSS selector for this purpose. The modal dialog is added as a child of this HTML division.
The .diaframe Selector
The entire modal dialog is placed inside an absolutely positioned HTML division. We use the CSS selector diaframe for this purpose. In the present example we have given this division a default position of 200 pixels from the top left hand corner of its parent container, diadiv which occupies the entire client ara of the HTML document. The width and height of diaframe are specified in em units - the use of a relative unit of measurement is essential to ensure that the dialog scales properly depending on the screen resolution and text size in use. We provide a frame around the dialog by setting the border attribute.The .diacapt Selector
At the top of the dialog box we need to display a caption bar. This uses the CSS selector diacapt. The caption is absolutely positioned inside its parent, diaframe. We provide a top and bottom padding to ensure that the contents of the caption - the x and ? buttons and the caption text itself - do not but against the boundaries of the caption bar. Theoverflow:hidden specification ensures that the contents do not wrap onto a new line or otherwise spill out of the caption bar irrespective of the text display size in use. The caption bar is given a height of 1.5em - enough to show a single line of text. The use of a a relative unit of length ensures that the caption bar scales correctly to different screen resolutions and text display sizes..diacapt Anchors
The easiest way to show border icons (control buttons) in the caption bar is through the use of right-floated anchors. We specify anchor characteristics for the diacapt selector. Floating turns the anchor into a block element. We provide a border to make the anchor look like a button and define its hover pseudo-class to make it tactile.
Border icons could be done in other ways - for instance using images or even an image map. However, the most bandwidth friendly solution is the floated anchor.
There is a subtle issue here with correctly setting the height of the anchors. Although the parent diacapt element has a client area of 1.4em the height setting we use here is slightly less than (1.4/0.8 - 0.1)em. Why? Because we have the settings font-size:0.8em and padding-top:0.05em to allow for. See here for a full discussion of such problems.
The .capt Selector
The caption text is placed in a span which uses the CSS selector capt. Note that when creating the caption bar contents using JavaScript this span element - containing actual caption text - is added last.The .diabody Selector
The actual body of the dialog - i.e. the area in which a relevant image is shown alongside text and form controls - is an absolutely positioned HTML division which uses the CSS selector diabody. We position this division just below the caption by specifyingtop:1.6em.The .diaimg Selector
Inside the body of the dialog, diabody we place two absolutely positioned division elements. The one of the left, diaimg has a fixed width of 101 pixels - enough to display our chosen image. Though not needed here we setoverflow:hidden to ensure that the image division does not end up with scrollbars or spill its contents should an attempt be made to display an image that is too big. The image is styled using the CSS selector diaimg.The .diatext Selector
The second absolutely positioned division inside diabody is used to display actual dialog text and controls. This division is placed to the right of diaimg - by setting left:101px - and sized from script using em units to ensure that it scales correctly at different screen resolutions and text display sizes.
You may well wonder why we did not use floated divisions instead of absolutely positioned ones. This is because in our tests only Firefox was able to handle the float specification correctly. The time will come when floating will be the right solution but for now absolute positioning is a safer bet.
The .diapara Selector
The text displayed in the dialog is placed in a HTML paragraph element styled using the CSS selector diapara. We setoverflow:auto to ensure that in the event that the text supplied for display is too long the element will appear with scroll bars. By no means an ideal solution but better than having text spilling out of the dialog.The .diaclose Selector
Finally we create an HTML division to host the Close button. We settext-align:right and provide a generous right hand side padding to ensure that the button appears in the familiar bottom right position.The ShowDialog Method
The ShowDialog function generates the HTML required to display the dialog. We begin by creating the overlay layer to block access to the underlying form controls - in the present case, only the Show Dialog button. Next we create the diadiv layer which acts as the parent for the modal dialog. As noted earlier, this is the easiest way of ensuring that the opacity setting of the overlay layer does not cause the dialog contents to appear dimmed. Note the use of the document.body.clientHeight/Width attributes for setting the height and width of these two divisions. We use the innerHTML attribute of diadiv to populate it with the actual modal dialog which is created by calling the MakeDialog function. Finally, we call AdjustSizes() to perform some residual sizing of the various dialog elements in order to ensure that the dialog scales properly if the user changes text display size.
Why put size adjustment into a separate function? The problem is that even with careful use of em sizing it is not always easy to ensure that all dialog elements scale correctly as the user changes text display size. However, this can be ensured by repeating size adjustment at regular intervals - using setInterval after checking to see if the text display size has changed. We have not done this in our example. Should you find it necessary, the separate location of size adjustment code will prove handy.
Dialog content building is done in a sequence of steps
- We construct a HTML code string containing the close, x, and help, ?, buttons. Then we append the HMTL for the span containing caption text. This order is important - if you put the caption text span before the floated anchors used for the control buttons you will end up with an unwanted line break.
- We build the HTML for the division, diacapt containing all caption controls.
- HTML for para which contains dialog text - in the present instance this is the sentence: CSS Modal Recipe Dialog from ExplainThat! - is built next followed by HTML for btns which contains the Close button.
- Finally we build the HTML for diatxt which contains the dialog prompt and Close button HTML code - built above - followed by the image to be displayed to its left in diaimg (Once again, note the order - image HTML code placed first is incorrectly interpreted by Opera and IE) and use it to build the HTML for diabody, the dialog contents container
The MakeDialog Method
With all of the above accomplished we build the HTML code for diaframe, the outer container for the entire dialog and provide it with the diacapt and diabody code built above. It is this HTML code string that we return as the result from MakeDialog.
The AdjustSizes Method
AdjustSizes is used to set the height/width of some HTML elements in the modal dialog in relative, em, units to ensure that the dialog scales properly at all screen resolutions and when the user changes the text display size. For the most part this code is quite easy to understand. However, there are a few subtleties to which we would like to draw your attention:
- The offsetWidth/Height attributes return HTML element width/height in pixels. Pixels, as used by real world web browsers, are an absolute unit of measurement. We use the fact that we know the em dimensions of diaframe to obtain a pixels to em conversion. It is important to appreciate that the horizontal and vertical conversion ratios are not the same. Hence the need for pxPeremX and pxPeremY
- When adjusting sizes we need to account for padding and border sizes.
- Finally - in our view - such adjustments are only worth attempting when using the strict HTML DTD.
The CloseDialog Method
CloseDialog is simple. We locate the overlay and diadiv divisions and remove them from their parent element. This automatically removes the modal dialog itself which is owned by diadiv.Download