Ïðèãëàøàåì ïîñåòèòü
Âÿçåìñêèé (vyazemskiy.lit-info.ru)

8.2 Margins

Previous Page Table of Contents Next Page

8.2 Margins

The separation between most normal-flow elements occurs because of element margins. Setting a margin creates extra "blank space" around an element. "Blank space" generally refers to an area in which other elements cannot also exist and in which the parent element's background is visible. For example, Figure 8-4 shows the difference between two paragraphs without any margins, and the same two paragraphs with some margins.

Figure 8-4. Paragraphs with, and without, margins
figs/css2_0804.gif

The simplest way to set a margin is by using the property margin.

margin


Values

[ <length> | <percentage> | auto ]{1,4} | inherit


Initial value

not defined


Applies to

all elements


Inherited

no


Percentages:

refer to the width of the containing block


Computed value:

see individual properties


The effects of setting auto margins were discussed in detail in Chapter 7, so we will not repeat the discussion here. Besides, it's more common to set length values for margins. Suppose you want to set a quarter-inch margin on h1 elements, as illustrated in Figure 8-5. (A background color has been added so you can clearly see the edges of the content area.)

h1 {margin: 0.25in; background-color: silver;}
Figure 8-5. Setting a margin for h1 elements
figs/css2_0805.gif

This sets a quarter-inch of blank space on each side of an h1 element. In Figure 8-5, dashed lines represent the blank space, but the lines are purely illustrative and would not actually appear in a web browser.

margin can accept any length of measure, whether in pixels, inches, millimeters, or ems. However, the default value for margin is effectively 0 (zero), so if you don't declare a value, by default, no margin should appear.

In practice, however, browsers come with preassigned styles for many elements, and margins are no exception. For example, in CSS-enabled browsers, margins generate the "blank line" above and below each paragraph element. Therefore, if you don't declare margins for the p element, the browser may apply some margins on its own—so even if you don't declare margins for an element, some might appear. Whatever you declare will override the default styles, of course.

Finally, it's possible to set a percentage value for margin. The details of this value type will be discussed in Section 8.2.2.

8.2.1 Length Values and Margins

As stated before, any length value can be used in setting the margins of an element. It's simple enough, for example, to apply a 10-pixel whitespace around paragraph elements. The following rule gives paragraphs a silver background and a 10-pixel margin, as shown in Figure 8-6:

p {background-color: silver; margin: 10px;}
Figure 8-6. Comparative paragraphs
figs/css2_0806.gif

(Again, the background color helps show the content area, and the dashed lines are for illustrative purposes only.) As Figure 8-6 demonstrates, 10 pixels of space have been added to each side of the content area. The result is somewhat similar to using the hspace and vspace attributes in HTML. In fact, you can use margin to set extra space around an image. Let's say you want one em of space surrounding all images:

img {margin: 1em;}

That's all it takes.

At times, you might desire a different amount of space on each side of an element. That's simple as well. If you want all h1 elements to have a top margin of 10 pixels, a right margin of 20 pixels, a bottom margin of 15 pixels, and a left margin of 5 pixels, here's all you need:

h1 {margin: 10px 20px 15px 5px;}

The order of the values is important, and follows this pattern:

margin: top right bottom left

A good way to remember this pattern is to keep in mind that the four values go clockwise around the element, starting from the top. The values are always applied in this order, so to get the effect you want, you have to arrange the values correctly.

8.2 Margins

An easy way to remember the order in which sides must be declared, other than thinking of it as being clockwise from the top, is to keep in mind that getting the sides in the correct order helps you avoid "TRouBLe"—that is, TRBL, for "Top Right Bottom Left."


It's also possible to mix up the types of length value you use. You aren't restricted to using a single length type in a given rule, as shown here:

h2 {margin: 14px 5em 0.1in 3ex;}  /* value variety! */

Figure 8-7 shows you, with a little extra annotation, the results of this declaration.

Figure 8-7. Mixed-value margins
figs/css2_0807.gif

8.2.2 Percentages and Margins

As I mentioned earlier, it's possible to set percentage values for the margins of an element. Percentages are computed in relation to the width of the parent element, so they change if the parent element's width changes in some way. For example, assume the following, which is illustrated in Figure 8-8:

p {margin: 10%;}



<div style="width: 200px; border: 1px dotted;">

<p>This paragraph is contained within a DIV that has a width of 200 pixels, 

so its margin will be 10% of the width of the paragraph's parent (the DIV).

