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:
- It forces developers to correctly indent their html, which should happen anyway
- 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 ofModule__box--style1
- Use hyphens to separate multiple words in a class name, like
foo-bar
instead offooBar
- 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.
Updated less than a minute ago