HTML is the final product, not the initial source

HTML is the final product

In researching the technologies and tools that I use when developing digital content I’ve come across multiple discussions about what’s the best way to create HTML for X application (ebooks, web, transforming into other formats and any number of ideas. Some people think that HTML is perfect for everyone to write, regardless of experience and comfort with the technology. We forget that HTML now is very different to HTML as it was originally created.

HTML —which is short for HyperText Markup Language— is the official language of the World Wide Web and was first conceived in 1990. HTML is a product of SGML (Standard Generalized Markup Language) which is a complex, technical specification describing markup languages, especially those used in electronic document exchange, document management, and document publishing. HTML was originally created to allow those who were not specialized in SGML to publish and exchange scientific and other technical documents. HTML especially facilitated this exchange by incorporating the ability to link documents electronically using hyperlinks.

From http://www.ironspider.ca/webdesign101/htmlhistory.htm

The biggest issue, in my opinion, is that HTML has become a lot more complicated than the initial design. Creating HTML content (particularly when used in conjunction with CSS frameworks like Bootstrap or Zurb or with applications that use additional semantic elements like ePub) takes a lot more than just knowing markup to code them correctly. It takes knowledge of the document structure, the semantics needed for the content or the applications we are creating and the restrictions and schemas that we need to use so that the content will pass validation.

This article presents 4 different approaches to creating HTML. Two of them use HTML directly but target it as the final output for transformations and templating engines; the other two use markup like HTML without requiring strict HTML conformance. I’ve made these selections for two reasons:

  • People who are not profesionals should not have to learn all the details of creating an ePub3 table of content or know the classes to add to elements to create a Bootsrap or Foundation layout grid
  • It makes it easier for developers and designers to build the layout for the content without having to worry about the content itself; we can play with layout and content organization in parallel with content creation and, if we need to make any further changes, we just run our compilation process again

Markdown

Perhaps the simplest solution when moving content from text to HTML is Markdown.

Markdown is a text to (X)HTML conversion tool designed for writers. It refers both to the syntax used in the Markdown text files and the applications used to perform the conversion.

Markdown language was created in 2004 by John Gruber with the goal of allowing people “to write using an easy-to-read, easy-to-write plain text format, and optionally convert it to structurally valid XHTML (or HTML)” (http://daringfireball.net/projects/markdown/)

The language was designed to be readable as-is, without all the additional tags and attributes that makes it possible to covert markdown to languages like SGML, XML and HTML. Markdown is a formatting syntax for text that can be read by humans and can be easily converted to HTML.

The original implementation of Markdown is markdown.pl and has been implemented in several other languages as applications (Ruby Gems, NodeJS modules and Python packages). All versions of Markdown are distributed under open source licenses and are included or available as a plugin for, several content-management systems and text editors.

Sites such as GitHub, Reddit, Diaspora, Stack Overflow, OpenStreetMap, and SourceForge use variants of Markdown to facilitate content creation and discussion between users.

The biggest weakness of Markdown is the lack of a unified standard. The original Markdown language hasn’t been really supported since it was released in 2004 and all new version of Markdown, both parser and language specification have introduced not wholy compatible changes to Markdown. The lack of standard is also Markdown’s biggest strength. It means you can, like Github did, implement your own extensions to the Markdown syntax to acommodate your needs.

Markdown is not easy to learn but once your fingers get used to the way we type the different elements it becomes much easier to work with as it is nothing more than inserting specific characters in a specific order to obtain the desired effect. Once you train yourself, it is also easy to read without having to convert it to HTML or any other language.

Most modern text editors have support for Markdown either as part of the default installation or through plugins.

Example Markdown document

Markdown example form daringfireball

Asciidoctor

I only discovered Asciidocs recently, while researching O’Reilly Media’s publishing toolchains. It caught my attention because of it’s structure, the expresiveness of the markup without being HTML like HTMLbook and the extensibility of the templating system that it uses behind the scenes.

Asciidoctor has both a command line interface (CLI) and an API. The CLI is a drop-in replacement for the asciidoc command from the Standard python distribution. This means that you have a command line tool asciidoctor that will allow you to convert your marked documents without having to resort to a full blown application.

Syntax-wise, Asciidoctor is progressively more complex as you implement more advanced features. In the first example below no tables are used, for example. Tables are used in the second and thirs examples both as data tables and for layout.

The documentation provides more detailed instructions for the desired markup.

Example Asciidoc documents

HTMLBook

O’Reilly Media has developed several new tools to get content from authors to readers. Atlas is their authoring tool, a web based application that allows you to create content they developed HTMLbook, a subset of HTML geared towards authoring and multi format publishing.

Given O’Reilly’s history and association with open source publishing tools (they were an early adopter and promoter of Docbook and still use it for some of their publications) I found HTMLbook intriguing but not something to look at right away, as with many things you leave for later it fell off my radar.

It wasn’t until I saw Sanders Kleinfeld’s (O’Reilly Media Director of Publishing Technologies) presentation at IDPF Book World conference (embedded below) that I decided to take a second look at HTMLbook and its ecosystem.

Conceptually HTMLbook is very simple; it combines a subset of HTML5, the semantic structure of ePub documents and other IDPF specifications to create a flavor of HTML 5 that is designed specifically for publishing. There are also stylesheets that will allow you to convert Markdown and other text formats into HTMLbook (see [Markdown to HTMLBook(https://github.com/oreillymedia/htmlbook.js) and AsciiDoc to HTMLBook (via AsciiDoctor).)

If you use Atlas (O’Reilly’s authoring and publishing platform) you don’t have to worry about markup as the content is created visually. The challenges begin when implementing this vocabulary outside the Atlas environment.

The project comes with a set of stylesheets to convert HTMLbook content to ePub, MOBI and PDF. The intriguing thing about the stylesheets is that they use CSS Paged Media stylesheets in conjunction with third party tools such as AntennaHouse, PrinceXML or their open source counterparts like XHTML2PDF or wkhtmltopdf.

The open source solutions offer permisive licenses that allow modification and integration into other products without requiring you to release your project under the same license like GPL and LGPL.

As with any solution that advocates creating HTML directly I have my reservations. In HTML formating in general and specialized formats like HTMLbooks in particular, the learning curve may be too steep for independent authors to use for creating content.

The user must learn not only the required HTML5 syntax but also the details regarding ePub semantic structure attributes and the other standards needed to create ePub books. While I understand that technologies such as this are not meant for independent authors or for poeple who are not comfortable or familiar with HTML but the learning curve may still be too steep for most users.

Example HTMLbook document

XML / XSLT

Perhaps the oldest solutions in the book to create HTML without actually creating HTML are XML-based. Docbook, TEI and DITA all have stylesheets that will take the XML content and convert it to HTML, PDF, ePub and other more esoteric formats.

In addition to stylesheets already available developers can create their own to adress specific needs.

Furthermore, tools like OxygenXML Author (and I would assume other tools in the same category have a visual mode that allow users to write XML content, validated against a schema in a way that is more familiar to people not used to creating content with raw XML tools.

The issues with xml are similar to those involved in creating HTML. The markup vocabulary requires brackets, attributes have to be enclosed in quotation marks and generall the syntax is as complicated as you make it. However, tools like Oxygen and smilar help alleviate this problem but don’t resolve it completely.

The screenshot below shows OxygenXML Author working in a Docbook 5 document using visual mode.

Visual editing using OxygenXML Author
Visual editing using OxygenXML Author

The positive side is that using XSLT there is no limit to what we can do with our XML content.

XML examples

Conclusion

After exploring a selection of HTML conversion options the question becomes which one is best?

The answer is it depends.

The best way to see how can these text-based tools can be incorporated is to ask yourself how much work you want to do in the backend versus how much work do you want you authors to do when creating the content. This is where the value of specialists in digital formats and publishing becomes essential, we can work with clients in providing the best solution to meet their needs.

Keep in mind who your audience and what the target vocabulary you’re working towards, it will dictate what your best strategy is. Are these all the solutions; definitely not. Other solutions may appear that fit your needs better than those presented here; I would love to hear if that is the case.

Striking the balance between author and publisher is a delicate one. I tend to fall on the side of making things easier for authors… The tools can be made to translate basic markup into the desired result with minimal requirements for authors to mark up the content; the same can’t necessarily be said about the publisher-first strategy

Epubcheck 4 is in the horizon

Epubcheck 4 is in the horizon, you should take another look at your books.

ePubcheck 4, the IDPF validator is currently in Alpha and available for download if you want test it. I downloaded it and made a first pass to what I thought was a valid book and was, not so pleasantly, surprised at how much it has changed.

I say not so pleasantly surprised because of the additonal breadth of checks the tools performs and the cryptic nature of the messages has prompted me to rethink the way in which my documents are laid out, particularly considering that I use Docbook to generate my epub content and it’s not laid out as standard HTML (uses tables to layout content wich means the table doesn’t need the same structure needed for data tables… I know… so 1990s but I did not create the stylesheets).

I’m concerned that publishers will use the new litmus test of epubcheck 4 to reject books taht would have normally passed the epubcheck 3.0.1 validation test.

The positive side of all these warnings is that documents will be more accessible because of the additional checks, assuming that authors (and publishers) bother with implementing any of the rules their books are flagged for.

Visualizing CSS properties

One of my earliest experiments in data visualization was to create visualization of the CSS properties as they are documented in the Web Platform Documentation project. Now that it’s in a shape where I’m willing to let it out in the wild it’s time to write about it and explain the rationale and the technology.

Rationale

I’m a visual person. Rather than search for something that I may or may not know exactly what it is, I’d rather look at something that, I hope, will make it easier for me to find what I’m looking for.

I’m also lazy. Instead of looking for a property in one place and then manually typing the full URL of the Web Platform Documentation project I’d rather add the URLs for all properties directly to the visualization so that, when the I find the property he’s looking for, I can go directly to it from the visualization tree.

Building the visualization

The data

The first thing I did was to pull the data from the Web Platform Documentation project using their API to generate an initial JSON file. I then had to edit the file manually to produce something closer to the JSON format that I was looking for:

[javascript]
{
“name”: “CSS”,
“children”: [
{
“name”: “Alignment”,
“children”: [
{
“size”: 1000,
“name”: “align-content”,
“url”: “http://docs.webplatform.org/wiki/css/properties/align-content”
},
{
“size”: 1000,
“name”: “align-items”,
“url”: “http://docs.webplatform.org/wiki/css/properties/align-items”
},
{
“size”: 1000,
“name”: “align-self”,
“url”: “http://docs.webplatform.org/wiki/css/properties/align-self”
},
{
“size”: 1000,
“name”: “alignment-adjust”,
“url”: “http://docs.webplatform.org/wiki/css/properties/alignment-adjust”
},
{
“size”: 1000,
“name”: “alignment-baseline”,
“url”: “http://docs.webplatform.org/wiki/css/properties/alignment-baseline”
}
]
}
]
}
[/javascript]

Every time I edited or made a change to the JSON file (the resulting full JSON file is about 2500 lines of code) I ran it through JSON lint to make sure that the resulting content was valid JSON. I haven’t always done this and it has been a constant source of problems: The page appears blank, only part of the content is displayed and other anoyances that took forever to correct.

Once we have the JSON file working, we can move into the D3 code.

The technology

D3.js is a JavaScript library for manipulating documents based on data. D3 helps you bring data to life using HTML, SVG and CSS. D3’s emphasis on web standards gives you the full capabilities of modern browsers without tying yourself to a proprietary framework, combining powerful visualization components and a data-driven approach to DOM manipulation.
From http://d3js.org

What this means is that we can build visual content based on data have collected or arbitrary data we have available. In this case we are visualizing an arbitrary grouping of CSS properties from the Web Platform Documentation project; all properties are listed but the grouping may change as the group comes to a consensus regarding the groups.

D3 follows a fairly straightforward process. We start by defining all our variables at the top of the script to prevent Javascrp variable hoisting. The code looks like this:

[javascript]
// Starting values were:
// width: 2140 – margin.right – margin.left
// height : 1640 – margin.top – margin.bottom
var margin = {top: 20, right: 120, bottom: 20, left: 120},
width = 1070 – margin.right – margin.left,
height = 820 – margin.top – margin.bottom;

var i = 0,
duration = 750,
root

var tree = d3.layout.tree()
.size([height, width]);

var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
[/javascript]

We create the SVG-related elements that we need in order to display the visualization data. The steps in the code below are:

  • Select the body of the document
  • Append the svg element
  • Set up width and heigh attributes with default values
  • Create a SVG group (indicated by the <g> tag) and translate it (move it by the ammount indicated by the top and left margin)

[javascript]
var svg = d3.select(“body”)
.append(“svg”)
.attr(“width”, width + margin.right + margin.left)
.attr(“height”, height + margin.top + margin.bottom)
.append(“g”)
.attr(“transform”, “translate(” + margin.left + “,” + margin.top + “)”);
[/javascript]

We load the JSON file using D3’s JSON loader and set up the root element and its position.

The function collapse makes sure tha elements without children are collapsed when we first open the visualization page. I wanted to make sure that users would not be overwhelmed with all the information available in the visualization and had a choice as to what items they would click and what information they’d access.

Preventing children from automatically displaying also prevents the clutter of the tree. If there are too many children open the vertical space gets reduced and it becomes hard to distinguish which item we are clicking in.

I’ve also set a default height for all elements… 100px sounds good at this stage.

[javascript]
d3.json(“json/css-data.json”, function(error, css) {
root = css;
root.x0 = height / 2;
root.y0 = 0;

function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
} root.children.forEach(collapse);
update(root);
});

d3.select(self.frameElement).style(“height”, “100px”);
[/javascript]

Because the click will change the nature of the layout and the number of visible elements we need to update the layout everytime the user clicks on a valid element. This wil involve hidding old elements,showing showing new nodes in the tree.

[javascript]
function update(source) {

// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);

// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 200; });

// Update the nodes…
var node = svg.selectAll(“g.node”)
.data(nodes, function(d) { return d.id || (d.id = ++i); });

// Enter any new nodes at the parent’s previous position.
var nodeEnter = node.enter().append(“g”)
.attr(“class”, “node”)
.attr(“class”, function(d) {
if (d.children) {
return “inner node”
} else {
return “leaf node”
}
})
.attr(“transform”, function(d) { return “translate(” + source.y0 + “,” + source.x0 + “)”; })
.on(“click”, click);
[/javascript]

Using D3’s Enter/Append/Exist system we go back into the nodes we created, we append a new circle and set its radius and color (lines 1 – 3 in the code below).

Next I add the text for each node, set up their X (line 5) and Y (line 6) coordinates for the text node. I’ve aligned the text usin a D3 trick where setting the Y value to .35em centers the text vertically.

For each leaf node I set up a link as only elements without children have URL attributes. We do this in two steps:

  • Append a SVG anchor element (svg:a) which is different than our regular HTML anchor (line 7)
  • Add an Xlink, the XML vocabulary for defining links between resources (line 8) using the xlink:href syntax

Finally, we setup and place the linkend attribute for each node in such a way that nodes with children will display their text to the left of the assigned circle and nodes without children will display the text to the right of the circle (line 11)

[javascript]
nodeEnter.append(“circle”)
.attr(“r”, 1e-6)
.style(“fill”, function(d) { return d._children ? “lightsteelblue” : “#fff”; });
nodeEnter.append(“text”)
.attr(“x”, function(d) { return d.children || d._children ? -10 : 10; })
.attr(“dy”, “.35em”)
.append(“svg:a”)
.attr(“xlink:href”, function(d){return d.url;})
.style(“fill-opacity”, 1)
.text(function(d) { return d.name; })
.attr(“text-anchor”, function(d) { return d.children || d._children ? “end” : “start”; });
[/javascript]

Most of the remaining work is to transition elements to and from their current position. This would be so much easier if we were using a library such as jQuery or Dojo but the result is worth the additional code.

The duration for all transitions is hardcoded to 750 miliseconds. Whether duration affects the user experiecne is an area to look further into.

[javascript]
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr(“transform”, function(d) { return “translate(” + d.y + “,” + d.x + “)”; });

nodeUpdate.select(“circle”)
.attr(“r”, 4.5)
.style(“fill”, function(d) { return d._children ? “lightsteelblue” : “#fff”; });

nodeUpdate.select(“text”)
.style(“fill-opacity”, 1);

// Transition exiting nodes to the parent’s new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr(“transform”, function(d) { return “translate(” + source.y + “,” + source.x + “)”; })
.remove();

nodeExit.select(“circle”)
.attr(“r”, 1e-6);

nodeExit.select(“text”)
.style(“fill-opacity”, 1e-6);

// Update the links…
var link = svg.selectAll(“path.link”)
.data(links, function(d) { return d.target.id; });

// Enter any new links at the parent’s previous position.
link.enter().insert(“path”, “g”)
.attr(“class”, “link”)
.attr(“d”, function(d) {
var o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
});

// Transition links to their new position.
link.transition()
.duration(duration)
.attr(“d”, diagonal);

// Transition exiting nodes to the parent’s new position.
link.exit().transition()
.duration(duration)
.attr(“d”, function(d) {
var o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
})
.remove();

// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
[/javascript]

The final bit of magic is to use D3’s onClick event to toggle the display of our content.

[javascript]
var svg
// Toggle children on click.
function click(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
update(d);
}
[/javascript]

Where to go next?

There are some areas I want to further explore as I move forward with the visualization and learn more about how to visualize data:

  • Does the length of the transitions change the way people react to the data?
  • How can we control the space between items when they are too many open?

I will post the answers to these questions as I find the answers 🙂

HTML as a single source format

In this essay I will take what may be an unpopular position: Using HTML with XML syntax (XHTML) is currently the best format to put your content in because it is easier to convert from XHTML/CSS to pretty much any other format. In making this case we’ll explore and work in the following areas and answer the following questions:

Definitions

When we speak about XHTML in this document we refer to an HTML document using XHTML syntax. I will not change the mime type on the server to fully comply with XHTML restrictions.

Why XHTML

The two main reasons I advocate XHTML as an authoring format are

XHTML enforces code clarity and authoring discipline

XHTML limits the freeform structure of HTML5. Documents conforming to XHTML specifications must have, at a minimum:

  • A DOCTYPE declaration
  • An HTML element
  • A HEAD element
  • TITLE element
  • BODY element

The structure written as XHTML tags looks like this:

[xml]
<!DOCTYPE html>
<html>
<head>
<title>Title Goes Here<title>
<head>
<body>
<h1>Content Area</h1>
<body>
<html>
[/xml]

This minimal structure must comply with the requirements below

All XHTML tag names & attribute names must be in lowercase

All XHTML attributes and elements must be in lower case

The following elements are not legal XHTML:

[xml]
<DIV CLASS=”chapter”>Chapter 1</div>

<Div Class=”chapter”>Chapter 1</div>
[/xml]

All XHTML elements must close

All elements must be closed, this includes both our standard tags such as the paragraph tag

[xml]
<p>This is a paragraph</p>
[/xml]

to empty elements such as images and form inputs elements

[xml]
<img src=”images/test.png” height=”800″ width=”600″ alt=”Test image” />

<input type=”submit” value=”Submit” />
[/xml]

All XHTML elements must be properly nested

XHTML insists on proper nesting of the elements on our content. This is no longer legal

[xml]
<p>This is the content of a paragraph

<p>This is our second paragraph
[/xml]

And it should be writen like this:

[xml]
<p>This is the content of a paragraph</p>

<p>This is our second paragraph</p>
[/xml]

All XHTML attribute values must be quoted

In addition to being lowercased, attributes must be quoted. Rather than:

[xml]
<div class=chapter>Chapter 1</div>
[/xml]

It has to be written like this:

[xml]
<div class=”chapter”>Chapter 1</div>
[/xml]

Because it is structured, we can use transformation tools to convert to/from XHTML

A lot of the discussions I’ve had with people seem to focus in the drawbacks of XHTML format as end users. One of the strengths W3C cited when moving to XHTML as the default format for the web was how easy it was for machines to read it and covert it to other formats.

I’ll cover two examples using Markdown: straigth transformation and converting Markdown into templated XHTML and an example of using XSLT 1.0 to covert one flavor of XHTML into another using Xsltproc

From markdown to html, straight up

One of the goals of Markdown is to: allow you to write using an easy-to-read, easy-to-write plain text format, then convert it to structurally valid XHTML (or HTML). The original tool and all its ttranslations to other languages are built to allow the conversion; where they are different is in the number of extensions to the core markdown language and the language the tools themselves are written on.

For these examples I chose Python Markdown mostly because it’s the language and the tool I’m familiar with. We will use the markdown file for the Markdown home page at Daring Fireball http://daringfireball.net/projects/markdown/index.text

Below is a portion of the resulting XHTML code:

[xml]
<h2>Introduction</h2>

<p>Markdown is a text-to-HTML conversion tool for web writers. Markdown
allows you to write using an easy-to-read, easy-to-write plain text
format, then convert it to structurally valid XHTML (or HTML).</p>

<p>Thus, “Markdown” is two things: (1) a plain text formatting syntax;
and (2) a software tool, written in Perl, that converts the plain text
formatting to HTML. See the <a href=”/projects/markdown/syntax”>Syntax</a> page for details pertaining to
Markdown’s formatting syntax. You can try it out, right now, using the
online <a href=”/projects/markdown/dingus”>Dingus</a>.</p>

<p>The overriding design goal for Markdown’s formatting syntax is to make
it as readable as possible. The idea is that a Markdown-formatted
document should be publishable as-is, as plain text, without looking
like it’s been marked up with tags or formatting instructions. While
Markdown’s syntax has been influenced by several existing text-to-HTML
filters, the single biggest source of inspiration for Markdown’s
syntax is the format of plain text email.</p>

<p>The best way to get a feel for Markdown’s formatting syntax is simply
to look at a Markdown-formatted document. For example, you can view
the Markdown source for the article text on this page here:
<a href=”http://daringfireball.net/projects/markdown/index.text”>http://daringfireball.net/projects/markdown/index.text</a></p>
[/xml]

The conversion process itself is simple. Using the Perl version it looks like this:

markdown content/webgl-2d-scale.md > test.html

From Markdown to templated XHTML

As part of my sunshine-markdown project I’ve researched ways to convert markdown to XHTML. as

[10:30:54] carlos@rivendell sunshine-markdown 4826$ ./sunshine --verbose
processing:  content/webgl-2-textures.md
processing:  content/webgl-2d-matrices.md
processing:  content/webgl-2d-rotation.md
processing:  content/webgl-2d-scale.md
processing:  content/webgl-2d-translation.md
processing:  content/webgl-2d-vs-3d-library.md
processing:  content/webgl-3d-camera.md
processing:  content/webgl-3d-orthographic.md
processing:  content/webgl-3d-perspective.md
processing:  content/webgl-3d-textures.md
processing:  content/webgl-and-alpha.md
processing:  content/webgl-animation.md
processing:  content/webgl-boilerplate.md
processing:  content/webgl-fundamentals.md
processing:  content/webgl-how-it-works.md
processing:  content/webgl-image-processing-continued.md
processing:  content/webgl-image-processing.md
processing:  index.md 

Sunshine is hardcoded to put the content of each markdown file into a template that looks something like this:

[xml]
< ?xml version=”1.0″ encoding=”UTF-8″?>





%(title)s

%(title)s

%(content)s



[/xml]

Using XSLT to convert XHTML into ePub-ready XHTML

One of the things we forget is that, because XHTML is structured content we can use XSLT and XPATH to convert it to other XML-based dialects, such as the XHTML dialect required for ePub3 conformance. A basic template to convert a div into a section with the proper attributes for ePub work may look something like this:

[xml]
< ?xml version=”1.0″?>








[/xml]

Flex Boxes and the Holy Grail

There is an updated post New in the CSS horizon: flexbox to be published shortly with updated code and better explanations. I refer you to that article for an update on how Flexbox works and better (and fully tested) working examples.

 

Content and images taken from Mozilla Developer Network Flexbox Page and A Complete Guide to Flexbox

One of the hardest things to do in web design is to create a fluid 3 column layout, also known as the holy grail. I could talk for hours about how it was goo enough for the technologies available when the model was first developed, how much of a pain it is to implement correctly, how it did not support mobile and small form devices and how long have developers wanted a solution.

Example of Holy Grail Layout
Example of Holy Grail Layout. Courtesy of Litesite

Instead I will talk about a solution that has finally become widely available. With the release of Firefox 28 to wide availability, the last of the big 4 browsers now supportd the full flexible box layouts specificactions. This means we can do some awesome crazy things with layouts that, until now we could only dream about.

In this article I will explain what Flexboxes are, the terminology, syntax, new CSS required to make it work and end with reworking the Holy Grail Layout using Flexboxes.

Getting things setup

Flexboxes don’t use the same terminology as other CSS elements. We need to discuss this terminology before we can fully understand and use the new layout in our own work.

Flex Container

The outermost container for our Flex Layout. We create this by assigning flex or inline-flex as the values of the display property depending on whether you want to use the Flex Container as a block or inline element.

.flex-container {
  display: flex
  /*  If you want the container to be a block element*/
}

or

.container {
  display: inline-flex
  /*  If you want the container to be an inline element*/
}

Each Flex Box container defines two axes:

  • A main axis that defines how the elements flow in the container
  • A cross axis that is perpendicular to the main

flex-direction

The flex-direction attribute defines the main axis (start, direction, end) for the container. It can take one of 4 values:

  • row: The flex container’s main-axis is defined to be the same as the text direction. The elements in the container flow in the same direction as the page content (left to right in the case of English)
  • row-reverse: The flex container’s main-axis is defined to be the same as the text direction. The elements in the container flow in the opposite direction to the page content (right to left in the case of English)
  • column: The flex container’s main-axis is defined to be the same as the block-axis. The main-start and main-end points are the same as the before and after points of the writing-mode (top to bottom in English)
  • column-reverse: The flex container’s main-axis is defined to be the same as the block-axis. The main-start and main-end points are reversed from the before and after points of the writing-mode (bottom to top in English)
.content {
  flex-direction: row;
}

flex-wrap

  • nowrap (default): single-line / left to right in ltr; right to left in rtl
  • wrap: multi-line / left to right in ltr; right to left in rtl
  • wrap-reverse: multi-line / right to left in ltr; left to right in rtl
.content {
  flex-direction: row;
  flex-wrap: wrap;
}

flex-flow

This is a shortcut for flex-direction and flex-wrap which together define both the main and cross axes. The default value is:

.container {
  flex-flow: "row nowrap"
}

justify-content

Justify content takes a special meaning when used in flex boxes: It tells the browser how to arrange the content of the container in its main axis. It can take the following values:

  • flex-start (default): items are packed toward the start line
  • flex-end: items are packed toward to end line
  • center: items are centered along the line
  • space-between: items are evenly distributed in the line; first item is on the start line, last item on the end line
  • space-around: items are evenly distributed in the line with equal space around them
.content {
  flex-direction: row;
  justify-content: space-around;
}

align-items

align-items controls the vertical positioning of the row’s element. It is the vertical counterpart to align-items. It can take the following values:

  • flex-start: cross-start margin edge of the items is placed on the cross-start line
  • flex-end: cross-end margin edge of the items is placed on the cross-end line
  • center: items are centered in the cross-axis
  • baseline: items are aligned such as their baselines align
  • stretch (default): stretch to fill the container (still respect min-width/max-width)

align-content

Controls the use of the rermaining vertical space within a flex-container’s row. This has no effect if there is only one row on the

  • flex-start: lines packed to the start of the container
  • flex-end: lines packed to the end of the container
  • center: lines packed to the center of the container
  • space-between: lines evenly distributed; the first line is at the start of the container while the last one is at the end
  • space-around: lines evenly distributed with equal space between them
  • stretch (default): lines stretch to take up the remaining space

Flex Item

Every element inside our Flex Container becomes a Flex Item. When we put text on the page as a direct child of the Flex Box it’ll be wrapped on an implicit flex item. There is no need to declare these elements explicitly.

order

Indicates the order (positive numbers without a unit) in which the items in a row are displayed. The default is to display them in source order.

.content-item1{
  order: 1;
}

flex-grow

Indicates the proportion that an item can grow by if necessary.

If all items have flex-grow set to 1, every child will set to an equal size inside the container. If you were to give one of the children a value of 2, that child would take up twice as much space as the others.

In the example below, item2 will take twice as much space as item1 and item3 if more space becomes available:

#item1 {
  grow: 1;
}
#item2{
  grow: 2;
}

#item3{
  grow: 1;
}

flex-shrink

Indicates the proportion that an item can shrink by if necessary.

If all items have flex-shrink set to 1, every child will set to an equal size inside the container. If you were to give one of the children a value of 2, that child would take up twice as much space as the others.

flex-basis

This defines the default size of an element before the remaining space is distributed.

Supported values:

  • length
  • auto

The default is auto

flex

This is the shorthand for flex-grow, flex-shrink and flex-basis. The flex-shrink and flex-basis parameters are optional.

Default is 0 1 auto.

align-self

If this property is set, it will override the align-item property of the parent.

  • flex-start: cross-start margin edge of the items is placed on the cross-start line
  • flex-end: cross-end margin edge of the items is placed on the cross-end line
  • center: items are centered in the cross-axis
  • baseline: items are aligned such as their baselines align
  • stretch (default): stretch to fill the container (still respect min-width/max-width)

The Holy Grail with Flex Boxes

Working example in Codepen:

See the Pen First Attempt at Flexbox by Carlos Araya (@caraya) on CodePen.2039

There is an updated Codepen with better results all around, including the fact that you get equal columns for free 🙂

The pen is copied below. Edit the pen in Codepen to see the full layout.

See the Pen Holy Grail Layout using Flexbox by Carlos Araya (@caraya) on CodePen.2039

Browser compatibility

Taken from Mozilla Developer Network Flexbox Page

Desktop Browsers

Feature Firefox (Gecko) Chrome Internet Explorer Opera Safari
Basic support (single-line flexbox) 18.0 (18.0)-moz(Behind a pref) [2]
22.0 (22.0) [2]
21.0-webkit
29.0
11 [3] 12.10
15-19 -webkit
6.1-webkit [1]
Multi-line flexbox 28.0 (28.0) 21.0-webkit
29.0
11 [3] 12.10
15-19 -webkit
6.1-webkit [1]

Mobile Browsers

Feature Firefox Mobile (Gecko) Android IE Phone Opera Mobile Safari Mobile
Basic support (single-line flexbox) 18.0 (18.0)-moz(Behind a pref) [2]
22.0 (22.0) [2]
? ? 15-19 -webkit 7-webkit [1]
Multi-line flexbox 28.0 (28.0) ? ? 15-19 -webkit 7-webkit [1]

1

Notes

[1] Safari up to 6.0 ( 6.1 for iOS ) supported an old incompatible draft version of the specification. Safari 6.1( 7 for iOS ) has been updated to support the final version

[2] Up to Firefox 22, to activate flexbox support, the user has to change the about:config preference “layout.css.flexbox.enabled” to true. From Firefox 22 to Firefox 27, the preference is true by default, but the preference has been removed in Firefox 28

[3] Internet Explorer 10 supports an old incompatible draft version of the specification; Internet Explorer 11 has been updated to support the final version.