Styleguide for developing responsive, optimized, and sustainable HTML, CSS, and JS.
- Golden rule
- HTML
- Syntax
- HTML5 doctype
- Pragmatism over semantics
- Attribute order
- [JavaScript generated markup](#javascript-generated markup)
- CSS
- Writing copy
- Javascript
- PHP
"Part of being a good steward to a successful project is realizing that writing code for yourself is a Bad Idea™. If thousands of people are using your code, then write your code for maximum clarity, not your personal preference of how to get clever within the spec." - Idan Gazit
All code in any code base should look like a single person typed it, no matter how many people contributed.
This means strictly enforcing these agreed upon guidelines at all times.
- Use soft-tabs with two spaces
- Nested elements should be indented once (2 spaces)
- Always use double quotes, never single quotes
- Don't include a trailing slash in self-closing elements
Incorrect example:
<!DOCTYPE html>
<html>
<head>
<title>Page title</title>
</head>
<body>
<img src='images/company-logo.png' alt='Company' />
<h1 class='hello-world'>Hello, world!</h1>
</body>
</html>
Correct example:
<!DOCTYPE html>
<html>
<head>
<title>Page title</title>
</head>
<body>
<img src="images/company-logo.png" alt="Company">
<h1 class="hello-world">Hello, world!</h1>
</body>
</html>
Enforce standards mode in every browser possible with this simple doctype at the beginning of every HTML page.
<!DOCTYPE html>
Strive to maintain HTML standards and semantics, but don't sacrifice pragmatism. Use the least amount of markup with the fewest intricacies whenever possible.
HTML attributes should come in this particular order for easier reading of code.
- class
- id
- data-*
- for|type|href
Such that your markup looks like:
<a class="" id="" data-modal="" href="">Example link</a>
Writing markup in a javascript file makes the content harder to find, harder to edit, and less performant. Don't do it.
- Create variables for your CSS animation properties, especially duration and delay. Consistent animation timing ensures eye-pleasing UI effects.
- Create variables for block padding, and use simple equations ($blockPadding/2) for lessor blocks. This ensures consistent element spacing.
- Utilize CSS animations as best you can -- they can save you a load of JavaScript code down the road.
Code is written and maintained by people. Ensure your code is descriptive, well commented, and approachable by others.
Great code comments convey context or purpose and should not just reiterate a component or class name.
Bad example:
/* Modal header */
.modal-header {
...
}
Good example:
/* Wrapping element for .modal-title and .modal-close */
.modal-header {
...
}
- Keep classes lowercase and use dashes (not underscores or camelCase)
- Avoid arbitrary shorthand notation
- Keep classes as short and succinct as possible
- Use meaningful names; use structural or purposeful names over presentational
- Prefix classes based on the closest parent component's base class
Bad example:
.t { ... }
.red { ... }
.header { ... }
Good example:
.tweet { ... }
.important { ... }
.tweet-header { ... }
- Use classes over generic element tags
- Keep them short and limit the number of elements in each selector to three
- Scope classes to the closest parent when necessary (e.g., when not using prefixed classes)
Bad example:
span { ... }
.page-container #stream .stream-item .tweet .tweet-header .username { ... }
.avatar { ... }
Good example:
.avatar { ... }
.tweet-header .username { ... }
.tweet .avatar { ... }
- Organize sections of code by component
- Develop a consistent commenting hierarchy
- If using multiple SASS files, break them down by component
Always write copy, including headings and code comments, in sentence case. In other words, aside from titles and proper nouns, only the first word should be capitalized.
Load all Javascript with AMD. Organize all scripts as separate coffee files and loaded asynchronously.
- Do your best to write JS in CoffeeScript.
- Use only Coffeescript in your coffee files, don't hardcode vanilla js in your coffee fies.
- Use soft-tabs with a two space indent.
- Always use camelCase, never underscores.
- Use implicit parentheses when possible.
- Follow @jashkenas's style. See the documentation for good examples.
- Any top level objects should be namespaced under the GitHub namespace.
- Don't ever use
$.get or $ .post. Instead use $.ajax and provide both a success handler and an error handler. - Use
$.fn.on instead of $ .fn.bind,$.fn.delegate and $ .fn.live.
- create a file showWidget.coffee (touch app/scripts/showWidget.coffee)
- use the AMD spec to load your JS (define, module, exports)
define([]
->
return 'module loaded'
)
- return public functions and methods in the API
- include a reference to the file in the RequireJS configuration
require ["showWidget"], (app) ->
console.log app
- reference the pattern library to ensure the pattern has not been created
- write the snippet with proper naming conventions (read style guide)
- note the CSS module has been completed
Use soft-tabs with a two space indent. Do your best to never use a semicolon. This means avoiding them at line breaks and avoiding multi-statement lines. For more info, read Mislav's blog post.
Try to prefix all javascript-based selectors with js-. This is taken from slightly obtrusive javascript. The idea is that you should be able to tell a presentational class from a functional class. Most of the codebase doesn't do this, let's try and move toward it.
Create separate coffee or js files for each individual component or feature.
Javascript objects are defined and exported as needed. The global TTVapp object contains methods that are returned in the public API. These methods are described below.
- The Utils object is used for caching objects, outputting dynamic data, defining app settings, and routing your application.
- Store references to frequently accessed data in Utils.cache
- use _log as a wrapper for console.log. this is so we can toggle the debug var in the settings object.
- stubbed for use when implementing a pushstate for the video pages
- The base Ajax Object provided in Sparky allows a simple way to make your request. Ajax.call for POST requests, and Ajax.get for get requests.
A request for a "Like Button" might look like this:
Ajax.call 'doLike',
pictureID: 7
(result) ->
# success
->
alert 'must be logged in'
First parameter would be the method we want to call for our Ajax script, second parameter is the data, third is the success function, and if the fourth parameter is set to a function, it will fire only if the user is not logged in.
Events play an important role in Javascript and the DOM. Javasript should be used to handle the logic, but having the ability to bind events by writing HTML is a breeze, and better represents what your specific elements can do. Say goodbye to the days of messy and disorganized event binding!
Firstly, create a few HTML elements in which you want to bind events to. Using HTML5 data attributes, assigning data-event to an element will bind it to the function name of its value. For instance: data-event="doLogin" will bind it to Events.endpoints.doLogin if it exists.
The default event type bound to the element is the click event. If you wish to listen for a different type of event, add the data-attribute data-method to your element and it's value should be the jQuery event name.
If you add to the DOM and want to bind elements, you may call Events.init or Events.bindEvents. Elements that have already been bound will not be bound again, thus binding only new elements.
Provided are a few examples of the implementation of events. The this keyword is available, and if you need to inspect the event object, you may pass it as a parameter to your endpoint function.
These guidelines are essentially identical to the Facebook guidelines, since I basically copy-pasted them. If you are already familiar with the Facebook guidelines, you probably don't need to read this super thoroughly.
- Use two spaces for indentation. Don't use tab literal characters.
- Use Unix linebreaks ("\n"), not MSDOS ("\r\n") or OS9 ("\r").
- Use K&R style braces and spacing.
- Put a space after control keywords like if and for.
- Put a space after commas in argument lists.
- Put a space around operators like =, <, etc.
- Don't put spaces after function names.
- Parentheses should hug their contents.
- Generally, prefer to wrap code at 80 columns.
- Name variables and functions using lowercase_with_underscores.
- Name classes using UpperCamelCase.
- Name methods and properties using lowerCamelCase.
- Use uppercase for common acronyms like ID and HTML.
- Name constants using UPPERCASE.
- Write true, false and null in lowercase.
- Do not use "#" (shell-style) comments.
- Prefer "//" comments inside function and method bodies.
- Use "" tag.
- Prefer casts like (string) to casting functions like strval().
- Prefer type checks like $v === null to type functions like is_null().
- Avoid all crazy alternate forms of language constructs like endwhile and "< >".
- Always put braces around conditional and loop blocks.
- Use PHP as a programming language, not a templating language.
- Avoid globals.
- Avoid extract().
- Avoid eval().
- Avoid variable variables.
- Prefer classes over functions.
- Prefer class constants over defines.
- Avoid naked class properties; instead, define accessors.
- Use exceptions for error conditions.
- Use type hints, use assert_instances_of() for arrays holding objects.
If/else:
if ($some_variable > 3) {
// ...
} else if ($some_variable === null) {
// ...
} else {
// ...
}
You should always put braces around the body of an if clause, even if it is only one line long. Note spaces around operators and after control statements. Do not use the "endif" construct, and write "else if" as two words.
for:
for ($ii = 0; $ii < 10; $ii++) {
// ...
}
Prefer $ii, $jj, $kk, etc., as iterators, since they're easier to pick out visually and react better to "Find Next..." in editors.
foreach:
foreach ($map as $key => $value) {
// ...
}
switch:
switch ($value) {
case 1:
// ...
break;
case 2:
if ($flag) {
// ...
break;
}
break;
default:
// ...
break;
}
break statements should be indented to block level.
array literals:
$junk = array(
'nuts',
'bolts',
'refuse',
);
Use a trailing comma and put the closing parenthesis on a separate line so that diffs which add elements to the array affect only one line.
operators:
$a + $b; // Put spaces around operators.
$omg.$lol; // Exception: no spaces around string concatenation.
$arr[] = $element; // Couple [] with the array when appending.
$obj = new Thing(); // Always use parens.
function/method calls:
// One line
eject($cargo);
// Multiline
AbstractFireFactoryFactoryEngine::promulgateConflagrationInstance(
$fuel,
$ignition_source);
function/method definitions:
function example_function($base_value, $additional_value) {
return $base_value + $additional_value;
}
class C {
public static function promulgateConflagrationInstance(
IFuel $fuel,
IgnitionSource $source) {
// ...
}
}
class:
class Dog extends Animal {
const CIRCLES_REQUIRED_TO_LIE_DOWN = 3;
private $favoriteFood = 'dirt';
public function getFavoriteFood() {
return $this->favoriteFood;
}
}