Table of contents
- Browser Support
- Browser Testing
- Preprocessor
- Postprocessor
- Length Units
- Breakpoints
- Mobile First
- Code Formatting and Style
- Naming Conventions
- Text Direction
- Characters and Punctuation
- Inspiration and Reference
As a general rule, browsers which global usage share is below 1% are not supported. Other browsers which may show a higher share are not supported for technical reasons (Internet Explorer 9-, Opera Mini, UC Browser...).
Global usage share statistics can be obtained from http://caniuse.com/usage_table.php.
Desktop
Browser | Version |
---|---|
Internet Explorer | 10+ (sites and apps) |
Chrome | latest |
Firefox | latest |
Safari | latest |
Not included:
- Below 1%: Opera.
Mobile
Browser | Version |
---|---|
Android Browser | 4.3+ |
IE Mobile | latest |
Chrome Android | latest |
Safari iOS | latest |
Not included:
- Above 1%: Opera Mini, UC Browser for Android.
- Below 1%: Opera Mobile, Blackberry Browser, Firefox for Android.
Use BrowserStack.
http://www.browserstack.com/
If you need to test Internet Explorer locally, get the official virtual machines from modern.IE.
Use LESS.
http://lesscss.org/
Adding and maintaining browser vendor prefixes mixins is both time consuming and error prone. This process can be totally automated via Autoprefixer, wich adds just the necessary vendor prefixes according to the up-to-date caniuse.com database.
Use Autoprefixer.
https://github.com/postcss/autoprefixer
By not setting the base font size and breakpoints to an absolute value we let the Browser and OS combination define the native optimal base font size, wich helps in readability, as well as users set their preferred base font size, which helps in accesibility.
Whenever the base font size is changed our UI will scale accordingly, as if the user had used the browser's zoom. As a quick example, here's a Foundation's Zurb Docs page when doubling the base font-size from 16px to 32px via browser settings and when zooming the page to 200%. Almost identical results.
Read more on the subject in Cloud Four's Proportional Media Queries FTW! and this W3Conversions post.
Set html
base font-size
to 100%
, 1em
, or inherit
. This is equivalent to 16px
for many browser and OS combinations, and that's the proportion that our UI will be based on.
Refer to this table to decide which unit to use in each case.
Unit | Use for |
---|---|
em | media query breakpoints |
rem | font-size, dimensions (margin, padding, height) |
% | width (mainly for grid units) |
px | small details (borders, corners, shadows, images) |
unitless | line-height |
Design comps and deliverables will typically be set in px. To convert px to a proportional rem value, divide by 16:
px | rem |
---|---|
16px | 1rem |
10px | 0.625rem |
... | ... |
Alternatively, if you prefer not having to calculate the rem values manually, use this simple px to rem conversion technique http://codepen.io/janogarcia/pen/bNrKEP/.
px | rem |
---|---|
16px | 16/@px |
10px | 10/@px |
... | ... |
To convert px to a proportional breakpoint em value, divide by 16:
px | breakpoint em |
---|---|
640px | 40em |
1025px | 64.0625em |
... | ... |
Define 3 to 5 global breakpoints, those that will affect the overall site layout and design. It is key that those breakpoints are agreed and shared with the designer.
As a starting point, you can refer to how breakpoints are configured on popular Front-end frameworks.
Add other minor breakpoints as necessary, those that affect only a few components (a special navigation bar, a media gallery...) for which you need a more fine breakpoint control, or otherwise would break their layout.
A major limitation of media query breakpoints is that they are based on the browser viewport. If you need ultimate component responsiveness, you'll need element queries, that is, media queries that are based on the component root, not on the browser viewport. This allows a component to be aware of the available width of the context where is being placed (think moving a horizontal menu from the header to a sidebar).
Techniques for Responsive Typography (section "Using Element Queries")
Responsive Elements
For best rendering performance, start with mobile styles first and then override those styles as necessary as the viewport gets larger.
Set your editor to the following settings to avoid common code inconsistencies and dirty diffs:
- Use soft-tabs set to four spaces.
- Trim trailing white space on save.
- Set encoding to UTF-8.
- Add new line at end of files.
Follow HTML style from http://codeguide.co/#html, with the following additions and exceptions:
- Use soft tabs with 4 spaces instead of 2.
- Write one discrete, block-level element per line.
- Always use lowercase tag and attribute names.
HTML attributes should be listed in alphabetical order.
<a class="{{class}}" data-name="{{name}}" href="{{url}}" id="{{id}}">{{text}}</a>
Elements with multiple attributes can have attributes arranged across multiple lines in an effort to improve readability and produce more useful diffs.
<a class="[value]"
data-action="[value]"
data-id="[value]"
href="[url]">
<span>[text]</span>
</a>
Alphabetize classes, ordered by component, helper, state, and context. Applying modifier classes after each individual component.
<div class="g collection collection--1of3 bch mtl tci is-active has-dropdown"></div>
Always escape the following characters:
Character | HTML entity |
---|---|
< | < |
> | > |
& | & |
Additionally, escape single and double quotes for attribute values:
Character | HTML entity |
---|---|
" | " |
' | ' |
- Use one discrete selector per line in multi-selector rulesets.
- The opening brace
{
on the same line as the last selector, preceded by a space. - The first declaration on a new line after the opening brace
{
. - Each declaration indented by four spaces.
- Each declaration on its own new line, with a trailing
;
. - Properties and values on the same line.
- Add a space after
:
. - The closing brace
}
on its own new line, and in the same column as the first character of the ruleset - Add a space after
//
comments.
// A basic example showing the most basic CSS formatting rules.
.selector-a,
.selector-b {
color: #aaa;
}
- Order properties alphabetically.
- Add a space after commas in values, e.g.,
rgba(0, 0, 0, 0.5)
- Use lowercase and shorthand hex values, e.g.,
color: #aaa;
. Lowercase letters are much easier to discern when scanning a document as they tend to have more unique shapes. - Use double quotes consistently, e.g.,
content: ""
- Double quote attribute values in selectors, e.g.,
input[type="checkbox"]
- Where allowed, avoid specifying units for zero-values, e.g.,
margin-top: 0;
instead ofmargin-top: 0px;
. - Strive to limit use of shorthand declarations to instances where you must explicitly set all the available values. Common overused shorthand properties include: padding, margin, font, background, border, border-radius. Excessive use of shorthand properties often leads to unnecessary overrides and unintended side effects.
- Separate each ruleset by a blank line.
// A complete example on CSS formatting.
.selector-a,
.selector-b {
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
color: #aaa;
font-style: italic;
padding-bottom: @b-space * 3;
}
input[type="checkbox"] {
content: "";
margin-top: 0;
}
Exceptions and slight deviations
Large blocks of single declarations can use a slightly different, single-line format. In this case, a space should be included after the opening brace and before the closing brace.
.icon {
background-image: url(/img/sprite.svg);
display: inline-block;
height: 16px;
width: 16px;
}
.icon--home { background-position: 0 0 ; }
.icon--person { background-position: -16px 0 ; }
.icon--files { background-position: 0 -16px; }
.icon--settings { background-position: -16px -16px; }
Long, comma-separated property values - such as collections of gradients or shadows - can be arranged across multiple lines in an effort to improve readability and produce more useful diffs. There are various formats that could be used; one example is shown below.
.selector {
background-image:
linear-gradient(#fff, #ccc),
linear-gradient(#f3c, #4ec);
box-shadow:
1px 1px 1px #000,
2px 2px 1px 1px #ccc inset;
}
Specificity
- Stick with classes instead of IDs for styling.
- Avoid unnecessary nesting, limit it as much as possible. This prevents overly-specific CSS selectors.
- Extends and Mixins should be placed before standard properties.
- Always place
:extend
statements on the first lines of a declaration block. - Group
.mixin
statements at the top of a declaration block, after any:extend
statements, ordered alphabetically. - Where possible, write numbers at the end of mathematic operations, e.g.,
@b-space * 0.5
.
// A basic example on LESS formatting.
.selector {
&:extend(.clearfix all);
.flex(1 1 50%);
.transition(opacity 0.2s ease);
padding-bottom: @b-space * 0.5;
}
A complete example on LESS and CSS formatting
You don't need to memorize the LESS and CSS formatting rules, just refer to the following snippet, which includes all the listed rules.
// A complete example on LESS and CSS formatting.
.selector-a,
.selector-b {
&:extend(.clearfix all);
.flex(1 1 50%);
.transition(opacity 0.2s ease);
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5);
color: #aaa;
font-style: italic;
padding-bottom: @b-space * 3;
}
input[type="checkbox"] {
content: "";
margin-top: 0;
}
Naming conventions in CSS are hugely useful in making the code more strict, more transparent, and more informative.
A good naming convention will better communicate what type of thing a class does, where can be used, and the relationships between classes.
This has several benefits when reading and writing HTML and CSS:
- It helps to distinguish between the classes for the root of the component, descendent elements, and modifications.
- It keeps the specificity of selectors low.
- It helps to decouple presentation semantics from document semantics.
The following naming convention, based on Medium's and SUIT CSS style guides, relies on structured class names and meaningful hyphens (i.e., not using hyphens merely to separate words).
.component {}
.component.is-animating {}
.component--modifier {}
.component-part {}
.component-anotherPart {}
A couple of examples sites that follow strict naming conventions:
- http://www.lonelyplanet.com/, based on Rizzo, which follows a style guide driven development approach.
- http://codeschool.com/, based on MVCSS.
syntax: js-<targetName>
JavaScript-specific classes reduce the risk that changing the structure or theme of components will inadvertently affect any required JavaScript behaviour and complex functionality. It is not neccesary to use them in every case, just think of them as a tool in your utility belt. If you are creating a class, which you dont intend to use for styling, but instead only as a selector in JavaScript, you should probably be adding the js-
prefix. In practice this looks like this:
<a href="/login" class="btn btn-primary js-login"></a>
JavaScript-specific classes should not, under any circumstances, be styled.
Utility classes are low-level structural and positional traits. Utilities can be applied directly to any element; multiple utilities can be used together; and utilities can be used alongside component classes.
They exist because certain CSS properties and patterns are used frequently. For example: floats, containing floats, vertical alignment, text truncation. Relying on utilities can help to reduce repetition and provide consistent implementations.
Because utilities are so focused, they will generally use !important
to ensure their styles are always applied.
<div class="u-clearfix">
<p class="u-textTruncate">{$text}</p>
<img class="u-pullLeft" src="{$src}" alt="">
<img class="u-pullLeft" src="{$src}" alt="">
<img class="u-pullLeft" src="{$src}" alt="">
</div>
Syntax: u-<utilityName>
Utilities must use a camel case name, prefixed with a u
namespace. What follows is an example of how various utilities can be used to create a simple structure within a component.
<div class="u-clearfix">
<a class="u-pullLeft" href="{$url}">
<img class="u-block" src="{$src}" alt="">
</a>
<p class="u-sizeFill u-textBreak">
…
</p>
</div>
Responsive utilities
Certain utilities can have responsive variants using the patterns: u-sm-<name>
, u-md-<name>
, and u-lg-<name>
for small, medium, and large media query breakpoints.
Syntax: <componentName>[--modifierName|-descendantName]
Component driven development offers several benefits when reading and writing HTML and CSS:
- It helps to distinguish between the classes for the root of the component, descendant elements, and modifications.
- It keeps the specificity of selectors low.
- It helps to decouple presentation semantics from document semantics.
You can think of components as custom elements that enclose specific semantics, styling, and behaviour.
ComponentName
The component's name must be written in camel case.
.myComponent { /* … */ }
<article class="myComponent">
…
</article>
componentName--modifierName
A component modifier is a class that modifies the presentation of the base component in some form. Modifier names must be written in camel case and be separated from the component name by two hyphens. The class should be included in the HTML in addition to the base component class.
/* Core button */
.btn { /* … */ }
/* Default button style */
.btn--default { /* … */ }
<button class="btn btn--primary">…</button>
componentName-descendantName
A component descendant is a class that is attached to a descendant node of a component. It's responsible for applying presentation directly to the descendant on behalf of a particular component. Descendant names must be written in camel case.
<article class="tweet">
<header class="tweet-header">
<img class="tweet-avatar" src="{$src}" alt="{$alt}">
…
</header>
<div class="tweet-body">
…
</div>
</article>
componentName.is-stateOfComponent
Use is-stateName
for state-based modifications of components. The state name must be Camel case. Never style these classes directly; they should always be used as an adjoining class.
JS can add/remove these classes. This means that the same state names can be used in multiple contexts, but every component must define its own styles for the state (as they are scoped to the component).
.tweet { /* … */ }
.tweet.is-expanded { /* … */ }
<article class="tweet is-expanded">
…
</article>
In order to support both LTR (most languages) and RTL (Arabic, Hebrew, Persian...) languages our styles should be text direction agnostic.
We'll serve two separate stylesheets for LTR and RTL languages. We won't be using RTL overrides on top of a LTR stylesheet: usually implemented as a second stylesheet containing the same selectors as the LTR one, or in the same stylesheet but preceding the RTL selectors with [dir=ltr]
or .dir-rtl
.
First, set the global text direction variables:
// Global: text direction
// For LTR set @base-text-direction: ltr;
// For RTL set @base-text-direction: rtl;
@base-text-direction: ltr;
// For LTR set @start: left; @end: right;
// For RTL set @start: right; @end: left;
@start: left;
@end: right;
Then, add proper lang
and dir
attributes to the <html>
tag:
<!-- English -->
<html lang="en" dir="ltr">
<!-- Arabic -->
<html lang="ar" dir="rtl">
Additionaly, when dealing with a RTL language, add direction: rtl;
and unicode-bidi: embed;
styles to the body
element:
body {
& when (@base-text-direction = rtl) {
direction: rtl;
unicode-bidi: embed;
}
}
Once you have properly set up the html
and body
elements language and text direction properties, make sure to turn every hardcoded horizontal property and value in your stylesheet, that is not centered or symmetrical, into a dynamic -text direction agnostic- horizontal value.
Use start
and end
, instead of the harcoded left
and right
positional names throughout your code (variable names, class names, properties, values...):
// Technique inspired on Yahoo! Atomic CSS
// https://www.haikudeck.com/atomic-css-science-and-technology-presentation-dJ0xlFjhBQ#slide-71
@blockquote-padding-start: 15/@px;
// left for LTR, right for RTL
.float-start { float: @start; }
// right for LRT, left for RTL
.float-end { float: @end; }
.position-bottom-start {
bottom: 0;
@{start}: 0;
}
.position-bottom-end {
bottom: 0;
@{end}: 0;
}
Watch out for the following properties, which may contain non-centered horizontal positions:
text-align
float
clear
margin
padding
border
border-radius
background-position
right
left
direction
Keep an eye, too, on transforms that affect any directional UI element (arrows, triangles, angle brackets...): rotate(90deg)
in LTR becomes rotate(-90deg)
for RTL.
Also, transform functions order matters. For example, let's say we're applying a translateX(10px)
transform in LTR to an arrow icon pointing to the right, the same transform in RTL plus inverting the icon direction will be either scaleX(-1) translateX(10px)
or translateX(-10px) scaleX(-1)
for RTL, but not scaleX(-1) translateX(-10px)
or translateX(10px) scaleX(-1)
.
Avoid using shorthand values for those properties that deal with horizontal dimensions and both left and right dimensions are not equal or symmetrical: border-width:
, border-color:
, border-style:
, border-radius:
, margin:
, padding:
...
If you really need to use shorthand values, wrap them inside a LESS CSS Guard or Mixin:
.border-rounded-start {
& when (@base-text-direction = ltr) {
border-radius: @component-base-border-rounded 0 0 @component-base-border-rounded;
}
& when (@base-text-direction = rtl) {
border-radius: 0 @component-base-border-rounded @component-base-border-rounded 0;
}
}
Flip horizontally every relevant or directional image. Typical examples of directional images include icons and icon sprites. As for relevant pictures and illustrations, you could create two versions, image.png
and image-rtl.png
, or less ideally make use of CSS transforms.
If you're cropping an image with a container element, you'll probably want to normalize the container direction to direction: ltr
so that the cropped area of the image is always the same no matter the agent's language direction.
Use a suitable font that supports the target RTL languages, or use basic Helvetica, Arial, sans-serif
fonts and no italics.
Use LTR overrides direction: ltr;
for that data that is always LTR: an <input>
for an URL, numbers, telephone numbers...
The direction
property in CSS sets the direction of content flow within a block-level element. This applies to text, inline, and inline-block elements. It also sets the default alignment of text and the direction that table cells flow within a table row.
It tells the browser the direction in which the displayed text is intended to be read, but it does not change the writing direction of text. The following example indicates that the direction of the Hebrew text is right to left:
<p>The bulk of the content is in English and flows left to right,
until this phrase in Hebrew makes an appearance,
<span lang="he" dir="rtl"> שָׁלוֹם</span> (meaning hello), which
needs to be set to read right-to-left.</p>`.
There is a specific HTML tag that can be used for changing the direction of text: <bdo>
the bidirectional override element. This exists so there is a semantics-free element to use just for this purpose:
<!-- This text will go left to right. -->
<p>This text will go left to right.</p>
<!-- .tfel ot thgir og lliw txet sihT -->
<p><bdo dir="rtl">This text will go right to left.</bdo></p>
Alternatively, you can use these helpers for local overrides:
[dir="ltr"],
.dir-ltr {
direction: ltr;
unicode-bidi: embed;
}
[dir="rtl"],
.dir-rtl {
direction: rtl;
unicode-bidi: embed;
}
bdo[dir="ltr"],
.dir-ltr-bdo {
direction: ltr;
unicode-bidi: bidi-override;
}
bdo[dir="rtl"],
.dir-rtl-bdo {
direction: rtl;
unicode-bidi: bidi-override;
}
For text of unknown directionality, for instance user generated content, we can add dir="auto"
to a wrapping element to let the user agent decide.
Make sure to always use the proper chracters and punctuation symbols for the text language in any context (HTML, CSS or JavaScript).
For example, in Chinese use the full-width comma ,
(single character) instead of the English comma and space combination ,
(two characters). Same for full stops 。
, colons :
and question marks ?
, to name a few.
Feel free to check the Punctuation articles on Wikipedia .
Area | Tools |
---|---|
Communication |
|
Design |
|
Development |
|
- http://styleguides.io/
- http://findguidelin.es/
- http://www.logodesignlove.com/brand-identity-style-guides
- http://bradfrost.com/blog/post/style-guide-best-practices/
- @fat
https://medium.com/@fat/mediums-css-is-actually-pretty-fucking-good-b8e2a6c78b06 - @necolas
https://github.com/suitcss/suit/blob/master/doc/STYLE.md - @mdo
http://codeguide.co/ - @csswizardry
http://cssguidelin.es/
Preprocessor-based
- @HugoGiraudel
http://sass-guidelin.es/
They are in essence conventions for selector naming and their combinators:
- Namespacing
- Meaningful dashes and underscores
- Module semantics (parent, children, extensions...)
Plus some ideas that revolve around OO design principles:
- Separation of concerns (CSS and HTML decoupling)
- SOLID principles
Popular
- Bootstrap
- Zurb Foundation
- html5-boilerplate
Not an UI framework, but has some useful cross-browser helper styles.
Niche
More tools
Responsive patterns
- http://bradfrost.github.io/this-is-responsive/
- http://tympanus.net/codrops/category/blueprints/
- http://patterntap.com/code
- http://html5please.com/
- http://caniuse.com/
- http://devdocs.io/
- http://web.archive.org/web/20131218210246/http://reference.sitepoint.com/css
- http://apps.workflower.fi/vocabs/
HTML
- http://html5doctor.com/
- http://htmlelement.info/
- http://www.w3.org/html/wg/drafts/html/CR/obsolete.html#non-conforming-features
- https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
- https://developer.mozilla.org/en-US/docs/Web/HTML/Reference
- https://docs.webplatform.org/wiki/html
CSS
- http://tympanus.net/codrops/css_reference/
- https://css-tricks.com/almanac/
- http://www.quirksmode.org/css/
- https://developer.mozilla.org/en-US/docs/Web/CSS/Reference
- https://docs.webplatform.org/wiki/html
- http://www.css3files.com/
Chars
Multilingual
- http://responsivenews.co.uk/post/123104512468/13-tips-for-making-responsive-web-design
- http://www.bbc.co.uk/gel/web/building-blocks/non-latin-typography/chinese-scripts
- https://en.wikipedia.org/wiki/Category:Punctuation
Multilingual: Text direction
- http://en.wikipedia.org/wiki/Right-to-left
- http://en.wikipedia.org/wiki/Bi-directional_text
- https://codex.wordpress.org/Right-to-Left_Language_Support
- http://alfy.me/2014/07/26/lets-talk-about-rtl.html
- http://stackoverflow.com/questions/12552804/direction-ltr-in-a-rtl-html-page/12555873#12555873
Validation