Given the declared width of 200 pixels, the margin will be 20 pixels on 

all sides.</p>

</div>

<div style="width: 100px;  border: 1px dotted;">

<p>This paragraph is contained within a DIV with a width of 100 pixels,

so its margin will still be 10% of the width of the paragraph's parent. 

There will, therefore, be half as much margin on this paragraph as that

on the first paragraph.</p>

</div>
Figure 8-8. Parent widths and percentages
figs/css2_0808.gif

By contrast, consider the case of elements without a declared width. In such cases, the overall width of the element box (including margins) is dependent on the width of the parent element. This leads to the possibility of "fluid" pages, where the margins of elements enlarge or reduce to match the actual size of the parent element (or display canvas). If you style a document so that its elements use percentage margins, then as the user changes the width of a browser window, the margins will expand or shrink to fit. The design choice is up to you.

You may have noticed something odd about the paragraphs in Figure 8-8. Not only did their side margins change according to the width of their parent elements, but so did their top and bottom margins. That's the desired behavior in CSS. Refer back to the property definition, and you'll see that percentage values are defined to be relative to the width of the parent element. This applies to the top and bottom margins as well as to the left and right. Thus, given the following styles and markup, the top margin of the paragraph will be 50px:

div p {margin-top: 10%;}



<div style="width: 500px;">

<p>This is a paragraph, and its top margin is 10% the width of its parent

element.</p>

</div>

If the width of the div changes, the top margin of the paragraph will, too. Seem strange? Consider that most elements in the normal flow are (as we are assuming) as tall as necessary to contain their descendant elements, including margins. If an element's top and bottom margins were a percentage of the parent, an infinite loop could result where the parent's height was increased to accomodate the top and bottom margins, which would then have to increase to match the new height, and so on. Rather than simply ignore percentages for top and bottom margins, the specification authors decided to make it relate to the width of the parent, which does not change based on the width of its descendants.

8.2 Margins

The treatment of percentage values for top and bottom margins is different for positioned elements; see Chapter 10 for more details.


It's also possible to mix percentages with length values. Thus, to set h1 elements to have top and bottom margins of one-half em, and side margins that are 10% the width of the browser window, you can declare the following, illustrated in Figure 8-9:

h1 {margin: 0.5em 10% 0.5em 10%;}
Figure 8-9. Mixed margins
figs/css2_0809.gif

Here, although the top and bottom margins will stay constant in any situation, the side margins will change based on the width of the browser window. Of course, we're assuming that all h1 elements are children of the body element and that body is as wide as the browser window. Plainly stated, the side margins of h1 elements will be 10% the width of the h1's parent element.

Let's revisit that rule for a moment:

h1 {margin: 0.5em 10% 0.5em 10%;}

Seems a little redundant, doesn't it? After all, you have to type in the same pair of values twice. Fortunately, CSS offers an easy way to avoid this.

8.2.3 Replicating Values

Sometimes, the values you're entering for margin get a little repetitive:

p {margin: 0.25em 1em 0.25em 1em;}

You don't have to keep typing in pairs of numbers like this, though. Instead of the preceding rule, try this:

p {margin: 0.25em 1em;}

These two values are enough to take the place of four. But how? CSS defines a few rules to accommodate fewer than four values for margin. These are:

  • If the value for left is missing, use the value provided for right.

  • If the value for bottom is missing, use the value provided for top.

  • If the value for right is missing, use the value provided for top.

If you prefer a more visual approach, take a look at the diagram shown in Figure 8-10.

Figure 8-10. Value replication pattern
figs/css2_0810.gif

In other words, if three values are given for margin, the fourth (left) is copied from the second (right). If two values are given, the fourth is copied from the second, and the third (bottom) from the first (top). Finally, if only one value is given, all the other sides copy that value.

This simple mechanism allows authors to supply only as many values as necessary, as shown here:

h1 {margin: 0.25em 0 0.5em;} /* same as '0.25em 0 0.5em 0' */

h2 {margin: 0.15em 0.2em;}  /* same as '0.15em 0.2em 0.15em 0.2em' */

p {margin: 0.5em 10px;}    /* same as '0.5em 10px 0.5em 10px' */

p.close {margin: 0.1em;}  /* same as '0.1em 0.1em 0.1em 0.1em' */

The method presents a small drawback, which you're bound to eventually encounter. Suppose you want to set the top and left margins for h1 elements to be 10 pixels, and the bottom and right margins to be 20 pixels. In that case, you have to write the following:

