How to do `hanging titles'

The CSS draft mentions that the properties float and width are most often used with images. What might not be obvious is that they can also be used for effects like the following:

THE TITLE  The paragraphs after the
OF THIS    title wrap around it, just
SECTION    as if the title had been
           an image. The style sheet
for this little trick is just a
1-liner: H1 {float: left; width: 5em}

As the example says, just two properties are needed to achieve this. For best results, however, one may want to add some padding here and there.

The full story

The properties that are most important for hanging titles are, beside float and width, also margin and height. Here is another example, which helps to understand their interaction:

-L-><-----------------W*----------------><-R- BODY

    <----W----><------------R*---------->     H1

    -L-><-------------W*---------------->     P

    THE TITLE  The paragraphs after the
    OF THIS    title wrap around it, just
    SECTION    as if the title had been
               an image. In this case,
               the space below the title
               is larger and the title
        appears to stick out into the
        margin a little. Setting the
        margin and height correctly is
        the key here.

(L = margin-left, W = width, R = margin-right, * = automatic) Assuming the source looked like this:

<body><h1>The title of this section</h1>
<p>The paragraphs...

Then a style sheet like this would do the trick:

BODY { margin: 0pt 2em }
H1 { float: left; width: 5em; height: 6em }
P { margin-left: 2em }

But let's first look at the behavior of margins in the normal case. That is, use the following style sheet without float:

BODY { margin: 0pt 2em }
H1 { width: 5em; height: 6em }
P { margin-left: 2em }

The result will now look like this

-L-><-----------------W*----------------><-R- BODY

    <----W----><------------R*-----------     H1

    -L-><-------------W*---------------->     P

    THE TITLE
    OF THIS
    SECTION

        The paragraphs after the title
        don't wrap around it.

Both H1 and P are childs of BODY. That means that for, say, P the following equation must hold:

widthbody = margin-leftP + border-leftP + padding-leftP + widthP + padding-rightP + border-rightP + margin-rightP

Normally, width is the variable in this equation, but if it has been set explicitly, as in the case of H1 above, the right margin becomes the variable (unless that has been set as well... see CSS1 section 4.2 for the rest.)

In the example, the width of BODY is computed in this way from the width of the HTML element and the width of P is computed from the width of BODY. For H1 the width is given, so the right margin is computed instead.

The actual position of the elements follows from the following:

Starting from the left side of the screen, one encounters first the margin, border and padding of the outermost element, HTML, then the margin, border and padding of BODY, then the margin, border and padding of P.

By default, all of padding, border and margin are 0, so the most common case is that the child's width is the same as its parent's. In the examples above, zero-width parts are not shown.

Now back to the example with floating H1. Here is what happens:

  1. The H1 has float: left, which means it is turned into a block and moved to the left. Its position is controled by its margin-left property. In the example the margin-left was not specified, in other words: it was 0. That means the H1 moves to the left edge of its parent.

    If there is already a floating element there, and there is enough space next to it, the H1 will be put to the right of the existing float, otherwise below it.

    If there is already a float and the H1 has the clear property set to left or both, then it will also be put below the existing float, but the paragraph that follows it will move down with it.

  2. The size of the H1 is controled by margin, padding and width as normal. In the absence of an explicit width, the width of H1 would be the full available space between the H1's margins. That's not what we want here, so the width has been set to an explicit value. That means that now the right margin is automatically adjusted.

    There is a subtle inconsistency in the rules here, which becomes clear when float is set to right. In this case we want the element to move to the right and, if we also set the width, the left margin should be adjusted automatically. According to the rules of CSS1 section 4.2 for normal, non-floating blocks, it's always the right margin that is stretched, but with float right that rule is reversed.

  3. The height of H1 could be automatic, as in the first example, but in this case some extra space is added by setting the height to 6em. The danger is, of course, that the fixed height is not large enough, in which case a vertical scollbar or a similar device will appear.

    Unless one really wants a fixed height, it is better to use a bottom margin for adding extra space. bottom-margin: 3em would have worked in this case.

    BODY { margin: 0pt 2em }
    H1 { float: left; width: 5em; margin-bottom: 3em }
    P { margin-left: 2em }
    
  4. The P element has a left margin of 2em, so it is indented relative to its parent, the BODY. Its right margin is 0pt (default value) and its width is automatic (also default). There is an element that it must wrap around, so the first few lines get a smaller actual width, but that width is not used in any further computations.

Negative margins

In the example above, we have set H1 against the left edge of its parent and the P was indented by 2em. That was done to avoid negative margins. The first idea about how to get the desired layout would probably be to set the P without any margins, but make the H1 stick out to the left, using a negative margin.

Using that idea, here is exactly the same result:

-L-----><-------------W*----------------><-R- BODY
    <-L-
    <----W----><------------R*---------->     H1

        <-------------W*---------------->     P

    THE TITLE  The paragraphs after the
    OF THIS    title wrap around it, just
    SECTION    as if the title had been
               an image. In this case,
               the space below the title
               is larger and the title
        appears to stick out into the
        margin a little. Setting the
        margin and height correctly is
        the key here.

But with a different style sheet:

BODY { margin: 0pt 4em }
H1 { float: left; width: 5em;
  margin-left: -2em; height: 6em }

Note that The P needs no rules at all now, but the H1 has got a left margin and the left margin of the BODY is now larger.

The question is to what extend negative margins should be allowed.


Bert Bos
6 Jun 1996