ALA Technical Style Guide

Hello, ALA folk! Here are some tips and markup patterns for producing ALA content. I’ve linked to some gists I’ve set up on GitHub, and in some cases embedded them, so if you have questions or would like to debate the choices we’ve made, feel free to leave comments there. Feel free to let me know if anything is missing. —Tim

Contents

Basic markup style

Whitespace versus P tags

We prefer markup to be as user-readable as possible, which luckily also means that we can use less code and more whitespace.

Here’s an example of some markup we’d prefer not to see in the system:

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.</p>
<p>Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc.</p>
<p>Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh.</p>

Content is much nicer and easier to work with if entered like this:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam.

Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc.

Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh.

We don’t need p tags; double line breaks will give us the whitespace and markup we need.

Whitespace gotchas

Unfortunately the ExpressionEngine text parser has some glitches in it, so here are a few things to keep in mind:

  1. Whitespace at the end of a line (such as a stray space or tab) can cause ExpressionEngine to generate an empty p tag.
  2. Empty lines (or extra line breaks between paragraphs) can cause ExpressionEngine to add unwanted br tags to the page.
  3. Indenting code in articles (but not code samples in pre > code tags) can cause ExpressionEngine some confusion.

None of these things are worth stressing about — just keep them in mind. As you’re proofing formatted articles, if you see some oddities in line-spacing, check to make sure that un-needed whitespace isn’t throwing things off.

Semantic versus stylistic markup

Please pay attention to those times when you are marking up text for stylistic purposes rather than semantic ones. Please don’t use strong or em tags when b or i would be sufficient.

Example:

Our favorite cruise was on the <i>Explorer of the Seas</i> and we <em>loved</em> it.

(<b>Note:</b> This was before everyone got all sick and was throwing up <strong>everywhere</strong>.)

This may seem like a small point, but it helps our content remain future-friendly.

UTF-8 & Special Characters

Because our HTML templates are UTF-8, we can get away without using most HTML entities. En dashes, em dashes, smart quotes, emoji even — almost everything will work.

Footnotes and translation links now go in their own separate fields; do not include them in the main content field.

Footnotes

Indicate a footnote marker in the content with the following markup:

<sup data-footnote>1</sup>

<sup data-footnote>2</sup>

… etc.

You do not need to link the marker to the note, nor do you need to link the note back to the marker; JavaScript automatically generates these links.

Translations

Translation links also have their own field, but — even better — foreign editors have the ability to add their own links, so we won’t need to worry about it too much.

Code samples

For blocks of code, use the pre > code pattern:

<pre><code class="language-">.x:hover { } 
.x:active { } 
 
.x:hover:before { } 
.x:active:before { }</code></pre>

Please note: Do not enter line breaks after the opening code tag, nor before the closing one. Because the code samples are white-space: pre formatted, those line breaks turn into unwanted whitespace in the layout.

Code formatting

Notice the class="language-" bit. This is a hook for the Prism code formatter. Finish the class with the relevant code type:

  • class="language-markup"
  • class="language-css"
  • class="language-javascript"

This is not strictly necessary, but it’s nice to have, especially for long chunks of JavaScript.

Tabs versus spaces

There are arguments to be made for either side, but we have chosen to fall on the side of tabs.

Smart quotes in code

You may have noticed that inline code blocks have smart quotes in them. This is another quirk of the ExpressionEngine text parser; it will create smart quotes within inline code blocks, but fortunately not within standalone pre > code blocks. We’ve chatted with the EllisLab folks about this, and it looks like they may fix this in a future release of EE.

Scripting Languages

Control structures such as parentheses require spacing on the outside only:

if (foo == bar) {
	// do something
}

