| Index: styleguide/web/web.md
|
| diff --git a/styleguide/web/web.md b/styleguide/web/web.md
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..60150efcf737dcbf37cea904e70c8018526c1d88
|
| --- /dev/null
|
| +++ b/styleguide/web/web.md
|
| @@ -0,0 +1,470 @@
|
| +<style>
|
| +
|
| +.note::before {
|
| + content: 'Note: ';
|
| + font-variant: small-caps;
|
| + font-style: italic;
|
| +}
|
| +
|
| +</style>
|
| +
|
| +# Chromium Web Development Style Guide
|
| +
|
| +[TOC]
|
| +
|
| +## Where does this style guide apply?
|
| +
|
| +This style guide targets Chromium frontend features implemented with JavaScript,
|
| +CSS, and HTML. Developers of these features should adhere to the following
|
| +rules where possible, just like those using C++ conform to the [Chromium C++
|
| +styleguide](../c++/c++.md).
|
| +
|
| +This guide follows and builds on:
|
| +
|
| +* [Google HTML/CSS Style Guide](https://google.github.io/styleguide/htmlcssguide.xml)
|
| +* [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml)
|
| +* [Google Polymer Style Guide](http://go/polymer-style)
|
| +
|
| +<div class="note">
|
| +Concerns for browser compatibility are usually not relevant for Chromium-only
|
| +code.
|
| +</div>
|
| +
|
| +## Separation of presentation and content
|
| +
|
| +When designing a feature with web technologies, separate the:
|
| +
|
| +* **content** you are presenting to the user (**HTML**)
|
| +* **styling** of the data (**CSS**)
|
| +* **logic** that controls the dynamic behavior of the content and presentation
|
| + (**JS**)
|
| +
|
| +This highlights the concern of each part of the code and promotes looser
|
| +coupling (which makes refactor easier down the road).
|
| +
|
| +Another way to envision this principle is using the MVC pattern:
|
| +
|
| +| MVC Component | Web Component |
|
| +|:-------------:|:-------------:|
|
| +| Model | HTML |
|
| +| View | CSS |
|
| +| Controller | JS |
|
| +
|
| +It's also often appropriate to separate each implementation into separate files.
|
| +
|
| +DO:
|
| +```html
|
| +<!-- missile-button.html -->
|
| +<link rel="stylesheet" href="warnings.css">
|
| +<b class="warning">LAUNCH BUTTON WARNING</b>
|
| +<script src="missile-button.js">
|
| +```
|
| +```css
|
| +/* warnings.css */
|
| +.warning {
|
| + color: red;
|
| +}
|
| +```
|
| +```js
|
| +// missile-button.js
|
| +document.querySelector('b').onclick = fireZeeMissiles;
|
| +```
|
| +
|
| +DON'T:
|
| +```html
|
| +<!-- missile-button.html -->
|
| +<b style="color: red;" onclick="fireZeeMissiles()">LAUNCH BUTTON WARNING</span>
|
| +```
|
| +
|
| +<div class="note">
|
| +For various technical and historical reasons, code using the Polymer library may
|
| +use <code>on-event</code>-style event listener wiring and
|
| +<code><style></code> tags that live inside of .html files.
|
| +</div>
|
| +
|
| +## HTML
|
| +
|
| +See the [Google HTML/CSS Style
|
| +guide](https://google.github.io/styleguide/htmlcssguide.xml).
|
| +
|
| +### Head
|
| +
|
| +```html
|
| +<!doctype html>
|
| +<html dir="$i18n{direction}">
|
| +<head>
|
| + <meta charset="utf-8">
|
| + <title>$i18n{myFeatureTitle}</title>
|
| + <link rel="icon" href="feature.png">
|
| + <link rel="stylesheet" href="feature.css">
|
| + <script src="feature.js"></script>
|
| +</head>
|
| +…
|
| +</html>
|
| +```
|
| +
|
| +* Specify `<!doctype html>`.
|
| +
|
| +* Set the `dir` attribute of the html element to the localized ‘textdirection’
|
| + value. This flips the page visually for RTL languages and allows
|
| + `html[dir=rtl]` selectors to work.
|
| +
|
| +* Specify the charset, UTF-8.
|
| +
|
| +* Link in image, icon and stylesheet resources.
|
| + * Do not style elements with `style="..."` attributes.
|
| +
|
| +* Include the appropriate JS scripts.
|
| + * Do not add JS to element event handlers.
|
| +
|
| +<div class="note">
|
| +Polymer event handlers like <code>on-tap</code> are allowed and often reduce the
|
| +amount of addressing (adding an ID just to wire up event handling).
|
| +</div>
|
| +
|
| +### Body
|
| +
|
| +```html
|
| +<h3>$i18n{autofillAddresses}</h3>
|
| +<div class="settings-list">
|
| + <list id="address-list"></list>
|
| + <div>
|
| + <button id="autofill-add-address">$i18n{autofillAddAddress}</button>
|
| + </div>
|
| +</div>
|
| +<if expr="chromeos">
|
| + <a href="https://www.google.com/support/chromeos/bin/answer.py?answer=142893"
|
| + target="_blank">$i18n{learnMore}</a>
|
| +</if>
|
| +```
|
| +
|
| +* Element IDs use `dash-form`
|
| + * Exception: `camelCase` is allowed in Polymer code for easier
|
| + `this.$.idName` access.
|
| +
|
| +* Localize all strings using $i18n{}
|
| +
|
| +* Use camelCase for $i18n{} keys names.
|
| +
|
| +* Add 2 space indentation in each new block.
|
| +
|
| +* Adhere to the 80-column limit.
|
| + * Indent 4 spaces when wrapping a previous line.
|
| +
|
| +* Use double-quotes instead of single-quotes for all attributes.
|
| +
|
| +* Don't close single tags
|
| + * DO: `<input type="radio">`
|
| + * DON'T: `<input type="radio" />`
|
| +
|
| +<div class="note">
|
| +All <code><custom-elements></code> and some HTML elements like
|
| +<code><iframe></code> require closing.
|
| +</div>
|
| +
|
| +* Use the `button` element instead of `<input type="button">`.
|
| +
|
| +* Do not use `<br>`; place blocking elements (`<div>`) as appropriate.
|
| +
|
| +* Do not use spacing-only divs; set the margins on the surrounding elements.
|
| +
|
| +* Only use `<table>` elements when displaying tabular data.
|
| +
|
| +* Do not use the `for` attribute of `<label>`
|
| + * If you're labelling a checkbox, put the `<input>` inside the `<label>`
|
| + * If you're labelling purely for accessibility, e.g. a `<select>`, use
|
| + `aria-labelledby`
|
| +
|
| +## CSS
|
| +
|
| +See the [Google HTML/CSS style
|
| +guide](https://google.github.io/styleguide/htmlcssguide.xml) (and again, browser
|
| +compatibility issues are less relevant for Chrome-only code).
|
| +
|
| +```css
|
| +.raw-button,
|
| +.raw-button:hover,
|
| +.raw-button:active {
|
| + --sky-color: blue;
|
| + -webkit-margin-start: 0;
|
| + background-color: rgb(253, 123, 42);
|
| + background-repeat: no-repeat;
|
| + border: none;
|
| + min-width: 0;
|
| + padding: 1px 6px;
|
| +}
|
| +```
|
| +
|
| +* Specify one selector per line.
|
| + * Exception: One rule / one line frames in a `@keyframe` (see below).
|
| +
|
| +* Opening brace on the same line as the last (or only) selector.
|
| +
|
| +* Two-space indentation for each declaration, one declaration per line,
|
| + terminated by a semicolon.
|
| +
|
| +* Use shorthand notation when possible.
|
| +
|
| +* Alphabetize properties.
|
| + * `-webkit` properties should be listed at the top, sorted alphabetically.
|
| + * `--variables` and `--mixins: {}` should be alphabetically declared when
|
| + possible.
|
| +
|
| +* Insert a space after the colon separating property and value.
|
| +
|
| +* Do not create a class for only one element; use the element ID instead.
|
| +
|
| +* When specifying length values, do not specify units for a zero value, e.g.,
|
| + `left: 0px;` becomes `left: 0;`
|
| + * Exception: 0% values in lists of percentages like `hsl(5, 0%, 90%)` or
|
| + within @keyframe directives, e.g:
|
| +```css
|
| +@keyframe animation-name {
|
| + 0% { /* beginning of animation */ }
|
| + 100% { /* end of animation */ }
|
| +}
|
| +```
|
| +
|
| +* Use single quotes instead of double quotes for all strings.
|
| +
|
| +* Don't use quotes around `url()`s unless needed (i.e. a `data:` URI).
|
| +
|
| +* Class names use `dash-form`.
|
| +
|
| +* If time lengths are less than 1 second, use millisecond granularity.
|
| + * DO: `transition: height 200ms;`
|
| + * DON'T: `transition: height 0.2s;`
|
| +
|
| +* Use two colons when addressing a pseudo-element (i.e. `::after`, `::before`,
|
| + `::-webkit-scrollbar`).
|
| +
|
| +* Use scalable `font-size` units like `%` or `em` to respect users' default font
|
| + size
|
| +
|
| +* Use `*-top/bottom` instead of `-webkit-*-before/after`
|
| + * `-top/bottom` are easier to understand (`before/after` is confusingly
|
| + similar to `start/end`)
|
| + * `-webkit-*-before/after` has far less advantage than `-webkit-*-start/end`
|
| +
|
| +### Color
|
| +
|
| +* When possible, use named colors (i.e. `white`, `black`) to enhance
|
| + readability.
|
| +
|
| +* Prefer `rgb()` or `rgba()` with decimal values instead of hex notation
|
| + (`#rrggbb`) because alpha can be more easily added.
|
| + * Exception: shades of gray (i.e. `#333`)
|
| +
|
| +* If the hex value is `#rrggbb`, use the shorthand notation `#rgb`.
|
| +
|
| +### URLs
|
| +
|
| +* Don't embed data URIs in source files. Instead, use grit's flattening.
|
| +
|
| +```css
|
| +background-image: url(../path/to/image.svg);
|
| +```
|
| +
|
| +The contents of file.png are base64-encoded and the `url()` is replaced with
|
| +
|
| +```css
|
| +background-image: url(data:image/xml+svg;base64,...);
|
| +```
|
| +
|
| +if `flattenhtml="true"` is specified in your .grd file.
|
| +
|
| +### RTL
|
| +
|
| +```css
|
| +.suboption {
|
| + -webkit-margin-start: 16px;
|
| +}
|
| +
|
| +#save-button {
|
| + color: #fff;
|
| + left: 10px;
|
| +}
|
| +
|
| +html[dir='rtl'] #save-button {
|
| + right: 10px;
|
| +}
|
| +```
|
| +
|
| +Use RTL-friendly versions of things like `margin` or `padding` where possible:
|
| +
|
| +* `margin-left` -> `-webkit-margin-start`
|
| +* `padding-right` -> `-webkit-padding-end`
|
| +* `text-align: left` -> `text-align: start`
|
| +* `text-align: right` -> `text-align: end`
|
| +* set both `left` for `[dir='ltr']` and `right` for `[dir='rtl']`
|
| +
|
| +For properties that don't have an RTL-friendly alternatives, use
|
| +`html[dir='rtl']` as a prefix in your selectors.
|
| +
|
| +## JavaScript
|
| +
|
| +### Style
|
| +
|
| +See the [Google JavaScript Style
|
| +Guide](https://google.github.io/styleguide/javascriptguide.xml).
|
| +
|
| +* Use `$('element-id')` instead of `document.getElementById`
|
| +
|
| +* Use single-quotes instead of double-quotes for all strings.
|
| + * `clang-format` now handles this automatically.
|
| +
|
| +* Omit curly braces for single-line if statements.
|
| +
|
| +* Use ES5 getters and setters
|
| + * Use `@type` (instead of `@return` or `@param`) for JSDoc annotations on
|
| + getters/setters
|
| +
|
| +* See [Annotating JavaScript for the Closure
|
| + Compiler](https://developers.google.com/closure/compiler/docs/js-for-compiler)
|
| + for @ directives
|
| +
|
| +* Prefer `event.preventDefault()` to `return false` from event handlers
|
| +
|
| +### Closure compiler
|
| +
|
| +* Use the [closure
|
| + compiler](https://chromium.googlesource.com/chromium/src/+/master/docs/closure_compilation.md)
|
| + to identify JS type errors and enforce correct JSDoc annotations.
|
| +
|
| +* Add a `compiled_resources2.gyp` file to any new web UI code directory.
|
| +
|
| +* Ensure that your `compiled_resources2.gyp` file is included in
|
| + `third_party/closure_compiler/compiled_resources2.gyp` (or somewhere in its
|
| + include hierarchy) so that your code is typechecked in an automated way.
|
| +
|
| +* Type Polymer elements by appending 'Element' to the element name, e.g.
|
| + `/** @type {IronIconElement} */`
|
| +
|
| +* Use explicit nullability in JSDoc type information
|
| + * Rather than `@type {Object}` use:
|
| + * `{!Object}` for only Object
|
| + * `{!Object|undefined}` for an Object that may be undefined
|
| + * `{?Object}` for Object that may be null
|
| + * Do the same for typedefs and Array (or any other nullable type)
|
| +
|
| +* Don't add a `.` after template types
|
| + * DO: `Array<number>`
|
| + * DON'T: `Array.<number>`
|
| +
|
| +* Don't specify string in template object types. That's the only type of key
|
| + `Object` can possibly have.
|
| + * DO: `Object<T>`
|
| + * DON'T: `Object<string, T>`
|
| +
|
| +### Events
|
| +
|
| +* Use Polymer's `on-tap` for click events instead of `on-click`
|
| + * `on-tap` handlers should use `stopPropagation()` to prevent parents from
|
| + handling the event where appropriate.
|
| +
|
| +<div class="note">
|
| +Calling <code>stopPropagation()</code> from an <code>on-tap</code> handler will
|
| +not prevent on-click event handlers, so make sure that <i>on-tap</i> is used
|
| +consistently throughout the page.
|
| +</div>
|
| +
|
| +## Polymer
|
| +
|
| +Also see the [Google Polymer Style Guide](http://go/polymer-style).
|
| +
|
| +* Use a consistent ordering in the “prototype” object passed to `Polymer()`:
|
| + * `is`
|
| + * `behaviors`
|
| + * `properties` (public, then private)
|
| + * `hostAttributes`
|
| + * `listeners`, `observers`
|
| + * `created`, `ready`, `attached`, `detached`
|
| + * public methods
|
| + * event handlers, computed functions, and private methods
|
| +
|
| +* Use camelCase for element IDs to simplify local DOM accessors (i.e.
|
| + `this.$.camelCase` instead of `this.$[‘dash-case’]`).
|
| +
|
| +* Use `this.foo` instead of `newFoo` arguments in observers when possible.
|
| + This makes changing the type of `this.foo` easier (as the `@type` is
|
| + duplicated in less places, i.e. `@param`).
|
| +
|
| +```js
|
| +properties: {
|
| + foo: {type: Number, observer: 'fooChanged_'}
|
| +},
|
| +
|
| +/** @private */
|
| +fooChanged_: function() {
|
| + this.bar = this.derive(this.foo);
|
| +},
|
| +```
|
| +
|
| +## Grit processing
|
| +
|
| +Grit is a tool that runs at compile time to pack resources together into
|
| +Chromium.
|
| +
|
| +### Preprocessing
|
| +
|
| +Grit can be used to selectively include or exclude code at compile-time in web
|
| +code. Preprocessing is be enabled by adding the `preprocess="true"` attribute
|
| +inside of a `.grd` file on `<structure>` and `<include>` nodes.
|
| +
|
| +<div class="note">
|
| +These preprocesor statements can live in places that surprise linters or
|
| +formatters (for example: running clang-format on a .js file with an <if>
|
| +in it). Generally, putting these language-invalid features inside of comments
|
| +helps alleviate problems with unexpected input.
|
| +</div>
|
| +
|
| +`<if>` tags allow conditional logic by evaluating an expression in a
|
| +compile-time environment of grit variables. These allow conditionally include
|
| +or excluding code.
|
| +
|
| +Example:
|
| +```js
|
| +function isWindows() {
|
| + // <if expr="win">
|
| + return true;
|
| + // </if>
|
| + return false;
|
| +}
|
| +```
|
| +
|
| +`<include src="[path]">` reads the file at `path` and replaces the `<include>`
|
| +tag with the file contents of `[path]`.
|
| +
|
| +Don't use `</include>` to close these tags; they're not needed nor supported.
|
| +
|
| +<div class="note">
|
| +Using <code><include></code> simply pastes the entire contents of a file,
|
| +which can lead to duplication. If you simply want to ensure some code is loaded
|
| +(and usually you do), you should use HTML Imports instead.
|
| +</div>
|
| +
|
| +Grit can read and inline resources when enabled via `flattenhtml="true"`.
|
| +
|
| +<div class="note">
|
| +The implementation of flattening does HTML parsing and URL detection via regular
|
| +expresions and is not guaranteed to work in all cases.
|
| +</div>
|
| +
|
| +Example:
|
| +
|
| +```css
|
| +.spinner {
|
| + background: url(../relative/file/path/to/spinner.svg);
|
| +}
|
| +```
|
| +
|
| +Is transformed to:
|
| +
|
| +```css
|
| +.spinner {
|
| + background: url(data:image/svg+xml;... base64-encoded content ...);
|
| +}
|
| +```
|
| +
|
| +A minification tool can be specified to Grit (like Closure compiler) to
|
| +transform the code before it's packed into a bundle.
|
|
|