h1 {margin: 10px 20px 20px 10px;} /* can't be any shorter */

You get what you want, but it takes a while to get it all in. Unfortunately, there is no way to cut down on the number of values needed in such a circumstance. Let's take another example, one where you want all of the margins to be auto—except for the left margin, which should be 3em:

h2 {margin: auto auto auto 3em;}

Again, you get the effect you want. The problem is that typing auto gets a little tedious. All you want to do is affect the margin on one side of the element, which leads us to the next topic.

8.2.4 Single-Side Margin Properties

Fortunately, there's a way to assign a value to the margin on a single side of an element. Let's say you only want to set the left margin of h2 elements to be 3em. Instead of using the typing-intensive margin, you could take this approach:

h2 {margin-left: 3em;}

margin-left is one of four properties devoted to setting the margins on each of the four sides of an element box. Their names should come as little surprise.

margin-top, margin-right, margin-bottom, margin-left


Values

<length> | <percentage> | auto | inherit


Initial value

0


Applies to

all elements


Inherited

no


Percentages:

refer to the width of the containing block


Computed value

for percentages, as specified; otherwise, the absolute length


Using any one of these properties lets you set a margin on that side only, without directly affecting any of the other margins.

It's possible to use more than one of these single-side properties in a single rule; for example:

h2 {margin-left: 3em; margin-bottom: 2em; 

  margin-right: 0; margin-top: 0;

  background: silver;}

As you can see in Figure 8-11, the margins are set as you want them. Of course, in this case, it might have been easier to use margin after all:

h2 {margin: 0 0 2em 3em;}
Figure 8-11. More than one single-side margin
figs/css2_0811.gif

Whether you use single-side properties or shorthand, you'll get the same result. In general, once you're trying to set margins for more than one side, it's easier to simply use margin. From the standpoint of your document's display, however, it doesn't really matter which approach you use, so choose whichever is easiest for you.

8.2.5 Negative and Collapsed Margins

As was discussed in detail in Chapter 7, it's possible to set negative margins for an element. This can cause the element's box to stick out of its parent or to overlap other elements without violating the box model. Consider these rules, which are illustrated in Figure 8-12:

div {border: 1px dotted gray; margin: 1em;}

p {margin: 1em; border: 1px dashed silver;}

p.one {margin:  0 -1em;}

p.two {margin: -1em 0;}
Figure 8-12. Negative margins in action
figs/css2_0812.gif

In the first case, the math works out such that the paragraph's computed width plus its right and left margins are exactly equal to the width of the parent div. So, the paragraph ends up two ems wider than the parent element without actually being "wider" (from a mathematical point of view). In the second case, the negative top and bottom margins effectively reduce the computed height of the element and move its top and bottom outer edges inward, which is how it ends up overlapping the paragraphs before and after it.

Combining negative and positive margins is actually very useful. For example, you can make a paragraph "punch out" of a parent element by being creative with positive and negative margins, or you can create a Mondrian effect with several overlapping or randomly placed boxes, as shown in Figure 8-13:

div {background: silver; border: 1px solid;}

p {margin: 1em;}

p.punch {background: white; margin: 1em -1px 1em 25%; 

  border: 1px solid; border-right: none; text-align: center;}

