CSS3 Columns and Paged Reflowable Content

Irfan Mirza

When it comes to the consumption of the written word in the digital form, the predominant complaint amongst devotees of conventional books remains the inability to develop with a digital book the connection that the provision to turn a page, the choice of paper and its color, the font, and other physical attributes specific to the book help to create.

Although the idea of recreating the whole experience—which includes the smell of the freshly opened book wafting off its spotless, untouched printed pages—in digital form will probably remain a wholly impractical and utterly unprofitable exercise in recreating the past, one aspect of that experience can now be recreated with minimum effort, for which all credit goes to the brains behind the CSS3 columns module.

Before the CSS3 Columns

Although the introduction of the columns module (currently still a candidate recommendation) has made recreating some aspects of the conventional book reading experience much easier, it was already achievable by relying on JavaScript wizardry or complex server side logic. 20 Things I Learned About Browsers and the Web by the Google Chrome team provides a highly engaging proof of the concept of recreating some elements of the traditional reading experience, albeit in a way that relies heavily on HTML and CSS logic.

In all probability, without relying on the CSS3 columns module, implementers would need to generate a style information specific to each user’s operating environment, and the decision to do so would entirely depend upon their willingness to create a reading experience suitable for devices of all sizes. However, that was then, and this is, of course, now.

The Dawn of a New Era

Well, before I usher in the new era, where presentation of digital content in pages would not mandate JavaScript wizardry or some server side PHP mastery, the uninitiated may appreciate a primer on CSS3 columns.

CSS3 Columns

Unlike some of the more talked about and visually arresting CSS3 features like transitions and animations whose underlying ideas can require a bit of focused study, the column-based presentation using CSS3 requires minimal learning and implementation time. At its simplest, the CSS author needs to declare the number of columns that he or she wants the content of the container to be split into, and from there, the browser does the rest.

#ThreeCols        
/* If you're planning to have more containers than just one with three columns, 
   then declare it a class. */

{

    -webkit-column-count:        3;

    -moz-column-count:           3;

    column-count:                3;   

/* Currently, only Opera supports column-specific properties without prefixes. */

}

<div id = 'ThreeCols'>

    <p>

        Insert Content Here.

    </p>

    <p>

        Insert Content Here.

    </p>

    <p>

        Insert Content Here.

    </p>

</div>

With just that much code, you can distribute the contents of a container into three columns (height of the container, when not specified, is determined by balancing the contents into specified number of columns). In the case of overflow, which can occur when the container has a declared height, the overflowing content will be distributed into columns with a width equal to that of the initial three columns, and the columns will be generated along the inline axis, which in case of English, becomes the x-axis.

By changing the value of column-count (prefixed accordingly), you should be able to divide the contents into any desired number of columns. However, with just the number of columns specified and no other processing instruction available, the browser will try to balance the distribution—essentially the height or amount—of the container’s content in the specified number of columns.

In order to override the default content distribution strategy across columns, you will need to set the column-fill property on the container element explicitly.

/*

    In addition to the previously included values, add the following

    to control the distribution of content across columns.

*/

#ThreeCols

{

    -webkit-column-fill:    auto; /* Status undefined: undocumented */

    -moz-column-fill:       auto;

    column-fill:            auto;

}

Use prefixes accordingly, as column-based design is still a candidate recommendation. The default value for the column-fill property is the balance which requires that the UA should try to minimize the variation in column length. With value of the column-fill set to auto, user agents are required to fill the columns sequentially, meaning there can be partially filled and empty columns. When using column-fill with auto, you will need to keep in mind following couple of details:

  • The column-fill property is only consulted when the container has a specified height. With no height specified, the UAs will always try to balance the height of the columns, essentially ignoring the specified value of column-fill.
  • Bear in mind that, presently, when it comes to column-based distribution of content in a container with specified height, the default behavior of all of the browsers with the exception of Opera does not conform to the requirements of the CR.

Let’s move on to bigger and better uses of column-based design.

CSS Columns and Paged Content

Setting the column-count to 1 or column-width to the maximum width of the container element instructs the browser to generate a single column equal to the width of the container, meaning all of the overflowing content would be distributed in columns of equal width along the x-axis or the inline axis. Theoretically, by using one of the two aforementioned properties with specified values, CSS authors should be able to create an illusion of pages, where content gets divided into parts equal to the height and width of the container.