An opening curly brace should be on the line of the command that uses it. The closing one should be on its own line (or if it is part of something like an else statement, on the line with the else:

if (foo == bar) {
	// do something
} else {
	// do something different
}

… or

if (foo == bar) {
	// do something
} else if (foo == rae){
	// do something different
}

CSS

For legibility, CSS blocks should be written with each property on a different line and with each selector on a different line.

p {
	color: #000;
	font-weight: bold;
}

em,
strong {
	font-size: 1.1em;
}

In-context code

code and var

Variables and properties should be marked using the var element, while all other bits of code should be wrapped in code tags.

Function and method references

Function and method references in paragraphs should always have their associated () unless being addressed specifically as a function or method:

In this section we pass the variable to <code>doSomething()</code> and we're off to the races.

or

In this section we pass the variable to the <code>doSomething</code> function and we're off to the races.
Inline CSS

CSS properties should be wrapped in code. Inline property assignments should not include the semicolon.

Then we set <code>color: #000</code> and go on about our business.

Demos

Demos, unless impractical for technical reasons, are to be hosted on the ALA server. Unlike uploading images, uploading demos requires FTP access. Ask a tech producer for help if you need it (Erin or Tim).

GitHub repos

If the article has files we’d like to share via GitHub, here’s the process for setting that up:

  1. Fork the author’s repo
  2. Turn issues off on our version
  3. Update the description with the article/issue number and URL
  4. Use the Readme to link to the original repo.

If there’s no repo to fork, go ahead and set one up, preferably giving the author full access so they can maintain it.

Embedded widgets

While we generally prefer not to embed widget (because it means, a. depending on a third-party’s account on a fourth-party’s service, and b. the code sample isn’t actually in the article (just a call to the code sample)), some widgets are workable.

CodePen pens are an example of an accpetable exception, because the embed code for pens comes with fallback HTML that we can alter so that it links to a local version of the demo in the case of a CodePen failure.

So: Feel free to use 3rd party widgets, as long as they are supported by a redundant copy on our own site. Take a gander at this blog post to really get a feel for it: Protecting Against Link Rot While Embracing the Future

<figure class="text full-width">
<p data-height="388" data-theme-id="0" data-slug-hash="BJrpg" data-default-tab="result" class='codepen'>See the demo: <a href='http://alistapart.com/d/390/ui-animation-and-ux-a-not-so-secret-friendship/demo-show-hide'>Show/hide example</a></p>
<script async src="//codepen.io/assets/embed/ei.js"></script>
<figcaption>Select items on the main nav to reveal the submenus.</figcaption>
</figure>

Code sample gotchas

Don’t forget to turn all open angle bracket characters (<) into HTML entities (&​lt;). Many times, if an article looks really messed up, the culprit is often an un-escaped open angle bracket.

In addition, ExpressionEngine has the unfortunate tendency of wanting to parse BBcode. Normally this isn’t a problem, but it’s unfortunate for us because the BBcode markup for italics is [​i​], which is a common thing to see in JavaScript samples. The answer? Replace [​i​] with [ i ]. The spaces will throw off the text parser, and it doesn’t affect the sample script at all.

(For the curious: how did I get those problematic examples to show up without causing problems? Stick zero-width-space entities in there: &​8203;)

Code Samples with Captions

<figure class="code">
<pre><code class="language-markup"><meta charset="utf-8"/></code></pre>
<figcaption>A UTF-8 encoding declaration should appear at the beginning of every <head> element.</figcaption>
</figure>

Blockquotes

For a blockquote, use the figure > blockquote + figcaption pattern. There are a couple flavors of this, all spelled out here:

That last “pullquote” variant is included for completeness, but don’t use it yet — we haven’t put CSS in place for it.

Figures

We support a few kinds of figures, and new ones keep popping up.

Images

All image figures are full-width; there are no half-column or floated image figures of any kind.

The “basic” versions will be what are used most frequently, but it would be good to encourage use of the hi-dpi and hi-dpi-with-small-screen-options versions as well. It means more production, but would make for a better world. We use the Filament Group’s Picturefill script to enable these responsive images.

(16/7/2015: The Picturefill snippets have been replaced with new standards-based snippets, and we have installed the latest Picturefill script for browsers that don’t yet support the new standard. The old Picturefill script will remain in place until we replace all the examples of the old pattern in articles. For reference, here are the old snippets.)

Optimizing images

Please consider running PNGs and JPGs through an app that losslessly reduces file sizes (beyond what Photoshop’s Save for Web does). For OS X I like ImageOptim; I’m not sure what the best option is for Windows.

Uploading images

Here’s the procedure for uploading in-content images (or any basic file type, really):

  1. Go to Content > Files > File Manager.
  2. For blog posts/ columns: In the left column select Misc Images.
  3. For articles: Right-click “In-Content Images” and create a new sub-folder for the issue (if it doesn’t already exist). Then click into that new sub-folder.
  4. Upload away.
  5. When the thumbnail appears, right click it and choose “View file.” (Note: you have to select the thumbnail before right clicking it to get the correct right-click menu.)
  6. Grab the URL of that image and paste it into your entry.

(Note that this procedure is for in-content images/files — not illustrations or member avatars/photos.)

Image sizes

The standard maximum width for an in-content image is 696px. (Illustrations scale to 50% of their actual size, so they should be 1920px for full-width.) Anything less than that is fine; anything more than that is technically fine too, but it means the browser will scale it down, which isn’t ideal.

Please be thoughtful about image sizes. Just because the max width is 696 doesn’t mean images should be 696 pixels wide by default — articles often benefit when we break the straight lines of the margins and introduce some elements that are less than the full width.

If the assets delivered by the author are hi-DPI/retina-ready, you will need to generate (or ask the author to generate) standard-DPI versions, and use the fourth or fifth pattern above to embed them into the content.

If the assets are particularly large, byte-wise, consider cutting small-screen-device users a break by creating some smaller assets for them, and use the fifth pattern to deliver it.

SVGs

We can support SVGs using the sixth pattern above. Because some common browser versions don’t support inline SVGs, we require a fallback.

Videos

If you’re just embedding a Vimeo or YouTube video, go ahead and drop the embed code provided by those services into a figure and call it a day. (Although, some tweaking of the embed code to reduce 3rd party interface elements and set an appropriate size wouldn’t go amiss.) Otherwise, a little more work is required to generate our video code snippets.

The maximum width for a video is 696px.

If all we have is a raw video file, the procedure requires a few steps.

  1. If not already done, convert the provided file to MP4 (H.264). Then create a second version using the WebM (vp8) format (this is for Firefox, which doesn’t yet support MP4). I like to use the dead-simple Miro Video Converter for OS X (not sure what the equivalent would be for Windows…).
  2. Upload those files just as you would upload any other image for an article.
  3. Head over to the Video for Everybody Generator and enter values for “MP4 Video,” “WebM Video,” “height,” and “width.” (The poster image is nice, but optional. The “Fallback Title” is better handled as a figcaption.)

Take the output of this and wrap it in a figure tag, and you’ll end up with something like this, which you can now drop into your article:

Note that there are two examples here — the first falls back to a Flash player, the second falls back to a simple image. Don’t use the flash version for now. We don’t have our own flash player in place.

This second example could be used for when the video isn’t necessary to the article, just cool or nice to have. A real-world example of this can be seen in this blog post, where the video is a simple screencast, and a single fallback image suffices if HTML5 video isn’t available.

Talk to Tim if you think it’s time we finally have our own flash player.

Tables

Here’s what a table generally looks like:

Member data
Name Email Position
Jeffrey Zeldman contact@alistapart.com Publisher
Tim Murtaugh contact@alistapart.com Technical Editor
Michelle Kondou michellekondou@gmail.com Web Developer
Figure 1: Headers as columns

This is the HTML that produces Figure 1 (please do not copy the HTML below to use in entries, there is a gist for the Figure 1 HTML further down).

<table>
<caption>Member data</caption>
	<thead>
		<tr>
			<th scope="col">Name</th>
			<th scope="col">Email</th>
			<th scope="col">Position</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td data-title="Name">Jeffrey Zeldman</td>
			<td data-title="Email">contact@alistapart.com</td>
			<td data-title="Position">Publisher</td>
		</tr>
		<tr>
			<td data-title="Name">Tim Murtaugh</td>
			<td data-title="Email">contact@alistapart.com</td>
			<td data-title="Position">Technical Editor</td>
		</tr>
		<tr>
			<td data-title="Name">Michelle Kondou</td>
			<td data-title="Email">michellekondou@gmail.com</td>
			<td data-title="Position">Web Developer</td>
		</tr>
	</tbody>
</table>

Best practices

We need to use the general structure: table > caption + thead + tbody for all tables (for semantics, accessibility and for the CSS to work as expected). Caption is optional, although it’s best practice to have one.

The <thead> element doesn’t contain data, it is simply the titles of columns. It wraps the first <tr> (it could wrap as many rows as needed that are all header information). When you use <thead>, there must be no <tr> that is a direct child of <table>. All rows must be within either the <thead>, <tbody>, or <tfoot>. Notice that we also wrapped all the rows of data in <tbody>.

If brief descriptive text is used to describe the table, for accessibility purposes that text should be contained within a <caption> element. The <caption> element must be the first thing after the opening <table> tag.

Responsive tables

For responsive tables to work we need to fill out the data-title attribute of the <td> element. The value of the <td> element data-title attribute must be the corresponding column header.

<td data-title="Name">Michelle Kondou</td>
Grab the HTML for Figure 1

Headers as rows
User costs What about your product might the user ignore if a form is onerous? Where will you keep all of this stuff?
Business costs How much time does a user really have to contribute to your form fields? What is the cost of updating, modifying, and potentially disposing of data?
Figure 2
Grab the HTML for Figure 2

To make a table header <th> or table cell <td> span more rows as in the example below use rowspan:

<th rowspan="2" scope="row">
A more complex structure
Name Username Email
Editors Caren Litherland caren contact@alistapart.com
Marie Connely marie contact@alistapart.com
Developers Tim Murtaugh tim contact@alistapart.com
Figure 3: Table with a subheader as row that spans 2 rows (Editors)
Grab the HTML for Figure 3

To make a table header <th> span more columns as in the example below use colspan:

<th colspan="2" scope="col">
User costs Business costs
Attention What about your product might the user ignore if a form is onerous? Data storage Where will you keep all of this stuff?
Time How much time does a user really have to contribute to your form fields? Data maintenance What is the cost of updating, modifying, and potentially disposing of data?
Figure 4
Grab the HTML for Figure 4

Inline styles

You can use <b>, <strong>, <em>, <cite>. For carriage returns within cells use <br> (although, before using <br> you should check whether you just need a cell <td> to span more rows <tr> using rowspan, as in Figure 3).

<td>Content<br>more content on new line</td>

Borders & backgrounds

We’ve created special classes for applying borders and backgrounds to individual rows <tr> and cells <td>. Note that some features such as zebra stripping and column borders are turned off for smaller resolutions (~ < 750px).

Borders (vertical and horizontal dividers)

You can apply borders to rows <tr> and cells <td>:

CELLS ROWS
Markup for left border: <td class="lb"> [...] </td> <tr class="lb"> [...] </tr>
Markup for right border: <td class="rb"> [...] </td> <tr class="rb"> [...] </tr>
Markup for top border: <td class="tb"> [...] </td> <tr class="tb"> [...] </tr>
Markup for bottom border: <td class="bb"> [...] </td> <tr class="bb"> [...] </tr>
Figure 5: Using classes to apply borders
Grab the HTML for Figure 5

To apply borders to a column (a set of vertical cells <td>) you would normally use <td class="lb"> on each cell (lb stands for left border). To make that easier we created classes that you need apply only once to the parent element, the <table> (as opposed to each cell in the column).

Border on the end of the first column: <table class="col-1"> [...] </table>
Border on the end of the second column: <table class="col-2"> [...] </table>
Border on the end of the third column: <table class="col-3"> [...] </table>
Border on the end of the fourth column: <table class="col-4"> [...] </table>

Figure 4 is an example of a table with a border on the end of the third column, using <table class="col-3"> [...] </table>.

Backgrounds

Note that tables are zebra stripped by default. Studies seem to show that zebra stripping is generally a good idea. To turn off zebra stripping apply class="zebraless" to the <table> element:

<table class="zebraless"> [...] </table>

After turning off zebra stripping, you can shade individual rows <tr> and cells <td> by applying class="bg" to the element:

Cell: <td class="bg"> [...] </td>
Row: <tr class="bg"> [...] </tr>
Examples:
Shaded Column
Header 1 Header 2 Header 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Figure 6
Grab the HTML for Figure 6

Shaded Cells
Header 1 Header 2 Header 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Figure 7
Grab the HTML for Figure 7

Shaded Row
Header 1 Header 2 Header 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Cell 1 Cell 2 Cell 3
Figure 8
Grab the HTML for Figure 8

Text alignment

By default all table content is aligned left, but you can use class="center" to center align content in individual cells <td>.

<td class="center"> [...] </td>

For example, in figure 5 above, the header and second column cells <td> are center aligned.
* Note that center alignment only works for cells <td> not rows <tr>.

Simple text

Sometimes, we just want to showcase a small piece of text as a figure:

<figure class="text">
<p>IA/UX → Design Comps → HTML Templates → CMS Integration</p>
</figure>

This, when in an article, renders like this:

IA/UX → Design Comps → HTML Templates → CMS Integration

An edge case, but useful when needed.

Full width

Occasionally you may come across something that needs more space; a good example might be an embedded demo from CodePen. The simple solution is to add the class full-width to your figure.

Interview / Q&A format

We have simple styles for formatting articles that are in a back-and-forth format:

<i>We sat down with <cite>A List Apart</cite> author, An Event Apart speaker, and IA Summit 2013 co-chair <a href="/author/kevinhoffman">Kevin M. Hoffman</a> to talk about what’s happening this year, and why you should come.</i>
 
<b>ALA: Who’s the IA Summit for?</b>
 
<b>KMH</b>: You don’t need to call yourself an information architect to come to the IA Summit. This is a conference for anyone invested in the “researchy,” “thinky,” or “structure-y” side of the design process—which I think is most of us, really.

There are three elements here:

  1. Intro graph (italicized)
  2. Question (bold)
  3. Answer (with leading initials)

Any post-interview content? End the interview section by starting a new section with an h2, then add text as you normally would.

Publishing tips

  • The “entry date” field is what determines when the entry will go live. We’re accustomed to this when working with articles and issues, as they’re always set to publish in the future, but we’ve been bitten a couple of times by columns or blog posts that have been in the works for a while, and go live with an entry date in the past. Strictly speaking this isn’t a huge problem, but it messes with RSS feeds.

Debugging content & Cache-busting

A few simple things to check for when fixing broken layouts:

  • un-closed tags
  • unescaped open angle brackets in code samples
  • instances of [​i​] in code samples
  • missing or extra whitespace in the markup
  • Code samples using double dashes inside a paragraph (use two html entities (8722) back to back to simulate the double dash inline).

We use CloudFlare as our CDN, which both protects us from abusive traffic and caches our pages to speed up delivery. This cache can cause problems when trying to edit or preview content, but there’s a trick: Add any query string to the end of any URL, and it will trigger CloudFlare to grab a new version of the page.

For example, if you’re working on this article:

http://alistapart.com/article/the-high-price-of-free

You can bust the cache for that URL by visiting this URL:

http://alistapart.com/article/the-high-price-of-free?bust

(The ?bust portion of that URL is totally arbitrary, but the existence of it tells CloudFlare to grab the latest version.)