Dec 27 2009

css techniques: text wrap around image

The challenge: I had designed a printed page layout with a different visual element on each page to help to break up rather long narrative. The client wanted this to be a template for her website, including the text-wrapped image. Below is a (different) page mock-up using a similar visual element in the lower left corner:

To make the page look similar to the printed version, the text to had to wrap around the image, not just squarely around an image with float:left styling. However, this is not as easy as it seems. I was familiar with the “sandbox’ technique, in which a series of sandbox DIVs is defined that block out the image so that the text can flow around them. This is cumbersome and a little time-consuming. However I stumbled upon a relatively simple technique that takes advantage of the <canvas> element.

By way of explanation, the <canvas> element “creates a fixed size drawing surface that exposes one or more ‘rendering contexts’, which are used to create and manipulate the content shown.” The term “rendering context” merely refers to either a 2D or (sometime in the future) a 3D image. To “draw” something, the <canvas> element is called by a script. In this case, Jacob Seidelin has developed a script, known as prettyfloat.js (download here).

Using this small script you simply give your image a CSS class of either “sandbag-left” or “sandbag-right”, depending on how your image should float. If the browser does not support <canvas> and image data access, a fallback mechanism simply sets the CSS float property to “left” or “right”, degrading to the old rectangular text wrap.

First, save the script with your project files (in this example to the same directory as the HTML file).

The image needs to be either .png or .gif to work properly, meaning it must have transparent pixels in which the text block will flow up next to the opaque pixels. To achieve this, the open the image in Photoshop, then:

  1. Open the Layers panel
  2. Double click on the Background layer to unlock it and make it available to transparency. This will now be labeled Layer 0.
  3. Create a new layer (Layer > New > Layer…) This will be a temporary layer on which you will draw a guide.
  4. Using the Polygonal Lassso tool, draw the guide leaving enough margin for the text:
  5. Using the Magic Wand tool, select the area to be made transparent
  6. IMPORTANT: Click on Layer 0 to make it the active layer
  7. Using the arrow keys on the keyboard, nudge the selected area 1 px to the right and 1 px up so there is no chance of a border of pixels along the straight edges
  8. Press the [delete] (or [Backspace]) key to erase the pixels:
  9. Save for Web & Devices using the PNG-24 preset

Now for the code:

In the <head> section of the HTML file, call the prettyfloat.js script:

<script src=”prettyfloat.js” type=”text/javascript”></script>

(Change the URL if you store your scripts in a separate directory)

The <body> section with just the wrapped text segment of the page is as follows:

<div class=”container”>
<div style=”position:relative; width:550px; height:450px;”> <img class=”sandbag-left” src=”flowers.png”>
<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi commodo, ipsum sed pharetra gravida, orci magna rhoncus neque, id pulvinar odio lorem non turpis. Nullam sit amet enim. Suspendisse id velit vitae ligula volutpat condimentum. Aliquam erat volutpat. Sed quis velit. Nulla facilisi. Nulla libero. Vivamus pharetra posuere sapien. Nam consectetuer. Sed aliquam, nunc eget euismod ullamcorper, lectus nunc ullamcorper orci, fermentum bibendum enim nibh eget ipsum. Donec porttitor ligula eu dolor. Maecenas vitae nulla consequat libero cursus venenatis. Nam magna enim, accumsan eu, blandit sed, blandit a, eros.</p>
<p>Quisque facilisis erat a dui. Nam malesuada ornare dolor. Cras gravida, diam sit amet rhoncus ornare, erat elit consectetuer erat, id egestas pede nibh eget odio. Proin tincidunt, velit vel porta elementum, magna diam molestie sapien, non aliquet massa pede eu diam. Aliquam iaculis. Fusce et ipsum et nulla tristique facilisis. Donec eget sem sit amet ligula viverra gravida.</p>

A test of how this renders in different browsers (using Adobe BrowserLab–more about that later) reveals that Firefox 2.0 on Mac OS X looks as intentded:

Chrome on Windows XP renders properly:

However, as expected, IE7 on Windows XP does not, though the results are acceptable (sort of):

Most newer browsers now support the <canvas> element so this is really is a relatively painless way to achieve a layout that has the look of a printed page.