In the case of Firefox and Opera, with column-count set to 1 and the container having a specified height, the browsers generate a single column wide enough to take up the whole space of the parent element, meaning that the paged layout effect can be achieved without specifying the value of column-width explicitly. However, webkit based browsers—Safari, Chrome and now Opera—fail to distribute the content in columns.

The pseudo algorithm makes it absolutely clear that if column-width or column-count have a specified value other than auto, then the container element must be treated as multicolumn element, so currently the behavior of webkit based browsers fails to conform to the requirements of the candidate recommendations.

Browser specific issues aside, in order to make it work in most modern browsers—Chrome, Firefox, Opera, and Safari—you would need to set the value of the column-width property on the container to be equal to the width of the container (percentage values do not work; exact pixel values or em values for the width of the container and the column-width currently produce the desired results).

With these issues in mind, the following code should comprise the simplest possible container level CSS definition to generate the illusion of pages (mind you, it requires JavaScript to work):

#Paged

{

    width:        80%;

    height:       100%;

    margin:       0 auto;
 
    -moz-column-count: 1

    column-count:      1;

    /* Will not work in webkit based browsers, so no need to add another declaration. */

}

Theoretically, the foregoing CSS declaration should distribute the contents of the container into columns with the width of each column equal to the width of the container block with id set to Paged. However, despite its completeness for the purpose, in order to make it work across browsers, especially webkit based browsers, you will need to use the following container-level declaration instead:

#Paged

{

    width:             1050px;   /* or any value of your liking but still an exact value. */

    height:            100%;

    margin:            0 auto;   /* Centered content. */
 
    column-width:      1050px;   /* Prefix accordingly, as this should work in most of the 
                                 modern browsers. */

}

If you have to use a percentage-based fluid design, you can always rely on some JavaScript and window.innerWidth to find the actual width and set the calculated value on the container element once DOMContentLoaded has fired.

Turning the Page

Currently, in order to recreate the illusion of pages, you will have to make use of a few JavaScript instructions (no wizardry required). To complete the task, you will need to use the value of scrollWidth property of the container element to determine the number of columns that the browser has generated for the given content. To get the scrollWidth value, you’ll first have to set overflow to auto.

Assuming that your given content has resulted in more columns than one, you would have a container with horizontal overflow and a horizontal scrollbar. When DOMContentLoaded fires, retrieve the value of scrollWidth and set the value of overflow on the container element to hidden; it will cause the scrollbar and overflowing content to disappear.

By dividing the value of scrollWidth by the actual width of the container, you should get the number of pages, or columns with width equal to the width of the container, that the browser has generated. Whenever the user clicks the appropriate button, you should increment or decrement the scrollLeft value by the total width of the container.

By doing so, you should be able to present to the viewer the next or previous page of the current document. While incrementing or decrementing the value of scrollLeft, by maintaining a value to indicate the current page and comparing it with the value of the page count, you should be able to adjust the status of the buttons that allow the user to move to the next or previous page.

Conclusion

Until the Paged Presentations section of the Generated Content for Paged Media Module gains full support, the aforementioned solution provides you with a simple and low-on-computing-resources solution that you can use today in almost all of the browsers, albeit with prefixes, to create an appealing illusion of the paged content.

Considering that an appealing presentation coupled with minimal loading times—both achievable using the aforementioned solution—can make all the difference, the ability to recreate the conventional book reading experience with as much authenticity as possible is within reach.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Jeroen

    Some of the article text is in the codeblocks.

    • http://www.onsman.com Ricky Onsman

      Yep, thanks, being fixed.

  • Inger

    In IE9 I get rows in stead of columns.

    • Irfan

      Hello Inger,

      As I have mentioned in the column, CSS columns-module is an emerging technology and even as of writing, a candidate recommendation (CR) — which means that although the document has been thoroughly reviewed by all of the stake holders, but still can change or evolve — hence, considering that it still is not a formally approved standard, expecting older browsers to produce desired results probably would be an unrealistic expectation.

      Considering the modular nature of the implementation of browser’s various processing modules, although updating the rendering engine of the older versions remains a possibility, I have my doubts that browser providers provide such patches.

      In case you’re planning to utilize the suggested solution, then either ask your viewers to upgrade to the latest version, or based on browser sniffing, choose the method best suited to their browser version, for example, the method chosen by Chrome Team for the linked book.