HTML Standards

Currently, the Spike HTML Standard stack includes jade, markdown, and smartypants on top of posthtml. The rationale behind each of these decisions is explained below. While the tools used to implement these features are subject to change in the future (especially jade), the features themselves we will not give up.

Whitespace Sensitivity

Writing html without correctly indenting is generally considered a major development sin. Generally, any deeply nested data structure should be written indented to preserve developer sanity. As such, just about all html written by professional developers you will find to be indented.

HTML itself, however, does not care in the least whether it's indented or not. So the indentation is simply used for human purposes, and when it comes to the code, it's basically a waste.

In that case, why not actually use the indentation for something? Making html whitespace-sensitive offers a couple nice benefits:

  1. It forces developers to correctly indent their html, which should happen anyway
  2. It makes for much cleaner markup because you don't need to write close tags

As such, whitespace-sensitive HTML is part of the Spike Standard stack.

div(id='foo')
  p hello there

An additional extremely useful feature for whitespace-based layouts is the ability to one-line more than one element, if one element simply wraps the other one. For example:

ul
  li: a(href='foo') bar

Here, the : is used to denote another element being nested inside the li without explicitly needing to newline and indent. This only works with an empty element that contains one other element. If the element has text content or contains two or more elements, it must use the normal indented syntax.

Layouts

Unless you are just making a single page with html, you will have shared elements that you want to repeat across all your pages. The <head> element, for example, or maybe your navigation and footer. Repeating these elements on every page is a big waste of time and is not DRY.

Having a layout system solves this problem nicely. Jade pioneered a fantastic layout system based on blocks and extends, that you can see boiled down to its essence here.

Essentially, when you extend another html file, we'll call it a layout, you take the content of the layout and import it into your own. You then have an opportunity to override the contents of any block in the layout. If you provide a block with content, it will override the content in the layout's block. If you don't, the layout's block is preserved.

Let's look at a quick example to get a feel for the basics:

extends layout

block title
  title Custom Page

block content
  p hello world!
html
  head
  	block title
      title Homepage
  body
    block content
    block footer
      footer
      	p Copyright etc etc

The above code is compatible with jade, but any system that uses whitespace-sensitive html and a block/extend system should also work with this code.

In this example, the index page overrides the title and content blocks, and leaves the footer block intact. The final rendered page will look something like this:

<html>
  <head>
    <title>Custom Page</html>
  </head>
  <body>
    <p>hello world!</p>
    <footer>
      <p>Copyright etc etc</p>
    </footer>
  </body>
</html>

Includes

Sometimes you have a piece of html that you want to use in more than one place. Copy/pasting it between the two is not DRY, so we need includes for this. Similar concept to layouts, but a different implementation.

p hello from a partial!
p hello from the index!
include partial.html

This code would compile to html looking like this:

<p>hello from the index!</p>
<p>hello from a partial!</p>

Expressions

Importing data into your html from a different format is an important ability to have. For example, you can use a JSON or yaml file to organize data, or import it from an API or CMS, then generate it into an html template.

In order to do this, you need to be able to evaluate basic javascript expressions within your html. For example, you want to be able to print out a variable, loop through an array, etc. For example:

p= foo + (1 + 6)

Given { foo: 'bar' } when compiling should yield:

<p>bar7</p>

Here, = is used to evaluate buffered code (jade syntax), but really the syntax is not super important. {{ var }} is also a common syntax, and equally valid. Switching to different delimiters is not an enormous overhead for people jumping into an application, so that part of the standard is open to change.

There must also be a way to evaluate unescaped unbuffered code. For example:

p!= "<span>hello!</span>"

Here, because of the !, the html entities are not escaped and the span will render as a normal element. This can be dangerous if linked to user input, but is necessary to have.

There must also be a way to interpolate an expression into the middle of other content. With jade, because of the tag= syntax, this operation uses a slightly different syntax. If using {{ style delimiters, it would remain the same.

p= Hello #{planet}!

Looping

There also must be a way to loop through data. For example

ul
  for item in items
    li= item.name

Given { items: [{ name: 'foo' }, { name: 'bar' }] } when compiling should yield

<ul>
  <li>foo</li>
  <li>bar</li>
</ul>

Again, the syntax above is jade's, but the specific syntax used for the looping is not nearly as important as the ability to loop. Adapting to different syntax for this is trivial for developers, as long as there's a reference/docs.

This could in theory be accomplished through evaluating an unbuffered expression, but the syntax would be messier, and it would need a special adaptation to work with a whitespace-singificant parser, so a custom looping implementation is preferred.

Conditionals

If using data in a template, you must be able to conditionally display it. For example:

h1 My Great Website
if environment === 'development'
  p Warning, not a production site!

Although the syntax cold be modified (require parens or not, at symbol before the conditional statement, etc), the ability to evaluate an expression to true/false and conditionally display content based on this is what's important here.

Markdown

Writing long form rich text in html is a very unfortunate experience, and is quite difficult to read and edit. Including inline tags for bold and italic text, links, etc. is a hassle. Markdown, however, makes rich text extremely easy to both read and write, and therefore is a preferred option. Here's an example of markdown using posthtml-md

md Hello **world**! Here's a [link to google](http://google.com).

And this would compile to:

<p>Hello <strong>world</strong>! Here's a <a href='http://google.com'>link to google</a>.

Good Typography

There are some parts of typography that are consistently used incorrectly, and using them correctly is a pain to do manually as you need extra html entities and such, which is confusing and hard to read. Smart quotes, em and en dashes, and ellipses all fit into this category. So we use smartypants to even that out. For example:

p Look it's some "smart quotes" -- and dashes...

This would compile to

<p>Look it's some “smart quotes” – and dashes…</p>

Code Style & Architecture

We have a few simple rules for code style in HTML:

  • Always indent your html correctly, unless your two elements are < 80 characters and can fit on one line, like <li><a href='foo'>bar</a></li>
  • Use ids for things that could and would never be repeated within a single page, for example an ID on the body element to identify the entire page.
  • Use classes for anything that could be repeated, for example a global list style.
  • Use short, straightforward class/id names, like box instead of Module__box--style1
  • Use hyphens to separate multiple words in a class name, like foo-bar instead of fooBar
  • Use the minimum number of ids and classes you need to apply your styles correctly. For example:
<!-- this is a good way to do things -->
<ul class='standard-list'>
  <li>foo</li>
  <li>bar</li>
</ul>

<!-- this is a bad way to do things, you can just use a descendent selector -->
<ul class='standard-list'>
  <li class='list-item'>foo</li>
  <li class='list-item'>bar</li>
</ul>
  • Use html5 elements appropriately, not just a div for everything. Reference.
  • Use <doctype html>
  • Use a lang attribute
  • Do not use wrapper elements unless they are absolutely necessary in your css to achieve a certain effect

There is not currently an html linter that we use, but we will have one in the near future, then this section will be split into style / architecture like the other sections.