Drop Cap: The Next Generation

    James Edwards
    James Edwards

    Recently I wrote about the drop-cap technique we’ve used in the blogs redesign: A Simple CSS Drop Cap. One comment really caught my interest, because it was asking about a situation I’d never even considered:

    I appreciate being able to have this drop-cap ability in CSS, but I’m from the old school of typography and, even in the days of hot-metal typesetting, we would kern these characters so the paragraph wrapped, conforming to the cap. — jackew

    I confess that I didn’t understand this at first (typography jargon ‘n’ all) and it had to be explained to me. The commenter was talking about a drop cap where the text flows around the shape of the letter, rather than just around its bounding box, so the letter feels more like a part of the text and less like a separate entity. To see the difference, compare the two examples in Figure 1, “Simple drop cap versus complex drop cap”: on the left, the text flows in a square around the letter’s bounding-box; on the right, it takes a more complex shape around the letter itself.

    Thinking about this problem, I found myself recalling an instance when some text was made to flow around a non-rectangular image a few years ago. I felt inspired to play with the idea, and it turned out to be very easy to implement—if a little fiddly to make exactly right.

    Figure 1. Simple drop cap versus complex drop cap

    Simple drop cap versus complex drop cap

    Flowing Floats

    The basic trick is to add a whole bunch of “slices” to the start of the paragraph, before the inner text: thin, rectangular floated strips, around the hight of one line, with varying widths, that the text can flow down the side of without clearing. For example, take the following markup:

    <p>  <span class="slice" id="s1"></span>  <span class="slice" id="s2"></span>  <span class="slice" id="s3"></span>  <span class="slice" id="s4"></span>  <span class="slice" id="s5"></span>  <span class="slice" id="s6"></span>  <span class="slice" id="s7"></span>  <span class="slice" id="s8"></span>  <span class="slice" id="s9"></span>  <span class="slice" id="s10"></span>  Lorem ipsum dolor sit amet, consectetuer adipiscing elit.   Nunc neque. In hac habitasse platea dictumst. Pellentesque   ultrices. Donec nunc metus, aliquam sit amet, aliquam in,   luctus ac, odio. Aenean orci velit, elementum ac, egestas   pellentesque, facilisis non ...</p>

    Style it with this CSS:

    p{  float: left;  clear: none;  font-family: tahoma,sans-serif;  font-size: 0.85em;  margin: 0;  line-height: 1.3;  background: url(maggie.jpg) no-repeat left top;}p .slice{  float: left;  clear: left;  display: block;  background: transparent;  height: 16px;  line-height: 1;  margin: 0 10px 0 0;}#s1 { width: 80px; }   #s2 { width: 97px; }   #s3 { width: 101px; }#s4 { width: 101px; }  #s5 { width: 93px; }   #s6 { width: 118px; }#s7 { width: 122px; }  #s8 { width: 162px; }  #s9 { width: 162px; }#s10 { width: 103px; }

    And you’ll end up with a paragraph that looks like the one in Figure 2, “Maggie Simpson flanked by miscellaneous text” (which is a good reason in itself, if you needed one!). You can also view this example online.

    Figure 2. Maggie Simpson flanked by miscellaneous text

    Maggie Simpson flanked by miscellaneous text

    Naturally the slices are transparent most of the time, so that all you see is the background image behind them. But if we style them instead so that they’re visible and separate, we’ll clearly see the mechanics involved in Figure 3, “The same image of Miss Simpson, now with visible slices”. You can view this example online too.

    Figure 3. The same image of Miss Simpson, now with visible slices

    The same image of Miss Simpson, now with visible slices

    Make It Smaller

    So if that all works okay, could we use the same idea to implement a better drop cap? All we’d have to do is put a big positioned letter over a bunch of very small slices, which describe the letter’s shape, and we create the effect of text flowing around the letter. It’s exactly the same technique, just on a smaller scale.

    What we find, however, is that the resolution of the effect we’re creating—by which I mean how fluid the shape of the text becomes, and how closely it follows the contours of the letter—is determined not by the size of the slices, but by how many lines of text are affected. Essentially, the bigger we make the drop cap relative to the rest of the text, the greater the number of lines that are affected by it; this means that the text takes on the shape of the letter more clearly (just like having more pixels in a photograph).

    Make It Bigger?

    The example we saw at the very start, and now again here in Figure 4, “A large “L” preceding miscellaneous text that flows around it”, takes eight lines to wrap completely around the drop cap—and I think it looks great.

    Figure 4. A large “L” preceding miscellaneous text that flows around it

    A large “L” preceding miscellaneous text that flows around it

    However, you can see how we’d need a minimum of four or five lines to flow around that letter, or there’d be minimal effect at all; less than that is just too little to describe the shape of most capitals.

    Make It So!

    So at last, here’s the code that makes that large drop-cap letter “L” with text flowing around and down its right-hand side (view the demo). First, the HTML:

    <p>  <span class="slice s1"></span>  <span class="slice s2"></span>  ...   <span class="slice s19"></span>  <span class="slice s20"></span>          <strong class="first-letter">L</strong>orem ipsum dolor   sit amet, consectetuer adipiscing elit. Nunc neque. In   hac habitasse platea dictumst. Pellentesque ultrices.   Donec nunc metus, aliquam sit amet, aliquam in, luctus   ac, odio. Aenean orci velit ...</p>

    To save space I’ve abridged that code example, omitting some of the slices, but this demo actually takes twenty slices, indexed by class name from slice s1 to slice s20. It also has quite a lot more text. Now here’s the CSS:

    p{  font-size: 0.73em;  position: relative;  float: left;  clear: none;  font-family: tahoma,sans-serif;  color: #224;  margin: 10px 0 0 10px;  width: 50%;  line-height: 1.3;}p > strong.first-letter{  position:absolute;  left:0;  top:0;  font-family:garamond,times,serif;  color:#004;  font-size:12.5em;  line-height:0.72;  text-shadow:0.01em 0.01em 0.02em rgba(0,0,50,0.5);}p > .slice{  float:left;  clear:left;  display:block;  background:transparent;  height:0.435em;  line-height:1;  margin:0 8px 0 0;}p > .s1 { width:4.8em; }   p > .s2 { width:4.8em; }p > .s3 { width:4.6em; }   p > .s4 { width:3.6em; }p > .s5 { width:3.6em; }   p > .s6 { width:3.6em; }p > .s7 { width:3.6em; }   p > .s8 { width:3.6em; }p > .s9 { width:3.6em; }   p > .s10 { width:3.6em; }p > .s11 { width:3.6em; }  p > .s12 { width:3.6em; }p > .s13 { width:3.6em; }  p > .s14 { width:8.2em; }p > .s15 { width:8.1em; }  p > .s16 { width:8.1em; }p > .s17 { width:8em; }    p > .s18 { width:8em; }p > .s19 { width:7.9em; }  p > .s20 { width:7.9em }

    That’s all it takes; no images are required. Since all the important sizes and dimensions are in em units, you only have to change the base font size on the container paragraph and it will all scale in proportion.

    To use a different letter, you firstly need to add a background color to the slices so that you can see them, and then adjust their widths one by one until the letter is completely covered. You don’t have to be super-accurate; it’s okay if you overestimate slightly. If you find that some lines are stopping just by the edge of a slice when you want them to flow underneath it (for example), you can slightly adjust the height of individual slices as well, to nudge the text flow in a particular direction; for example:

    p > .s1 { width:4.8em; }p > .s2 { width:4.8em; }p > .s3 { width:4.6em; height:0.385em; }p > .s4 { width:3.6em; height:0.485em; }p > .s5 { width:3.6em; }...etc

    Two Little Wrinkles

    One slight downside to this technique is that it now requires a wrapper around the first letter. The original technique used in this design takes the :first-letter pseudo-element to create the drop cap. However, that’s impossible for these examples, because current browsers simply don’t implement enough CSS properties for that pseudo-element to do the job (for example, positioning fails to work, and that’s crucial). In any case, the presence of the slice elements before the text means that some browsers no longer consider it to be the first letter anymore. That’s why we have to use a wrapper.

    The other minor issue with this technique is that it doesn’t work properly in IE6, even though the basic trick does; the slices are out of proportion and out of position, and the surrounding text displacement is inaccurate. It might be possible to tweak it bit by bit with hacks until it’s right, but who has time for that stuff anymore!

    It’s trivial to degrade the effect for IE6 by using a child selector instead of a descendant selector, leaving just the bolding from the <strong> tag around the first letter. If you really felt motivated, you could use a CSS hack to define a different, simpler drop cap just for IE6:

    /* IE6's alternative drop-cap! */* html p strong.first-letter{    color:#003;    font-family:times,serif;    font-size:4.6em;    float:left;    margin:0.4em 0.2em 0 0;    line-height:0.7;}

    Apart from those two technical glitches, there’s also the inevitable question of whether you’re bothered by all those semantically superfluous span elements. There’s no way to avoid the need for them, as there just aren’t enough workable pseudo-elements to do this in CSS alone. Creating this effect comes at a cost then, and it’s up to you to decide whether it’s worth it for the end result.

    Real-world Implementation

    The fiddly part in all this is defining the size of all those slices, to match whatever letter (in whatever size and font) you want the text to flow around. It’s no real bother for a handful of test cases, but if you wanted it to have real-world flexibility, you might want to think about streamlining and abstracting the implementation. And one likely approach would be to do it in JavaScript. That’s a whole other article though …