p.mond {background: #333; color: white; margin: 1em 3em -3em -3em;}
Figure 8-13. Punching out of a parent
figs/css2_0813.gif

Thanks to the negative bottom margin for the "mond" paragraph, the bottom of its parent element is pulled upward, allowing the paragraph to stick out of the bottom of its parent.

Speaking of top and bottom margins, it's also important to remember that vertically adjacent margins in the normal flow will collapse, a topic we covered in the previous chapter. Margin collapsing is at work in practically every document you style. For example, here's a simple rule:

p {margin: 15px 0;}

This will cause one paragraph to follow another with 15 pixels of "margin space" between them. If margins didn't collapse, there would be 30 pixels of space between two adjacent paragraphs, but that behavior wouldn't be what authors expect.

This does, however, mean that you need to be careful about how you style margins. Most likely, you'll want to close up the space between a heading and the following paragraph. Because paragraphs in HTML documents have a top margin, it isn't enough to set the bottom margin for the heading as zero; you must also eliminate the top margin of the paragraph. This is simple to do with CSS2's adjacent-sibling selector:

h2 {margin-bottom: 0;}

h2 + p {margin-top: 0;}

Unfortunately, browser support for adjacent-sibling selectors is (as of this writing) limited enough that most users will see a 1-em space between the heading and a following paragraph. You can still get the desired effect without using CSS2 selectors, but you'll have to be a little tricky:

h2 {margin-bottom: 0;}

p {margin: 0 0 1em;}

This will actually remove a top margin from all paragraphs, but since they also all have 1em bottom margins, the desired interparagraph separation will hold, as shown in Figure 8-14.

Figure 8-14. Intelligently setting margins
figs/css2_0814.gif

This works because the usual 1-em separation between paragraphs is a result of margin collapsing. Thus, if you take away one of those margins—the top margin, in this case—the visual result will be the same as if you'd left the margin in place.

8.2.6 Margins and Inline Elements

Margins can also be applied to inline elements, although the effects are a little different. Let's say you want to set top and bottom margins on strongly emphasized text:

strong {margin-top: 25px; margin-bottom: 50px;}

This is allowed in the specification, but since you're applying the margins to an inline nonreplaced element, it will have absolutely no effect on the line height. Since margins are effectively transparent, the above declaration will have no visual effect whatsoever. This happens because margins on inline nonreplaced elements don't change the line height of an element.

8.2 Margins

The only properties that can change the distance between lines containing only text are line-height, font-size, and vertical-align, as described in Chapter 7.


The above facts are true only for the top and bottom sides of inline nonreplaced elements; the left and right sides are a different story altogether. We'll start by considering the simple case of a small inline nonreplaced element within a single line. Here, if you set values for the left or right margin, they will be visible, as Figure 8-15 makes clear (so to speak):

strong {margin-left: 25px; background: silver;}
Figure 8-15. An inline nonreplaced element with a left margin
figs/css2_0815.gif

Note the extra space between the end of the word just before the inline nonreplaced element and the edge of the inline element's background. You can add that extra space to both ends of the inline if you want:

strong {margin: 25px; background: silver;}

As expected, Figure 8-16 shows a little extra space on the right and left sides of the inline element, and no extra space above or below it.

Figure 8-16. An inline nonreplaced element with a 25-pixel margin
figs/css2_0816.gif

Now, when an inline nonreplaced element stretches across multiple lines, the situation changes a bit. Figure 8-17 shows what happens when an inline nonreplaced element with a margin is displayed across multiple lines:

strong {margin: 25px; background: silver;}
Figure 8-17. An inline nonreplaced element with a 25-pixel margin displayed across two lines of text
figs/css2_0817.gif

The left margin is applied to the beginning of the element and the right margin to the end of it. Margins are not applied to the right and left side of each line. Also, you can see that, if not for the margins, the line may have broken after "text" instead of after "strongly emphasized." Margins only affect line-breaking by changing the point at which the element's content begins within a line.

The situation gets even more interesting when we apply negative margins to inline nonreplaced elements. The top and bottom of the element aren't affected, and neither are the heights of lines, but the left and right ends of the element can overlap other content, as depicted in Figure 8-18:

strong {margin: -25px; background: silver;}
Figure 8-18. An inline nonreplaced element with a negative margin
figs/css2_0818.gif

Replaced elements represent yet another story: margins set for them do affect the height of a line, either increasing or reducing it depending on the value for the top and bottom margin. The left and right margins of an inline replaced element act the same as for a nonreplaced element. Figure 8-19 shows a series of different effects on layout from margins set on inline replaced elements.

Figure 8-19. Inline replaced elements with differing margin values
figs/css2_0819.gif

Historical Margin Problems

As useful as margins are, a number of problems can arise with their use—all of them centered around Navigator 4.x, unsurprisingly.

The first hitch is that Navigator 4.x added margin rules to its default margins instead of replacing its default values. For example, consider:

h1 {margin-bottom: 0;}

p {margin-top: 0;}

NN4.x will display the elements with the usual blank space between them because it's adding the zero values to its own default margins. If you want to overcome this space, you can always use negative margins, such as setting a -1em top margin on the paragraph. The problem with this solution is that it won't work universally. A CSS-conformant browser will then overlap the text, since it replaces the top margin of the paragraph.

The problem gets worse, unfortunately. If you apply margins to inline elements, your layout will more or less shatter. NN4.x assumes that a margin on any element, inline or not, refers to the left edge of the browser window. This is utterly, completely wrong. Unfortunately, if you have a lot of NN4.x visitors, the use of margins on inline elements is a very risky proposition and not one to be taken lightly. Fortunately, it's easy to hide CSS from NN4.x, so that you can style your documents without worrying about NN4.x messing them up.


    Previous Page Table of Contents Next Page