A mostly reasonable approach to Markup and CSS
This document is intended to:
- Improve readability
- Minimize common code smells
- Reduce errors and improve maintainability
This document is not intended to:
- Advocate specific frameworks or libraries
- Give advice on design patterns and project architecture
- Guide the reader in learning CSS
- Overview
- Methodology
- HTML Formatting
- HTML Best Practices
- CSS Formatting
- CSS Best Practices
- SCSS
- Accessibility
- Browser & Device Support
- Files & Folders
- License
-
1.1 Prime Directive
The standards herein are a guide to keep developers at Horizontal Digital interoperable amongst each other and able to produce the highest quality code given the timeline and budget constraints of a project.
For a successful project, always favor solutions that benefit the project and end users over producing "perfect code".
Always aim to meet the standards knowing you'll have to break the rules at some point. Be thoughtful about when you deviate and check with a senior software engineer or a principal software engineer for guidance.
-
1.2 Expectations
- Understand and follow the standards outlined in this document.
- Understand and follow the methodology.
- Write code knowing that someone else might be maintaining it.
- Select tools that benefit the project.
-
1.3 Goals
Strive to make your code:
- semantic
- accessible
- predictable
- reusable
- flexible
- resilient
- understandable
- scalable
- performant
- maintainable
- interoperable
The following key points and ideas make up the methodology of "how" and "why" we do Front-End Development at Horizontal Digital the way we do. Most of these topics are touched on in the standards in the form of rules to follow, but they will be covered more in depth in an effort to better explain and stress the importance of our methodology.
-
2.1 Modularity
Approaching front end code from a modular point of view addresses the goal outlined in our standards. Writing in a modular fashion makes our code more flexible to change and resistant to breakage as sites grow larger. Modular code is more scalable and maintainable - requiring less CSS that can do more.
The goal here is not to avoid repeating a property/value pair, but to identify the patterns that can be abstracted for high reuse and to identify and create modules that are fully encapsulated logical entities that are easy to extend, and extremely portable.
A module, or "object," is the combination of some markup and the associated CSS (and sometimes Javascript). It is portable, in that it does not change based upon context. It contains all of the CSS needed for that object to function, without relying on context or utility type classes.
Objects come in all shapes and sizes. A button is an object. A heading is an object. A masthead is an object. Some classes have sub-components (class members) which are the children markup elements (and the associated CSS) that make up the object. If the objects are carefully written, you can put them together in any number of ways without having to write additional CSS.
Objects are the Lego blocks that are assembled into full blown pages and sites. Writing CSS to be modular means removing contextual dependencies and writing defensive selectors that limit the depth of applicability.
-
2.2 CSS Selectors
One of the quickest ways to improve the modularity and flexibility of code is to think harder about the selectors you choose. The first step is to eliminate IDs from CSS selection. IDs do nothing that classes can't also do, but instantly limit reuse and flexibility as they cannot appear on a page more than once. They are also difficult to work with due to their high specificity. The ideal selector is a single classname like
.masthead.The next step is to avoid contextual selection, especially across unrelated objects. By styling an object based on context, we again reduce flexibility by needlessly tying an object's appearance to some unrelated class farther up the DOM tree. Now we've created a situation where those styles can only be used within that container, whereas had we simply written the object without contextual selection, we would be free to move that module anywhere in our site and it would still function as it should.
Contextual selection introduces complexity and unpredictability into the mix. If the next developer is unaware of a myriad of contextual conditions for an object, imagine the frustration as an object breaks or changes simply by moving it somewhere else in the site. By avoiding contextual selection, we keep our selector specificity low and gain predictable, robust objects.
Contextual selectors also add weight to our selectors, making them more difficult to work with.
/* DO */ .utilNav { } /* DO NOT */ .masthead .utilNav { }
Avoid overqualified selectors. Similar to contextual selectors, overqualification limits flexibility and needlessly increases selector weight.
/* DO */ .utilNav { } /* DO NOT */ div.utilNav { }
Avoid using elements in selectors. Elements are risky for a couple of reasons. First, they limit the markup elements we can apply a given class to - making semantic decisions for us in our CSS. Second, they have a high depth of applicability - meaning the likelihood that something will accidentally receive or collide with those styles goes up.
/* DO */ .utilNav-item { } /* DO NOT */ .utilNav a span { }
By simply avoiding IDs, elements and contextual selection, the potential for reuse and modularity increases dramatically.
One false sense of reuse is the use of stacked selectors. In most cases, stacked selectors are an indication that objects aren't properly being identified and abstracted into objects. If selectors are being stacked, a single class probably should have been used.
/* DO */ .utilNav { } /* DO NOT */ .newsNav, .eventsNav, .legalNav { }
-
2.3 Object Identification
One key to writing modular, object based front end code is getting the granularity right. This usually involves thinking about the items on our pages "inside out" instead of "outside in."
Instead of thinking about creating pages, think about the little bits that combine to make that page. The bits are smaller and generally good at doing one thing - being a button, being a list with top borders on my items, being a container that has space for an image, a heading and some copy, being a grid to lay out major components of a site. With each object doing an excellent job, being free of contextual specificity and elemental restraints - it can be placed into the site at will, in a predictable, flexible fashion.
-
2.4 Object Members
Objects may consist of a single element.
<a href="#" class="btn">Push Me</a>
Or objects may consist of base class and any number of class members (sub-components). We prefix the name of sub-components with the base class name, followed by a hyphen to indicate a sub-component.
<div class="object"> <div class="object-member"> ... </div> </div>
A very common pattern is for objects to have head, body and foot components.
<div class="featurePanel"> <div class="featurePanel-hd"> ... </div> <div class="featurePanel-bd"> ... </div> <div class="featurePanel-ft"> ... </div> </div>
Components are frequently optional, and certainly aren't restricted to head, body and foot items.
<div class="featurePanel"> <div class="featurePanel-bd"> ... </div> </div>
-
2.5 Object Extension
We can account for variations on an object by creating an extension to that object. We prefix the name of an extension with the base class name, followed by an underscore to indicate an extension.
<div class="object object_extension"> ... </div>
Extending objects is an important habit to get into. Always directly alter the object you want to change, instead of styling it contextually from a different object.
<!-- DO --> <div class="box"> <a href="#" class="btn btn_secondary">Go Back</a> </div>
/* DO */ .btn { color: #000000; } .btn_secondary { color: #999999; }
<!-- DO NOT --> <div class="box"> <a href="#" class="btn">Go Back</a> </div>
/* DO NOT */ .btn { color: #000000; } .box .btn { color: #999999; }
-
2.6 Object Mixins
Extensions to an object should follow a single ancestry chain. Two sub-classes of an object should not appear on the same object if they are of a different ancestry chain. For these types of scenarios, we have mixins.
Mixins are a type of class extension that do not create a sub-class, but rather can be added to (mixed with) any super or sub-class of object. If a type of object has many variations that cannot be elegantly defined into discrete sub-classes, mixins may be the best solution. Mixins are generally an undesirable way to write CSS and should only be used when that is the best option availabe - usually when a design lacks consistency. Often it is better to create more base classes than to try and shoehorn everything into a single object with a lot of mixins.
We indicate an object mixin by prefixing the name with "mix-" and the base class name.
<div class="object mix-object_extension"> ... </div>
<h1 class="hdg hdg_h1"> ... </h1> <h1 class="hdg hdg_h1 mix-hdg_cap"> ... </h1> <h1 class="hdg hdg_h2"> ... </h1> <h1 class="hdg hdg_h2 mix-hdg_cap"> ... </h1>
.hdg { font-family: arial, helvetica, sans-serif; font-weight: bold; } .hdg_h1 { font-size: 30px; } .hdg_h2 { font-size: 20px; } .mix-hdg_cap { text-transform: uppercase; }
-
2.7 Object States
States are special class extensions that represent the various states an object may be in - often used in conjunction with Javascript. States are indicated with the "is" prefix before the extension name.
<div class="object object_isState"> ... </div>
<a href="#" class="navItem navItem_isActive"> ... </a>
.navItem { color: #ffffff; background: #000000; } .navItem_isActive { color: #000000; background: #ffffff; }
-
2.8 All Together Now
With these naming conventions, intention and structure become clear just from reading a class from right to left. Underscore means extends, hyphen indicates a class member (sub-component).
A selector this deep is rare, but it illustrates the point:
.cta-bd_highlight-status { }Right to left, this tells us we're dealing with: The status element which is a sub-component (-) of the highlight extension (_) of bd which is a sub-component of the cta base object. From this alone we can extrapolate the ancestry of our selector as well as part of the markup structure this object has:
<div class="cta"> <div class="cta-bd cta-bd_highlight"> <div class="cta-bd-status cta-bd_hightlight-status"> ... </div> </div> </div>
-
2.9 Depth of Applicability
Carefully written objects limit their depth of applicability. A selector with a high depth of applicability casts too wide a net and can result in unexpected results. By writing defensive selectors from the start, we eliminate that risk. An object's depth of applicability should extend only to the known components of that module. For instance, if we started an object that is used on a product listing page:
<ul class="listing"> <li> ... </li> <li> ... </li> <li> ... </li> <li> ... </li> </ul>
One might be tempted to style the list like this:
.listing li { border-top: 1px solid #000000; padding-top:10px; margin-top: 10px; }
This selector is not defensive enough - any number of things could go inside of .listing, including other lists, which means we'd then have to override our listing styles and make sure our overrides appear later in the CSS source file. We would improve the depth of applicability by utilizing a child combinator selector:
.listing > li { border-top: 1px solid #000000; padding-top: 10px; margin-top: 10px; }
That accomplishes the goal of limiting the depth at which that style will be applied. By making a small change in our selector, we have ensured that these styles will not collide with any of the other modules it may house. We can even take this a step further by removing the element from the selector completely, which would allow us to use this object's styles with more than one kind of markup element:
.listing > * { border-top: 1px solid #000000; padding-top: 10px; margin-top: 10px; }
Alternatively, we can just name member we wish to style and use its classname as the selector:
<ul class="listing"> <li class="listing-item"> ... </li> <li class="listing-item"> ... </li> <li class="listing-item"> ... </li> <li class="listing-item"> ... </li> </ul>
.listing-item { border-top: 1px solid #000000; padding-top: 10px; margin-top: 10px; }
-
2.10 Keeping Objects Separate in the DOM
The classes that make up separate objects should not be combined in the DOM - this leads to unpredictable results and breaks object encapsulation. Keep objects separate, both in CSS and in the DOM.
<!-- DO --> <div class="grid"> <div class="grid-col grid-col_1of2"> <div class="someModule"> ... </div> </div> </div> <!-- DO NOT --> <div class="grid"> <div class="someModule grid-col grid-col_1of2"> ... </div> </div>
-
2.11 Separation of Concerns
By separating certain concerns amongst our objects, we end up with a more flexible set of objects. The rules of thumb are:
- Separate layout styles from container styles
- Separate content styles from container styles
By having layout be its own class of object, separate from container objects, we dramatically increase the number of layouts we can achieve while increasing the flexibility of where and how we can use our container objects. All while writing less CSS as containers no longer need lots of width and float rules, only to be overridden in other contexts. This works to simplify the code and results in more predictable results.
Similarly, by separating our content styles from our container styles, we increase the flexibility and predictability of our content - as we can put any object into any other object and it won't suddenly change.
Attempting to separate your objects into these three duties results in code that is easier to work with, flexible to change, resistant to breakage, scalable and maintainable.
-
2.12 Resources
-
3.1 Output
All html formatting standards are written with source files in mind. If you're using a build process, templates, or partials, the source files (not the build files) are the ones that need to follow the outlined standards.
-
3.2 Closing Tags
All elements should be closed via a tag pair or self closing declaration.
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
<input type="text" />
-
3.3 Indentation
Use 4 spaces for indenting.
Place block, list and table elements on a new line and indent the new line 4 additional spaces.
<div> <ul> <li><a href="page.html">Link</a></li> <li><a href="page.html">Link</a></li> </ul> </div>
When using templating logic to generate markup, indent each new line 4 additional space.
{{#if}} <div> ... </div> {{/if}}
-
3.4 Trailing Whitespace
Remove all trailing whitespace.
-
3.5 Capitalization
Use only lowercase.
This applies to element names, attributes, and attribute values (unless strings).
<img src="felix.png" alt="Felix, a cat, wrestles with his yarn playfully" />
-
3.6 Quotes
Use double quotes around attribute values.
<input type="text" />
-
3.7 Boolean Attributes
Boolean attributes should not have a value.
<input type="text" disabled />
-
3.8 Comments & Grouping
Use standard HTML comments to indicate the beginning and end of large sections of code.
<!-- Main Content --> <div> ... </div> <!-- // End Main Content -->
-
3.9 TODO Comments
Mark todos and action items with a comment that includes
TODO. Be sure thatTODOis always uppercase.<!-- TODO - Review content styles --> <div> ... </div>
-
4.1 W3C Validation
- Write valid code.
- Remaining errors and warnings should be intentional.
Resources
-
4.2 Doctypes
Use the HTML5 doctype.
<!doctype html>Resources
-
4.3 Encoding
Use UTF-8 encoding. This meta tag should always be the very first element inside of the document's
<head>element.<meta charset="utf-8" />
If you end up working in code that does not use an HTML5 doctype, use the meta tag associated with the proper doctype.
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
-
4.4 HTML5 Usage
Not all projects warrant the use of HTML5 elements, but when they do, use HTML5 elements and attributes that progressively enhance modern browsers.
Use
<div data-controller="exampleDataController"></div><input type="email" placeholder="example@domain.com" /><input type="search" /><input type="tel" /><input type="url" /><input type="text" required /><article></article><aside></aside><figure></figure><footer></footer><header></header><mark></mark><nav></nav><section></section><time></time><small>© 2015 Horizontal Digital</small>
Use with Caution
<audio></audio><canvas></canvas><video></video><figcaption></figcaption><keygen></keygen><main></main><meter></meter><progress></progress><output></output>
Do Not Use
<datalist></datalist><dialog></dialog><details></details><summary></summary><menu></menu><menuitem></menuitem><hgroup></hgroup><wbr><bdi>
Special Consideration
Entirely new elements like
<video>should use appropriate markup based fallbacks so the content is still accessible even if the browser can't render it.<video width="640" height="360" controls> <source src="cats.mp4" type="video/mp4" /> <source src="cats.ogv" type="video/ogg" /> <object width="640" height="360" type="application/x-shockwave-flash" data="cats.swf"> <param name="movie" value="cats.swf" /> <param name="flashvars" value="controlbar=over&image=cats.jpg&file=cats.mp4" /> <img src="cats.jpg" width="640" height="360" alt="Download the video below" /> <a href="cats.mp4">Download cats mp4 file</a> <a href="cats.OGV">Download cats ogv file</a> </object> </video>
Resources
-
4.5 HTML5 Form Validation
By default, many HTML5 form inputs include validation that is provided by the browser. Error messages are on by default, though in many cases the browser implemented messages are not what a designer wants. In order to remove validation (and thereby the messages) use the
novalidateattribute on the containing form.<form action="#" method="post" novalidate> <label for="email">Email address:</label> <input type="email" placeholder="example@domain.com" id="email" /> <button type="submit" id="submit">Submit</button> </form>
Resources
-
4.6 Optional Tags
Include tags deemed optional in HTML5 (
<html>,<head>,<body>)<!doctype html> <html> <head> <title> ... </title> </head> <body> <p> ... </p> </body> </html>
-
4.7 Type Attributes
HTML5 Doctype
When working with the HTML5 doctype, omit
typeattributes for stylesheets and scripts.<link rel="stylesheet" href="screen.css" /> <script src="global.js" />
Legacy Doctypes
When working with legacy doctypes older than HTML5, include
typeattributes for stylesheets and scripts.<link rel="stylesheet" href="screen.css" type="text/css" /> <script src="global.js" type="text/javascript" />
-
4.8 Protocol
Whenever possible, omit the protocol portion (
http:,https:) from URLs.<link rel="stylesheet" href="//www.horizontaldigital.com/assets/styles/screen.css" /> <a href="//www.horizontaldigital.com/">Horizontal Digital</a>
-
4.9 HTML Entities
Use the appropriate HTML entity names or numbers for special and reserved characters.
© 2012-2015 Crispin & Mulberry ™
-
4.10 Semantic Markup
Write clean semantic markup that clearly reinforces the meaning of the page content.
<nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About Us</a></li> <li><a href="#">Resources</a></li> <li><a href="#">Contact</a></li> </ul> </nav>
<div> <small>© 2012 Horizontal Digital</small> </div>
When generic containers are needed, use
<div>for block level elements and<span>for inline elements.Resources
-
4.11 Document Outline
Craft a proper document outline by using appropriate heading levels in a linear fashion.
When necessary, use headings that are hidden in an accessible way to enhance the document outline.
Note that the outline algorithm has changed in HTML5 with the use of new sectioning elements (nav, article, section and aside), allowing the creation of a document outline without using headings in a linear, hierarchical fashion. Do not do this. Craft an outline that is complete and accurate from a pre-HTML5 point of view.
-
4.12 HTML4
<h1>Horizontal</h1> <h2 class="isVisuallyHidden">Divisions</h2> <h3>Horizontal Digital</h3> <h3>Horizontal Talent</h3> <h2 class="isVisuallyHidden">Departments</h2> <h3>New Business</h3> <h4>Human Resources</h4> <h4>Finance</h4> <h4>Information Technology</h4>
Resources
- http://html5doctor.com/outlines/
- http://www.456bereastreet.com/archive/201205/make_sure_your_html5_document_outline_is_backwards_compatible/
- http://html5forwebdesigners.com/semantics/index.html#sectioning_content
- http://webaim.org/projects/screenreadersurvey/#headings
- http://www.paciellogroup.com/blog/2013/10/html5-document-outline/
- http://www.w3.org/TR/html5/sections.html#headings-and-sections
-
4.13 Microdata, Microformats and RDFa
Microdata, microformats and RDFa are all approaches to marking up certain types of data in a machine readable way. Search engines and devices/browsers can leverage this increased semantics in various useful ways. While most search engines currently support all three, Google and the WHATWG are putting their weight behind microdata and this is our preferred method of implementing rich data.
Here are some examples of places where we can use microdata:
- Creative Work
- Event
- Person
- Place
- Organization
- Product
- Review
- Rating
Get to know the various types of data that will benefit from this type of markup and leverage this increased semantics whenever possible.
<div itemscope itemtype="http://schema.org/Product"> <h2 itemprop="name">Strawberry Champagne Vinaigrette</h2> <a href="/shop-our-products/strawberry-champagne-vinaigrette" itemprop="url"> <img src="/media/images/products/strawberry-champagne-vinaigrette.jpg" alt="" itemprop="image" /> </a> <div> Item: <span itemprop="sku">753604</span> </div> <div itemprop="description"> Drizzle this sweet, gorgeous ruby dressing over salads or grilled meats. Limited time. </div> <div itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating"> <div> <span itemprop="ratingValue">3</span> stars </div> <div> <span itemprop="reviewCount">4</span> reviews </div> </div> <div itemprop="offers" itemscope itemtype="http://schema.org/Offer"> <span itemprop="price">$8.99</span> </div> </div>
Resources
-
4.14 Image Formats
Know image formats well and choose the best format for each scenario. The goal is the best image quality at the smallest file size.
Resources
-
4.15 Image Usage
Consider options carefully when choosing whether or not images will be included as inline images or background images. If an image is considered to be content or if a content editor would want to change the image, it should be inline in the markup as an
<img>element. If an image is used to enhance the visual aesthetics of the interface and supplies no extra meaning to the markup it should be a CSS background image.
-
4.16 Tables
Tables should be reserved for tabular data and never used to achieve page layout.
To make tables semantic and accessible, always:
- Use
<thead>,<tbody>and<tfoot>to differentiate between the table header, table body, and table footer - Use
<tr>to separate table rows - Use
<th>for table headers and<td>for table data - Include a proper scope on the
<th>
<table> <thead> <tr> <th scope="col">Year</th> <th scope="col">Make</th> <th scope="col">Model</th> <th scope="col">Color</th> <th scope="col">Horsepower</th> </tr> </thead> <tbody> <tr> <td>2000</td> <td>Toyota</td> <td>Matrix</td> <td>Silver</td> <td>140hp</td> </tr> <tr> <td>2007</td> <td>BMW</td> <td>328xi</td> <td>Jet Black</td> <td>255hp</td> </tr> </tbody> </table>
- Use
-
5.1 Capitalization
Use camelCase for selector names and lowercase for properties & property values (unless strings).
.mySelector { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.2 Name Delimiters
For more information on classes, class members, class extensions and class mixins, read the methodology.
Class Names
Use camelCase for class names.
.featurePromo { padding: 10px; border: 1px solid #bbbbbb; background: #ffffff; }
Sub Components
Use a hyphen before a class member (sub-component) name, prefixed with the base class name. The class member name is camelCased.
.featurePromo-hd { margin-bottom: 10px; } .featurePromo-bd { position: relative; padding: 5px; } .featurePromo-ft { border-top: 1px solid #000000; } .featurePromo-statusMessage { padding: 10px; border: 1px dotted #ff0000; }
Extensions
Use an underscore before a class extension name, prefixed with the base class or sub-component class it extends. The extension name is camelCased.
.featurePromo_primary { border-color: #ff0000; background: #aa6600; } .featurePromo_lastChild { border: none; } .featurePromo-bd_inset { padding: 20px; }
Mixins
Use
mix-followed by the base class, then the rest of the class extension name. The extension name is camelCased..hdg { font-family: arial, helvetica, sans-serif; font-size: 32px; font-weight: bold; text-transform: uppercase; color: #000000; } .hdg_1 { font-size: 30px; } .hdg_2 { font-size: 20px; } .mix-hdg_brandColor { color: #cccccc; }
States
Use an underscore between a state class and the class it extends. Prefix the state class name with
is. The state name is camelCased.menuItem_isActive { font-weight: bold; text-decoration: underline; }
Themes
Name class theme extensions prefixed with
theme-followed by the base class, then the rest of the class extension name. The extension name is camelCased.masthead { background: #333333; } .theme-masthead_cats { background: transparent url("../images/cat-bg.jpg") no-repeat 0 0; } .theme-masthead_wolfPack { background: transparent url("../images/3-wolves-bg.jpg") no-repeat 0 0; }
-
5.3 Brackets
Place the opening curly-bracket of each rule block on the same line as the last selector.
Place the closing curly-bracket of each rule block on its own line after the final property of the rule block.
.selector { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.4 Indentation
Use 4 spaces for indenting.
Indent each property in a rule block 4 spaces.
.selector { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.5 Property Whitespace
Put each property on its own line.
Follow each property with a colon and a single space.
.selector { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.6 Semi-colons
Follow each property value with a semi-colon.
.selector { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.7 Trailing Whitespace
Remove all trailing whitespace.
-
5.8 Rule Block Separation
Separate each rule block by an empty line.
.selector { color: #ff0000; font-family: Times, "Times New Roman", serif; } .selector { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.9 Property Order
CSS properties should be grouped by commonality (display, then box-model, then positioning, then background/color, then typography, then misc/etc).
.selector { display: block; width: 400px; height: 222px; padding: 4px; margin: 2px; position: absolute; top: 22px; left: -12px; color: #ffffff; font: 12/1.2 normal Helvetica, Arial, san-serif; text-transform: uppercase; text-indent: 0; }
-
5.10 Vendor Prefixes
Include vendor prefixes for all properties that have had a vendor prefix in the past.
It is not necessary to include vendor prefixes for specific rendering engines if it never existed.
Include the W3C standard property after the vender prefixed properties.
.selector { -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; }
.selector { -webkit-transform: rotate(40deg); -moz-transform: rotate(80deg); -ms-transform: rotate(40deg); -o-transform: rotate(40deg); transform: rotate(40deg); }
Resources
-
5.11 Multi-Value Properties
Format multi-value properties by starting a new line for each value and indenting each line 4 spaces.
.selector { background: transparent url("space.png") repeat-x 0 0; background: transparent url("stars-1.png") repeat-x -130% 0, transparent url("stars-2.png") repeat-x 40% 0; }
-
5.12 Single Properties
It is acceptable to put rule blocks with a single property on a single line.
Include a space after the opening bracket and before the closing bracket.
.selector { background-position: 0 -100px; }
No line break is required between rule blocks when the selectors are part of the same object and the properties match.
.icn_twitter { background-position: 0 -100px; } .icn_facebook { background-position: 0 -200px; } .icn_youtube { background-position: 0 -300px; }
-
5.13 Quotes
Use double quotes.
File Paths and Data URIs
Use double quotes for file paths and data URIs.
.selector { background-image: url("background.png"); }
Font Family
Use double quotes for font names unless they are system fonts that don't require them.
.selector { font-family: "LeagueGothic", Helvetica, Arial, sans-serif; }
Generated Content
Use double quotes around generated content values.
.selector:before { content: "Chapter:"; display: inline; }
Attribute Selectors
Use double quotes around values in attribute selectors.
input[type="text"] { color: #ff0000; }
-
5.14 Multiple Selectors
Separate multiple selectors in the same rule block with a comma and place each selector on a new line.
.navItem:focus, .navItem:active { color: #ff0000; font-family: Times, "Times New Roman", serif; }
-
5.15 Comments & Grouping
Group related rule blocks by base object using the standardized section comment style.
/* --------------------------------------------------------------------- Box ------------------------------------------------------------------------ */ .box { padding: 20px; background-color: #cccccc; }
If a section requires additional subsets of comments, a single line comment is acceptable.
If a property / value pair needs additional clarity or is not self-documenting, add comments on the same line immediately following the value.
/* --------------------------------------------------------------------- Horizontal List ------------------------------------------------------------------------ */ .hList { overflow: hidden; *zoom: 1; /* ie6-7 float clearing */ } .hList > * { float: left; } /* horizontal spacing extensions */ .hList_tight > * + * { margin-left: 8px; } .hList_std > * + * { margin-left: 16px; } .hList_loose > * + * { margin-left: 24px; } /* adds vertical pipes between list elements */ .hList_divided > * + * { margin-left: 12px; padding-left: 12px; border-left: 1px solid; }
.carousel { position: relative; /* A positioning reference for .carousel-nav */ } .carousel-nav { position: absolute; /* Positioned against .carousel base class */ right: 20px; bottom: 20px; z-index: 10; /* Pull navigation on top of .carousel-slides */ }
-
5.16 Hexadecimal Notation
Always use six character and lowercase hexadecimal notation.
.selector { background-color: #ff0000; }
-
5.17 TODO Comments
Mark todos and action items with a comment that includes
TODO. Be sure thatTODOis always uppercase./* TODO - Review content styles */ .selector { color: #ff0000; }
-
5.18 Table of Contents
Do not include a table of contents in the CSS.
/* DO NOT */ /* --------------------------------------------------------------------- Table of Contents 1 - Masthead 2 - Utility Classes 3 - Grid 4 - Media Object 5 - Icons ------------------------------------------------------------------------ */
-
6.1 Encoding
Do not declare a
@charsetin the CSS./* DO NOT */ @charset "UTF-8"; .selector { color: #ff0000; }
-
6.2 Browser Reset
/* ------------------------------------------------ RESET CSS (thanks Eric Meyer) ------------------------------------------------ */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font-weight: inherit; font-style: inherit; font-family: inherit; vertical-align: baseline; } body { line-height: 1; } ol, ul { list-style: none; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; } table { border-collapse: collapse; border-spacing: 0; } :focus { outline-width: 0; } html { overflow-y: scroll; /* Always show a vertical scrollbar, even when there is no scrolling */ } html { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } /* ------------------------------------------------ HTML5 Element Reset ------------------------------------------------ */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, main { display: block; } audio, canvas, video, progress, picture { display: inline-block; } template { display: none; } /* ------------------------------------------------ Form Reset Styles ------------------------------------------------ */ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-results-button, input[type="search"]::-webkit-search-results-decoration { -webkit-appearance: none; } input[type="search"] { -webkit-appearance: none; -webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box; } textarea { overflow: auto; vertical-align: top; resize: vertical; } ::-moz-focus-inner { border: 0; padding: 0; }
Do not use normalize.css or a universal selector reset.
-
6.3 Classes & IDs
Do not use
idfor styling purposesAcceptable uses for
idinclude:- JavaScript selection - prefix these with
js-to indicate they are for JavaScript only - Assigning form labels to inputs
- Jump links between sections of a page
<div class="carousel" id="js-carousel"> ... </div>
<label for="firstName">First Name</label> <input type="text" id="firstName" class="input input_txt" />
<a href="#mainContent">Skip to Main Content</a> ... <div class="content" id="mainContent"> ... </div>
Resources
- JavaScript selection - prefix these with
-
6.4 Contextual Selectors
Avoid cross module contextual selection.
/* DO NOT */ .box .hdg { }
If a single module can make use of a contextual selector (as the markup structure is known), be sure to apply it with the proper depth of applicability.
.list > li { }
-
6.5 Selector Specificity
Keep selector specificity as low as possible, opting for a single class as the best selector.
.box { padding: 20px; background-color: #cccccc; }
Resources
-
6.6 Separation of Concerns
Using the outlined methodology, separate layout styles from container styles and content styles from container styles.
Resources
-
6.7 Naming Conventions
Name Quality
Class names should be specific enough so that you can comprehend the name without context, but generic enough for reuse throughout the code base.
.wrapper { } .masthead { } .globalFooter { } .cta { } .btn { } .box { } .icn { }
Numerical/Enumerated Naming
Do not use numbers, letters, the greek alphabet, or any other sequential naming convention.
/* DO NOT */ .box1 { } .box2 { } .box3 { }
There are a few notable exceptions:
- Heading tags:
.hdg_1,.hdg_2, etc. are appropriate as they indicate hierarchy. - Vertical rhythm classes:
.vr_2x,.vr_3x, etc. are appropriate as they indicate a ratio.
- Heading tags:
-
6.8 Class Chaining
Avoid chaining classes.
/* DO */ .btn_primary { } /* DO NOT */ .btn.primary { }
An exception to this rule is chaining state classes, as they are often applied via JavaScript and chaining classes in this way provides an appropriate level of reuse.
.btn.isActive { }
-
6.9 Body / Page Classes
Avoid using body / page classes. This includes classes on the
<html>or<body>element, or page-based classes on wrapper<div>s.The exception to this rule is when leveraging Modernizr or other feature detection to add classes to the
<html>element, allowing for feature based fallbacks in CSS.<html class="no-js"> ... </html>
.carouselItem { float: left; margin: 0 10px; } /* Stack carousel items if no JS */ .no-js .carouselItem { float: none; margin: 0 0 20px; }
-
6.10 Shorthand
Use of shorthand is encouraged unless setting a single value.
When using shorthand, be explicit and define all values.
.selector { margin: 12px 0 16px 0; }
.selector { font: italic small-caps normal 13px/1.6 Arial, Helvetica, sans-serif; }
-
6.11 Browser Hacks
Browser hacks are an acceptable alternate means of including browser specific code.
Browser specific code should not be needed in most cases - but should be used to handle known browsers bugs such as emulating inline-block in IE7.
If a hack is included, a comment is required to explain the reasoning.
.selector { display: inline-block; *display: inline; /* ie6-7 emulate inline-block */ *zoom: 1; /* ie6-7 emulate inline-block */ }
If you need to include a large amount of code targeted at a specific browser, instead utilize conditional comments that allow for inclusion of browser specific stylesheets. Keep in mind that this technique hinders your ability to utilize the cascade.
<!--[if IE 9]><link href="ie9.css" rel="stylesheet" /><![endif]--> <!--[if lte IE 8]><link href="ie8.css" rel="stylesheet" /><![endif]--> <!--[if lte IE 7]><link href="ie7.css" rel="stylesheet" /><![endif]--> <!--[if lte IE 6]><link href="ie6.css" rel="stylesheet" /><![endif]-->
Resources
-
6.12 Multiple Stylesheets
All CSS should be placed in the same stylesheet with the following exceptions:
- Browser specific stylesheets
- Media specific stylesheets (print)
- Breakpoint specific stylesheets (width media queries)
- Area specific stylesheets (standard site, admin area)
<link href="screen.css" rel="stylesheet" media="screen" /> <link href="print.css" rel="stylesheet" media="print" />
Do not use
@importto include stylesheets. All stylesheets should be linked in the head of your document./* DO NOT */ @import url("layout.css"); @import url("typography.css");
IE conditional stylesheets should use
ltedeclarations, with the exception of IE9.<!-- DO --> <!--[if IE 9]><link href="ie9.css" rel="stylesheet" /><![endif]--> <!--[if lte IE 8]><link href="ie8.css" rel="stylesheet" /><![endif]--> <!--[if lte IE 7]><link href="ie7.css" rel="stylesheet" /><![endif]--> <!--[if lte IE 6]><link href="ie6.css" rel="stylesheet" /><![endif]--> <!-- DO NOT --> <!--[if lte IE 9]><link href="ie9.css" rel="stylesheet" /><![endif]--> <!--[if IE 8]><link href="ie8.css" rel="stylesheet" /><![endif]--> <!--[if IE 7]><link href="ie7.css" rel="stylesheet" /><![endif]-->
-
6.13 Units
The recommended unit for font-sizes is pixels.
.selector { font-size: 12px; }
The recommended units for setting box model related properties are pixels and percentages.
.box { width: 25%; margin-bottom: 10px; }
When building RWD websites and web applications, alternative units of measurement may be more appropriate, but should be chosen with care to do what's best for the project while striving to maintain our goals.
-
6.14 Line-Height
Declare line-height values as unit-less. Unit-less line heights act as a multiplier to the text size for a given element. Always leave a comment explaining the math.
.selector { font-size: 12px line-height: 1.25; /* 15px / 12px = 1.25 */ }
Resources
-
6.15 Color Values
Use hexadecimal notation for color values. RGBA is acceptable if opacity is needed, but be sure to provide a fallback for browsers that don't support RGBA.
.selector { color: #ff0000; } .selector { color: #ff0000; /* fallback for non-rgba browsers */ color: rgba(255, 0, 0, 0.8); }
-
6.16 Clearing Floats
All floats should be cleared using the micro clearfix syntax.
<ul class="hList"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul>
.hList:before, .hList:after { content: " "; display: table; } .hList:after { clear: both; } .hList > li { float: left; }
Resources
-
6.17 Sprites
Use sprites whenever possible to improve performance by reducing http requests. Use multiple sprites that are categorized appropriately (nav-sprite, icon-sprite, etc.) as opposed to using a single super sprite for the entire site.
Resources
-
6.18 Image Replacement
When using background images that include text, it's important that there is a text equivalent in the markup itself so that the text is accessible. Use a suitable image replacement technique to keep the text hidden from view.
<a href="/home/" class="nav-home">Home</a>
.nav-home { background-image: url("nav-home.png"); /* image for display of nav home button */ background-repeat: no-repeat; background-color: transparent; border: 0; overflow: hidden; } .nav-home:before { content: " "; display: block; width: 0; height: 100%; }
Resources
-
6.19 Font Embedding
Use
@font-faceto embed custom fonts.Font services like TypeKit or the Google Font API may be used. If embedding from a third party site is required, opt to use a CSS method over one that requires JavaScript.
Do not use FAUST, SIFR or Cufon.
@font-face { font-family: 'GiantHeadOTRegular'; src: url('../fonts/giant-head/giant-head-regular-ot-webfont.eot'); src: url('../fonts/giant-head/giant-head-regular-ot-webfont.eot?#iefix') format('embedded-opentype'), url('../fonts/giant-head/giant-head-regular-ot-webfont.woff') format('woff'), url('../fonts/giant-head/giant-head-regular-ot-webfont.ttf') format('truetype'), url('../fonts/giant-head/giant-head-regular-ot-webfont.svg#GiantHeadOTRegular') format('svg'); font-weight: normal; font-style: normal; }
Resources
-
6.20 Font Stacks
Choose font stacks with care, being mindful to ensure all bases are covered. Good font stacks generally have 2-4 font fallbacks declared and set the browser default serif or sans-serif last in the stack.
.selector { font-family: "LeagueGothic", Helvetica, Arial, sans-serif; }
Resources
-
6.21 Positioning
Do not use absolute positioning to layout the main sections of a page.
Do not use relative positioning to "shim" elements around the page to achieve pixel perfection.
Do use positioning contexts when necessary to achieve a flexible and robust object. When using positioning in CSS, leave a comment describing the context.
<div class="carousel"> <ul class="carousel-slides"> ... </ul> <ul class="carousel-nav"> ... </ul> </div>
.carousel { position: relative; /* A positioning reference for .carousel-nav */ } .carousel-nav { position: absolute; /* Positioned against .carousel base class */ right: 20px; bottom: 20px; }
-
6.22 Document Flow
Take advantage of the natural document flow when spacing content by using only margin bottom on content elements so they can easily be interchanged while keeping a predictable document flow and avoiding margin collapsing issues.
Additionally use padding on containers to keep a consistent "edge".
<div class="box"> <div class="userContent"> <h2>All About Cats</h2> <p> ... </p> <p> ... </p> <h3>Nocturnal Habits</h3> <p> ... </p> <p> ... </p> </div> </div>
.box { padding: 20px; background: #ffffff; } .userContent h2 { font-size: 24px; color: #333333; margin-bottom: 12px; } .userContent h3 { font-size: 20px; color: #333333; margin-bottom: 12px; } .userContent p { font-size: 12px; margin-bottom: 12px; }
When dealing with inter-modular spacing, consider using a vertical rhythm object to provide predictable document flow.
-
6.23 W3C Validation
Write valid code. Remaining errors & warnings should be intentional.
Resources
-
7.1 Folder Structure
The file structure when using SCSS includes 4 folders: base, helpers, landmarks, and modules.
The base folder contains:
- Elements - styles for base element like
<body>or<a>. - Fonts -
@font-facerules for embedding fonts for global use - Reset - common reset styles
The helpers folder contains:
- Utilities - styles for common patterns like
.isVisuallyHiddenand common mixins likeclearfix - Variables - all global variables used throughout the site
- Vendor - mixins for vendor prefixes
The landmarks and modules folders contain:
- A folder for each object named after the object
- A file within each folder named after the object that contains relevant styles for the object
Additionally there is a
screen.scssfile that is used to import all SCSS partials for inclusion in a single compiledscreen.cssfile.└── assets └── styles ├── base | ├── _elements.scss | ├── _fonts.scss | └── _reset.scss ├── helpers | ├── _utils.scss | ├── _vars.scss | └── _vendor.scss ├── landmarks | ├── masthead | | └── _masthead.scss | ├── navPrimary | | └── _navPrimary.scss | └── footer | └── _footer.scss ├── modules | ├── blocks | | └── _blocks.scss | ├── grid | | └── _grid.scss | ├── hlist | | └── _hlist.scss | └── media | └── _media.scss └── screen.scssWhen media queries are introduced into the code the folder structure becomes more complex in order to offer the modularity required to support legacy browsers.
The file structure remains the same, however the following rules apply.
- Each object in the landmarks or modules folder should use the name of the object and the name of the corresponding breakpoint in it's file name separated by a single underscore.
- If a module level variable is needed for multiple breakpoints, add a
_helpers.scsspartial. Use the aforementioned naming convention - the object name followed by_helpers.scss
Additionally, instead of compiling everything into a single
screen.cssfile, code will be compiled intomodern.cssandlegacy.cssfiles using the following steps:- Create a
_screen_breakpoint.scssfile for each breakpoint - Import partials for each module into the corresponding breakpoint files making sure not to include media queries
- Import all breakpoint partials into
legacy.css - Import all breakpoint partials into
modern.csswith each file contained inside the corresponding media queries
Taking these steps provides two production ready CSS files - one of which requires media queries and one that doesn't that can be used to apply a fixed width design for legacy browsers.
└── assets └── styles ├── base | ├── _elements.scss | ├── _fonts.scss | └── _reset.scss ├── helpers | ├── _utils.scss | ├── _vars.scss | └── _vendor.scss ├── landmarks | ├── masthead | | ├── _masthead_large.scss | | ├── _masthead_medium.scss | | └── _masthead_screen.scss | ├── navPrimary | | ├── _navPrimary_large.scss | | ├── _navPrimary_medium.scss | | └── _navPrimary_screen.scss | └── footer | ├── _footer_large.scss | ├── _footer_medium.scss | └── _footer_screen.scss ├── modules | ├── blocks | | ├── _blocks_helpers.scss | | ├── _blocks_medium.scss | | └── _blocks_screen.scss | ├── grid | | └── _grid_medium.scss | ├── hlist | | ├── _hlist_helpers.scss | | ├── _hlist_large.scss | | ├── _hlist_medium.scss | | ├── _hlist_screen.scss | | └── _hlist_small.scss | └── media | └── _media_screen.scss ├── _screen.scss ├── _screen_large.scss ├── _screen_medium.scss ├── _screen_small.scss ├── legacy.scss └── modern.scss - Elements - styles for base element like
-
7.2 Partials
Sass files that are not intended to be compiled independently, should be named with a leading underscore.
_media.scss
-
7.3 Silent Comments
Silent comments should be used when the comment is irrelevant to the output.
//---------------------------------------------------------------------- // Micro Clearfix Mixin //---------------------------------------------------------------------- @mixin clearfix() { &:before, &:after { content: " "; display: table; } &:after { clear: both; } }
-
7.4 Variables
Global Variables
Variables defined outside of ruleset are considered to be global and are used for setting values used across multiple modules, such as brand colors.
Define all global variables in the global
helpers/_vars.scsspartial.Write global variables using uppercase letters delimited by underscores.
$BRAND_COLOR_RED: #ff0000; .nav a { color: $BRAND_COLOR_RED; }
Module Variables
Module variables are defined outside a ruleset and are intended for use only with a single module.
If the variable is used only in a single file, define it at the top of the file above all rulesets.
If the variable is used by more than one file in the module, define it in a module level
_module_helpers.scsspartial.To prevent variable collisions, module variables should be prefixed with the base object name separated by a single dash.
$example-SPACING_UNIT: 10px; .example-hd { margin-bottom: $example-SPACING_UNIT; } .example-bd { margin-bottom: $example-SPACING_UNIT; }
Private Variables
Private variables are defined inside a single ruleset and are intended for use only within that ruleset.
Write private variables using uppercase letters delimited by underscores, and preceded by a single underscore.
.exampleObject { $_SIZE: 200px; $_OFFSET: -($_SIZE / 2); // Pull the object half its size to center it. position: absolute; top: 50%; left: 50%; height: $_SIZE; width: $_SIZE; margin-top: $_OFFSET; margin-left: $_OFFSET; }
-
7.5 Operators
Operators should always be surrounded by a single space.
Use of operators should always be accompanied by a comment.
.exampleObject { $_SIZE: 100px; $_PULL: -($_SIZE / 2); /* Pull the object half its size to center it. */ position: absolute; top: 50%; left: 50%; height: $_SIZE; margin-top: $_PULL; margin-left: $_PULL; }
-
7.6 Nesting
Avoid nesting selectors.
/* DO */ .hList { @include clearfix(); } .hList > li { float: left; } /* DO NOT */ .hList { @include clearfix(); > li { float: left; } }
Also avoid nesting pseudo classes & pseudo elements.
/* DO */ .nav a { color: #ffffff; } .nav a:hover { color: #00ff00; } /* DO NOT */ .nav a { color: #ffffff; &:hover { color: #00ff00; } }
There are a few scenarios where nesting is acceptable. These includes things like sandboxing an entire stylesheet to avoid conflicting selectors, wrapping a WYSIWYG stylesheet, and nesting media queries to make a small change that's not at a minor breakpoint.
When nesting is appropriate, all selectors should be indented one level deeper than the parent selector.
.exampleObject { padding: 10px; @media (max-width: 500px) { padding: 20px; } }
-
7.7 Mixins
Use mixins to define styles that can be reused throughout the site to avoid repeating common code blocks. Mixins can be used at both the global and module level. Mixins used by a single module should be prefixed with the module name, and defined in the appropriate location.
Mixin definitions should always include the parenthesis.
Provide default arguments when their absence could cause a compilation error, otherwise, avoid using default arguments in favor of optional arguments.
@mixin isVisuallyHidden() { width: 1px !important; height: 1px !important; margin: -1px !important; border: 0 !important; padding: 0 !important; clip-path: inset(100%) !important; clip: rect(0 0 0 0) !important; overflow: hidden !important; position: absolute !important; white-space: nowrap !important; }
If a mixin is used to produce vendor prefixes of a single property, it should mimic the W3C naming and syntax.
@mixin transition($transition) { -webkit-transition: $transition; -moz-transition: $transition; -o-transition: $transition; transition: $transition; }
-
7.8 @extend
Do not use
@extend./* DO */ .message { padding: 10px; border: 1px solid #cccccc; } .message_success { color: #00ff00; } .message_error { color: #ff0000; } /* DO NOT*/ .message { padding: 10px; border: 1px solid #cccccc; } .message_success { @extend .message; color: #00ff00; } .message_error { @extend .message; color: #ff0000; }
-
7.9 @control directives
@if,@each,@while,@forFlow control directives should never use the single line syntax.
Curly braces should be formatted identically to selectors.
.exampleObject { @if 1 + 1 == 2 { border: 1px solid; } }
-
7.10 Other @directives
@import
Do not include the file extension when using
@import.@import "_media";
@media
It is acceptable to use
@mediarules nested in selectors if they are used for small tweaks. Separate stylesheets (screen,screen_small,screen_large, etc) should be used for major breakpoints..exampleObject { padding: 10px; @media (max-width: 500px) { padding: 20px; } }
@function
Function naming should follow the same naming conventions as mixins.
@warn
It is acceptable to use
@warnin-lieu of TODO comments.@debug
It is acceptable to use
@debugprovided it is not committed to the version control repository.
-
8.1 Source Order
Use logical source order as assistive devices follow source top to bottom.
<div class="masthead"> ... </div> <div class="navigation"> ... </div> <div class="contentMain"> ... </div> <div class="contentRelated"> ... </div> <div class="footer"> ... </div>
-
8.2 JavaScript Content
JavaScript content should be accessible to screen readers. The best option for this is to use a logical source order and keep appended / prepended items near the element that triggers their appearance.
If this isn't an option rely on ARIA techniques instead.
<div class="contentMain"> <a href="#myModal" class="js-spawn-modal">View Larger Image</a> <div class="modal" id="myModal"> ... </div> </div> <div class="footer"> ... </div>
-
8.3 Page Titles
Include a unique title for each page.
<title>Horizontal Digital: HTML & CSS Style Guide - Accessibility</title>
-
8.4 ARIA Roles
Landmark Roles
Use landmark ARIA roles on all projects.
The landmark ARIA roles include:
- banner - wraps the typical site masthead. Use only once per page.
- search - place on a form that performs search.
- navigation - place on your navigation container (for in-document and site-wide navigation).
- main - place on container that holds the main page content. Use only once per page.
- complementary - place on containers that are akin to the
<aside>HTML5 element. - contentinfo - place on element that contains meta information about the page or content, often the site footer. Use only once per page.
When using HTML5 elements, like
<header>and<footer>, provide progressive enhancement for screen readers by including ARIA landmark roles on these elements as well, even though some screen readers may see this as redundant.<div class="masthead" role="banner"> ... <form class="search" action="#" method="post" role="search"> ... </form> ... </div> <div class="navigation" role="navigation"> ... </div> <div class="contentMain" role="main"> ... </div> <div class="contentRelated" role="complementary"> ... </div> <footer class="footer" role="contentinfo"> ... </footer>
If the project requirements allow, you may combine the use of landmark ARIA roles with HTML5 elements.
<header class="masthead" role="banner"> ... <form class="search" action="#" method="post" role="search"> ... </form> ... </header> <nav class="navigation" role="navigation"> ... </nav> <main class="contentMain" role="main"> ... </main> <aside class="contentRelated" role="complementary"> ... </aside> <footer class="footer" role="contentinfo"> ... </footer>
Resources
-
8.5 Skip Links
In order for keyboard users to easily skip to the main content of a site without tabbing through all the previous content, use a "skip to content" link. It is also acceptable to include a "skip to navigation" link if it takes an excessive number of tabs to get focus on the navigation.
It's best practice to bring focusable into view when they are focused.
<body> <a href="#page-content" class="isVisuallyHidden">Skip to Content</a> <div class="masthead"> ... </div> <div id="page-content" class="contentMain"> ... </div> </body>
.isVisuallyHidden:not(:focus):not(:active) { width: 1px !important; height: 1px !important; margin: -1px !important; border: 0 !important; padding: 0 !important; clip-path: inset(100%) !important; clip: rect(0 0 0 0) !important; overflow: hidden !important; position: absolute !important; white-space: nowrap !important; }
-
8.6 Alt Attributes
Use
altattributes on all images.If the image is in a link, the alt text should specify the action that will be taken upon clicking the image.
Include any text content that appears in an image in the
altattribute.<!-- DO --> <a href="index.html"><img src="../images/logo.png" alt="Crispen & Mulberry Home" /></a> <!-- DO NOT --> <a href="index.html"><img src="../images/logo.png" alt="Logo" /></a>
If a content image contains no useful information or text, include the
altattribute but leave the value empty.Do not describe the image. Never use the phrases "image of" or "picture of" in
altvalues.<!-- DO --> <img src="../images/business.jpg" alt="" /> <!-- DO NOT --> <img src="../images/business.jpg" alt="Picture of two gentlemen shaking hands with a blue sky and tree in the background" />
-
8.7 Longdesc Attributes
Do not rely on the longdesc attribute for consistent accessibility.
Instead, opt for including the content as text on the page or provide a link to the text alternative on the page.
<img src="infographic.jpg" alt="A list of all the presidents with facial hair listed chronologically" /> <a href="presidents-with-facial-hair.html">See the list of presidents who had facial hair while in office.</a>
-
8.8 Tables
Include
thead,tbodyandtfootto indicate the table header, table body and table footer.Declare table header cells and scope them properly.
<table> <thead> <tr> <th scope="col">Name</th> <th scope="col">Goals</th> <th scope="col">Assists</th> </tr> </thead> <tbody> <tr> <td>Evgeni Malkin</td> <td>50</td> <td>59</td> </tr> <tr> <td>Ilya Kovalchuk</td> <td>37</td> <td>46</td> </tr> </tbody> </table>
-
8.9 Form Labels
All form controls, except
<button>, require a corresponding<label>, even if the label is hidden from view.The
forattribute is required on all labels.<label for="name">Name:</label> <input type="text" id="name" />
If possible, it is preferable to wrap inputs with the corresponding label.
<label for="professionDoctor">Doctor <input type="radio" name="profession" id="professionDoctor" /></label> <label for="professionLawyer">Lawyer <input type="radio" name="profession" id="professionLawyer" /></label> <label for="professionOther">Other <input type="radio" name="profession" id="professionOther" /></label>
-
8.10 Form Button Values
Form input buttons require a
valueattribute.<input type="submit" value="Submit" />
<input type="reset" value="Reset" />
Image type inputs require an
altattribute.<input type="image" src="button.png" alt="Submit" />
Button elements require a value between the opening and closing tags.
<button type="submit">Submit</button>
-
8.11 Form Placeholder Text
Use placeholder text to provide a hint to the user.
Whenever possible, do not use
placeholdertext as a replacement for a<label>. When necessary, opt for visually hiding the label instead.<label for="email" class="isVisuallyHidden">Email</label> <input type="email" id="email" placeholder="user@domain.com" />
-
8.12 Form Grouped Controls
Use a
fieldsetto logically group form controls.If form labels don't clearly identify what information is being collected, use a
legendto label the group.Keep legend text short as it is read by screen readers before each input in the fieldset.
<fieldset> <legend>Profession</legend> <label for="professionDoctor">Doctor <input type="radio" name="profession" id="professionDoctor" /></label> <label for="professionLawyer">Lawyer <input type="radio" name="profession" id="professionLawyer" /></label> <label for="professionOther">Other <input type="radio" name="profession" id="professionOther" /></label> </fieldset>
-
8.13 Form Validation
Form inputs that have validation requirements - like required fields, or an expected email format - should be clearly labeled in an accessible manner indicating the requirement. They should also include the
aria-requiredattribute with the value set totrue.Form validation and submission should be accessible to both the mouse and keyboard.
All form inputs that are validated client side should also be validated in the same manner on the server side.
If a field returns as invalid, it should include the
aria-invalidattribute with the value set to the proper value (true,false,grammar,spelling).<form action="#" method="post"> <ul> <li> <label for="formUsername">Username <span class="required">*</span></label> <input type="input" id="formUsername" required aria-required="true" /> </li> <li> <label for="formEmail">Email Address <span class="required">*</span></label> <input type="email" id="formEmail" required aria-required="true" /> </li> <li> <label for="formPassword">Password <span class="required">*</span></label> <input type="password" id="formPassword" required aria-required="true" aria-describedby="password-requirements" /> <span id="password-requirements">Use 6-20 characters, at least 1 uppercase letter and 1 number.</span> </li> <li> <input type="submit" value="Sign Up" /> </li> </ul> </form>
Resources
- http://alistapart.com/article/aria-and-progressive-enhancement
- http://www.deque.com/blog/accessible-client-side-form-validation-html5-wai-aria/
- https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-invalid_attribute
- http://webaim.org/techniques/formvalidation/
-
8.14 Hiding Content
When hiding content on a page, choose the appropriate method.
Using
display: none;orvisibility: hidden;will hide content from a screen reader.If content is meant to be available to a screen reader but not to a sighted user, hide the content by using a utility class.
<h2 class="isVisuallyHidden">Featured Articles</h2>
.isVisuallyHidden { width: 1px; height: 1px; margin: -1px; padding: 0; border: 0; position: absolute; clip: rect(0 0 0 0); overflow: hidden; }
Resources
-
8.15 Focus Styles
Include
:focusstyles to ensure proper keyboard accessibility. Keep in mind,:focusis included inreset.css, so it will need to be intentionally styled to fit your project requirements.Resources
-
8.16 Tabindex
A site should be navigable via keyboard. Write markup that is semantic and supports a logical tab index. Modifying the
tabindexshould be a last resort.
-
8.17 Magnification
Web pages should remain usable and understandable when the text is magnified via the browser's magnification feature. This includes "pinch zooming" on touch devices. The page may not remain aesthetically pleasing, but it should remain understandable and usable.
-
9.1 Support Documentation
Identify which browsers and devices are supported in the
README.mdfile.
-
9.2 Progressive Enhancement
Progressive enhancement methodology should be used to the fullest extent possible on all projects.
Resources
-
9.3 Design Accuracy
Surgical precision is expected when recreating our static design assets into dynamic websites. While RWD makes this more challenging, you can still test for visual accuracy at the breakpoints provided in the comps.
Test the accuracy of your work as part of your everyday workflow. You can easily test how accurate the website is in relation to the initial design assets in any environment using the following steps:
- Take a screenshot in the browser.
- Paste the screenshot as the top layer in the design asset.
- Drop the opacity of the screenshot to 50%.
- Invert the colors of the screenshot.
- Everything that matches turns a 50% grey and "disappears" from view while the remaining artifacts that are misplaced generally turn hot pink and neon blue.
-
9.4 Testing
Test all required browsers and devices early and often. A feature is not considered complete until it is tested natively in all required browser and device environments.
-
10.1 Folder Structure
Our standard folder structure is as follows:
└── assets ├── media | ├── images | ├── fonts | └── uploads ├── styles ├── scripts └── vendorAdditionally, an example of a typical sass directory structure can be found in the sass section.
-
10.2 File Names
Use lowercase for all file names (including images) with hyphens as delimiters between words.
The only exception to this rule is SCSS partials which should be prefixed with an underscore.
Good Examples
- modern.css
- global-masthead.html
- josh-with-a-horses-head.png
- _vars.scss
-
10.3 Storage of Dev Assets
Do not store development assets such as wireframes, PSDs, sprite source files, etc. in the actual project respository.
(The MIT License)
Copyright (c) 2012 Airbnb
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
