HTML Standards
The Spike HTML Standard stack can be accessed through a single plugin bundle for simple configuration. This is what you will find in spike's default template when you create a new project. It includes:
- reshape-expressions
- reshape-layouts
- reshape-include
- reshape-content with markdown-it
- reshape-retext with smartypants.
All of these plugins run on top of reshape, our foundation-level html transformation platform. The rationale behind each of these decisions and purpose of these plugins is explained in depth below. This is a living document and any and every part of it is subject to change in the future. We try to align as closely as possible with future HTML standards when considering our default stack and best practices.
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 in reshape-layouts.
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 src='layout.sgr'>
<block name='title'>
<title>Custom Page</title>
</block>
<block name='content'>
<p>hello world!</p>
</block>
</extends>
<html>
<head>
<block name='title'>
<title>Homepage</title>
</block>
</head>
<body>
<block name='content'></block>
<block name='footer'>
<footer>
<p>Copyright etc etc</p>
</footer>
</block>
</body>
</html>
Note
Although this example uses standard html, if you are using sugarml, a common choice in the spike community, the same syntax applies.
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</title>
</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. We use reshape-include to implement this feature in the spike-standards stack.
<p>hello from a partial!</p>
<p>hello from the index!</p>
<include src='partial.html'></include>
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. We use reshape-expressions to accomplish this.
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) }}</p>
Given { foo: 'bar' }
when compiling should yield:
<p>bar7</p>
We use handlebars-style delimiters here, but all delimiters are completely configurable through reshape-expressions if you want. 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>" }}}</p>
With {{{
, 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.
Looping
There also must be a way to loop through data. For example
<ul>
<each loop='item of items'>
<li>{{ item.name }}</li>
</each>
</ul>
Given { items: [{ name: 'foo' }, { name: 'bar' }] }
when compiling should yield
<ul>
<li>foo</li>
<li>bar</li>
</ul>
The syntax above comes from reshape-expressions, 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</h1>
<if condition="environment === 'development'">
<p>Warning, not a production site!</p>
</if>
Although the syntax could 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 rehape-content along with markdown-it:
<p md>Hello **world**! Here's a [link to google](http://google.com).</p>
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 through reshape-retext to even that out. For example:
<p>Look it's some "smart quotes" -- and dashes...</p>
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 almost 7 years ago