From 025de3918e1fdb07b8e471ed5ff6e23ea57f1c4f Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Thu, 18 May 2017 15:23:40 +0100 Subject: [PATCH] Linting rules and examples of bad/good code with lint rules (#2) Explain linting rules and provide bad/good code examples Added sass-lint yaml file linting rules (#2) --- config/.sass-lint.yml | 355 +++++++++++++++++++++++++++++++++++ docs/coding-standards/css.md | 236 ++++++++++++++++++++++- 2 files changed, 586 insertions(+), 5 deletions(-) create mode 100644 config/.sass-lint.yml diff --git a/config/.sass-lint.yml b/config/.sass-lint.yml new file mode 100644 index 0000000000..1f23160145 --- /dev/null +++ b/config/.sass-lint.yml @@ -0,0 +1,355 @@ +# Not yet supported by sass-lint: +# ChainedClasses, DisableLinterReason, ElsePlacement, PropertyCount +# PseudoElement, SelectorDepth, SpaceAroundOperator, TrailingWhitespace +# UnnecessaryParentReference, Compass::* +# +# The following settings/values are unsupported by sass-lint: +# Linter Comment, option "style" +# Linter Indentation, option "allow_non_nested_indentation" +# Linter Indentation, option "character" +# Linter NestingDepth, option "ignore_parent_selectors" +# Linter SpaceBeforeBrace, option "allow_single_line_padding" + +files: + include: '**/*.s+(a|c)ss' +options: + formatter: stylish + merge-default-rules: true +rules: + + # Rule bem-depth will enforce how many elements a BEM selector can contain. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/bem-depth.md + bem-depth: 0 + + # Rule border-zero will enforce whether one should use 0 or none when specifying a zero border value + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/border-zero.md + border-zero: 1 + + # Rule brace-style will enforce the use of the chosen brace style. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/brace-style.md + brace-style: + - 1 + - allow-single-line: false + + # Rule class-name-format will enforce a convention for class names. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/class-name-format.md#example-7 + # will allow .block {}, .block__element{}, .block--modifier {} + class-name-format: + - 1 + - convention: hyphenatedbem + + # Rule clean-import-paths will enforce whether or not @import paths should have leading underscores and/or filename extensions. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/clean-import-paths.md + clean-import-paths: + - 1 + - filename-extension: false + leading-underscore: false + + # TODO: empty-args + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/empty-args.md + + # Rule empty-line-between-blocks will enforce whether or not nested blocks should include a space between the last non-comment declaration or not. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/empty-line-between-blocks.md + empty-line-between-blocks: + - 1 + - ignore-single-line-rulesets: true + + # Rule extends-before-declarations will enforce that extends should be written before declarations in a ruleset. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/extends-before-declarations.md + extends-before-declarations: 0 + + # Rule extends-before-mixins will enforce that extends should be written before mixins in a ruleset. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/extends-before-mixins.md + extends-before-mixins: 0 + + # Rule final-newline will enforce whether or not files should end with a newline. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/final-newline.md + final-newline: + - 1 + - include: true + + # Rule force-attribute-nesting will enforce the nesting of attributes + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/force-attribute-nesting.md + force-attribute-nesting: + - 0 + + # Rule force-element-nesting will enforce the nesting of elements + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/force-element-nesting.md + force-element-nesting: + - 0 + + # Rule force-pseudo-nesting will enforce the nesting of pseudo elements/classes. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/force-pseudo-nesting.md + force-pseudo-nesting: + - 0 + + # Rule function-name-format will enforce a convention for function names. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/function-name-format.md + function-name-format: + - 1 + - allow-leading-underscore: true + convention: hyphenatedlowercase + + # Rule hex-length will enforce the length of hexadecimal values + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/hex-length.md + hex-length: + - 1 + - style: long + + # Rule hex-notation will enforce the case of hexadecimal values + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/hex-notation.md + hex-notation: + - 1 + - style: lowercase + + # Rule id-name-format will enforce a convention for ids. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/id-name-format.md + id-name-format: + - 1 + - convention: hyphenatedlowercase + + # Rule indentation will enforce an indentation size (tabs and spaces) and it will also ensure that tabs and spaces are not mixed. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/indentation.md + indentation: + - 1 + - size: 2 + + # Rule leading-zero will enforce whether or not decimal numbers should include a leading zero. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/leading-zero.md + leading-zero: + - 1 + - include: false + + # Rule mixin-name-format will enforce a convention for mixin names. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/mixin-name-format.md + mixin-name-format: + - 1 + - allow-leading-underscore: true + convention: hyphenatedlowercase + + # Rule mixins-before-declarations will enforce that mixins should be written before declarations in a ruleset. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/mixins-before-declarations.md + mixins-before-declarations: 0 + + # Rule nesting-depth will enforce how deeply a selector can be nested. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/nesting-depth.md + nesting-depth: + - 1 + - max-depth: 3 + + # TODO: no-attribute-selectors + # Rule no-attribute-selectors will warn against the use of attribute selectors. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-attribute-selectors.md + + # TODO: no-colour-hex + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-color-hex.md + + # Rule no-color-keywords will enforce the use of hexadecimal color values rather than literals. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-color-keywords.md + no-color-keywords: 1 + + # Rule no-color-literals will disallow the use of color literals and basic color functions in any declarations other than variables or maps/lists. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-color-literals.md + no-color-literals: 1 + + # TODO: no-combniators + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-combinators.md + + # Rule no-css-comments will enforce the use of Sass single-line comments and disallow CSS comments. Bang comments (/*! */, will be printed even in minified mode) are still allowed. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-css-comments.md + no-css-comments: 1 + + # Rule no-debug will enforce that @debug statements are not allowed to be used. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-debug.md + no-debug: 1 + + # TODO: no-disallowed-properties + # Rule no-disallowed-properties will warn against the use of certain properties. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-disallowed-properties.md + + # Rule no-duplicate-properties will enforce that duplicate properties are not allowed within the same block. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-duplicate-properties.md + no-duplicate-properties: 1 + + # Rule no-empty-rulesets will enforce that rulesets are not empty. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-empty-rulesets.md + no-empty-rulesets: 1 + + # Rule no-extends will enforce that @extend is not allowed to be used. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-extends.md + no-extends: 0 + + # Rule no-ids will enforce that ID selectors are not allowed to be used. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-ids.md + no-ids: 1 + + # Rule no-important will enforce that important declarations are not allowed to be used. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-important.md + no-important: 0 + + # Rule no-invalid-hex will enforce that only valid of hexadecimal values are written. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-invalid-hex.md + no-invalid-hex: 1 + + # Rule no-mergeable-selectors will enforce that selectors aren't repeated and that their properties are merged. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-mergeable-selectors.md + no-mergeable-selectors: 0 + + # Rule no-misspelled-properties will enforce the correct spelling of CSS properties and prevent the use of unknown CSS properties. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-misspelled-properties.md + no-misspelled-properties: 1 + + # Rule no-qualifying-elements will enforce that selectors are not allowed to have qualifying elements. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-qualifying-elements.md + no-qualifying-elements: + - 1 + - allow-element-with-attribute: true + allow-element-with-class: false + allow-element-with-id: false + + # TODO: no-trailing-whitespace + # Rule no-trailing-whitespace will enforce that trailing whitespace is not allowed. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-trailing-whitespace.md + + # Rule no-trailing-zero will enforce that trailing zeros are not allowed. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-trailing-zero.md + no-trailing-zero: 1 + + # Rule no-transition-all will enforce whether the keyword all can be used with the transition or transition-property property. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-transition-all.md + no-transition-all: 1 + + # TODO: no-universal-selectors + # Rule no-universal-selectors will warn against the use of * (universal) selectors. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-universal-selectors.md + + # Rule no-url-protocols will enforce that protocols and domains are not used within urls. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-url-protocols.md + no-url-protocols: 1 + + # Rule no-vendor-prefixes will enforce that vendor prefixes are not allowed to be used. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/no-vendor-prefixes.md + no-vendor-prefixes: 0 + + # Rule placeholder-in-extend will enforce whether extends should only include placeholder selectors. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/placeholder-in-extend.md + placeholder-in-extend: 1 + + # Rule placeholder-name-format will enforce a convention for placeholder names. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/placeholder-name-format.md + placeholder-name-format: + - 1 + - convention: hyphenatedlowercase + + # Rule property-sort-order will enforce the order in which declarations are written. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/property-sort-order.md + property-sort-order: + - 0 + - order: 'smacss' + + # Rule property-units will disallow the use of units not specified in global or per-property. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/property-units.md + property-units: + - 1 + - global: [ + 'cm', + 'em', + 'pt', + 'px', + 'rem', + 'vh' + ] + + # TODO: pseudo-element + # Rule pseudo-element will enforce that: + # - pseudo-elements must start with double colons + # - pseudo-classes must start with single colon + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/pseudo-element.md + + # Rule quotes will enforce whether single quotes ('') or double quotes ("") should be used for all strings. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/quotes.md + quotes: + - 1 + - style: double + + # Rule shorthand-values will enforce that values in their shorthand form are as concise as specified. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/shorthand-values.md + shorthand-values: + - 0 + - allowed-shorthands: + - 1 + - 2 + - 3 + + # Rule single-line-per-selector will enforce whether selectors should be placed on a new line. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/single-line-per-selector.md + single-line-per-selector: 1 + + # Rule space-after-bang will enforce whether or not a space should be included after a bang (!). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-after-bang.md + space-after-bang: + - 1 + - include: false + + # Rule space-after-colon will enforce whether or not a space should be included after a colon (:). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-after-colon.md + space-after-colon: + - 1 + - include: true + + # Rule space-after-comma will enforce whether or not a space should be included after a comma (,). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-after-comma.md + space-after-comma: + - 1 + - include: true + + # Rule space-around-operator will enforce whether or not a single space should be included before and after the following operators: +, -, /, *, %, <, > ==, !=, <= and >=. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-around-operator.md + space-around-operator: + - 1 + - include: true + + # Rule space-before-bang will enforce whether or not a space should be included before a bang (!). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-before-bang.md + space-before-bang: + - 1 + - include: true + + # Rule space-before-brace will enforce whether or not a space should be included before a brace ({). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-before-brace.md + space-before-brace: + - 1 + - include: true + + # Rule space-before-colon will enforce whether or not a space should be included before a colon (:). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-before-colon.md + space-before-colon: 1 + + # Rule space-between-parens will enforce whether or not a space should be included before the first item and after the last item inside parenthesis (()). + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/space-between-parens.md + space-between-parens: 0 + + # Rule trailing-semicolon will enforce whether the last declaration in a block should include a semicolon (;) or not. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/trailing-semicolon.md + trailing-semicolon: 1 + + # Rule url-quotes will enforce that URLs are wrapped in quotes. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/url-quotes.md + url-quotes: 1 + + # Rule variable-for-property will enforce the use of variables for the values of specified properties. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/variable-for-property.md + variable-for-property: + - 0 + - properties: [] + + # Rule variable-name-format will enforce a convention for variable names. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/variable-name-format.md + variable-name-format: + - 1 + - allow-leading-underscore: true + convention: hyphenatedlowercase + + # Rule zero-unit will enforce whether or not values of 0 used for length should be unitless. + # https://github.com/sasstools/sass-lint/blob/master/docs/rules/zero-unit.md + zero-unit: 1 diff --git a/docs/coding-standards/css.md b/docs/coding-standards/css.md index d3bd0f6a8c..a00ceaf470 100644 --- a/docs/coding-standards/css.md +++ b/docs/coding-standards/css.md @@ -21,7 +21,7 @@ Objects, components, utilites and JS hooks use a prefix: Utility u- .govuk-u-visually-hidden JS hooks js- .govuk-js-enabled - + **Why** To easily identify components, objects and utilties and to know what the implications of changing each one will be. @@ -47,12 +47,12 @@ It can be reused and is not tied to any specific piece of UI. ## JS hooks js- -Use a prefix for all JavaScript hooks. +Use a prefix for all JavaScript hooks. # BEM -BEM – meaning block, element, modifier – is a front-end naming methodology. +BEM – meaning block, element, modifier – is a front-end naming methodology. BEM tells developers how classes relate to each other. @@ -65,11 +65,11 @@ The naming convention follows this pattern: .govuk-c-card // Block - the root of a component .govuk-c-card__body // Element - a part of the block .govuk-c-card--active // Modifier - a variant of the block - + The reason for double hyphens and underscores after the block name, is so that the block can be hyphen delimited, for example: .govuk-c-phase-banner - + BEM stands for `Block__Element--Modifier`, not `Block__Element__Element--Modifier`. Avoid multiple element level naming. @@ -79,3 +79,229 @@ Avoid multiple element level naming. * [Harry Roberts - BEMIT: Taking the BEM Naming Convention a Step Further](https://csswizardry.com/2015/08/bemit-taking-the-bem-naming-convention-a-step-further/) * [CSS-Tricks - BEM - 101](https://css-tricks.com/bem-101/) + +# Linting + +To ensure code quality and consistency in our Sass files we check that certain style rules are followed using a project [YAML file](../config/.sass-lint.yml) +As we're using node-sass parser to parse our scss files, the package of choice is [sass-lint](https://github.com/sasstools/sass-lint). + +## Running the lint task +You can run the linter in [gulp](https://www.npmjs.com/package/gulp-sass-lint) or check linting directly in [Sublime Text](https://github.com/skovhus/SublimeLinter-contrib-sass-lint), [Atom](https://atom.io/packages/linter-sass-lint) or other [IDE's](https://github.com/sasstools/sass-lint#ide-integration) + +## Linting rules + +We use the following rules when linting files: + +### Use soft tabs (2 spaces) +### Write each property in own line + +Bad: + +`.selector {border: 0; padding: 0;}` + +Good: +``` +.selector { + border: 0; + padding: 0; +} +``` + +### Use variables for colours not HEX values in selectors rules, unless in variables. + +Bad: +``` +.selector { + color: #005ea5; +} +``` +Good: +.selector { + color: $govuk-blue; +} + +### Colours defined as variables should be in lowercase and in full length + +Bad: +``` +$white: #FFF; +``` +Good: +``` +$white: #ffffff; +``` + +### Use `border: 0` not `none` to denote no border +### Avoid using ID selectors +### Separate rule, function, and mixin declarations with empty lines + +Bad: +``` +p { + margin: 0; + em { + ... + } +} +a { + ... +} +``` + +Good: +``` +p { + margin: 0; + + em { + ... + } +} + +a { + ... +} +``` + +### Use no more than 3 levels of nesting +### Don't use extends, use mixins +### Allow max 3-rule property shorthand if possible + +Bad: +``` +margin: 1px 2px 3px 2px; +``` +Good: +``` +margin: 1px 2px 3px; +``` +### Files should always have a final newline +### Commas in lists should be followed by a space + +### The basenames of `@import`ed SCSS partials should not begin with an underscore and should not include the filename extension + +Bad: +``` +@import '_foo.scss'; +@import '_bar/foo.scss'; +``` +Good: +``` +@import 'foo'; +@import 'bar/foo'; +``` + +### Properties should be formatted with a single space separating the colon from the property's value + +Bad: +``` +.foo { + content:bar'; +} +``` +Good: +``` +.foo { + content: 'bar'; +} +``` + +### Operators should be formatted with a single space on both sides of an infix operator. These include `+, -, *, /, %, ==, !=, >, >=, <,` and `<=` + +Bad: +``` +.selector { + margin: 5px+15px; +} + +$foo: 1; +$bar: 3; + +.selector { + margin: $foo+$bar+'px'; +} + +$foo: 1+1; +$bar: 2-1; + +@if $foo==$bar { + $baz: 1; +} + +@if ($foo!=$bar) { + $baz: 1; +} +``` +Good: +``` +.selector { + margin: 5px + 15px; +} + +$foo: 1; +$bar: 3; + +.selector { + margin: $foo + $bar + 'px'; +} + +$foo: 1 + 1; +$bar: 2 - 1; + +@if $foo == $bar { + $baz: 1; +} + +@if ($foo != $bar) { + $baz: 1; +} +``` + +### Functions, mixins, variables, and placeholders should be declared with all lowercase letters and hyphens instead of underscores + +Bad: +``` +@mixin FONT_STACK() { + content: ''; +} +``` +Good: +``` +@mixin font-stack() { + content: ''; +} +``` + +### Omit length units on zero values + +Bad: +``` +.selector { + margin: 0px; +} +``` +Good: +``` +.selector { + margin: 0; +} +``` + +### Property values and variable declarations should always end with a semicolon +### Don't write trailing zeros for numeric values with a decimal point + +``` +.selector { + font-size: 0.5em; +} +``` +Good: +``` +.selector { + font-size: 0.5em; +} +``` + +### Remove trailing whitespace + +More write up on [supported rules](https://github.com/sasstools/sass-lint/tree/master/docs/rules).