Below is a list of linters supported by scss-lint
, ordered alphabetically.
- BangFormat
- BemDepth
- BorderZero
- ChainedClasses
- ColorKeyword
- ColorVariable
- Comment
- Compass Linters
- DebugStatement
- DeclarationOrder
- DisableLinterReason
- DuplicateProperty
- ElsePlacement
- EmptyLineBetweenBlocks
- EmptyRule
- ExtendDirective
- FinalNewline
- HexLength
- HexNotation
- HexValidation
- IdSelector
- ImportantRule
- ImportPath
- Indentation
- LeadingZero
- LengthVariable
- MergeableSelector
- NameFormat
- NestingDepth
- PlaceholderInExtend
- PrivateNamingConvention
- PropertyCount
- PropertySortOrder
- PropertySpelling
- PropertyUnits
- PseudoElement
- QualifyingElement
- SelectorDepth
- SelectorFormat
- Shorthand
- SingleLinePerProperty
- SingleLinePerSelector
- SpaceAfterComma
- SpaceAfterPropertyColon
- SpaceAfterPropertyName
- SpaceAfterVariableColon
- SpaceAfterVariableName
- SpaceAroundOperator
- SpaceBeforeBrace
- SpaceBetweenParens
- StringQuotes
- TrailingSemicolon
- TrailingWhitespace
- TrailingZero
- TransitionAll
- UnnecessaryMantissa
- UnnecessaryParentReference
- UrlFormat
- UrlQuotes
- VariableForProperty
- VendorPrefix
- ZeroUnit
Reports when you use improper spacing around !
(the "bang") in !default
, !global
, !important
, and !optional
flags.
You can prefer a single space or no space both before and after the !
.
Bad
color: #000!important;
Good
color: #000 !important;
Configuration Option | Description |
---|---|
space_before_bang |
Whether a space should be present before the ! , as in color: #000 !important; (default true) |
space_after_bang |
Whether a space should be present after the ! , as in color: #000 ! important; (default false) |
Disabled by default
Reports when a BEM selector contains more elements than a configurable maximum number.
Bad
.block__element__subelement {
...
}
Good
.block__element {
...
}
Configuration Option | Description |
---|---|
max_elements |
Maximum number of elements allowed in a BEM selector (default 1) |
Prefer the terser border: 0
over border: none
.
You can specify preferring border: none
over border: 0
by setting the
convention
option.
Configuration Option | Description |
---|---|
convention |
Whether to prefer 0 (zero) or none (none) (default zero) |
Disabled by default
Reports when you define a rule set using a selector with chained classes (a.k.a. adjoining classes).
Bad
.foo {
padding: 5px;
}
.bar {
margin: 5px;
}
.foo.bar {
display: block;
}
Good: write chained classes as new class
.foo {
padding: 5px;
}
.bar {
margin: 5px;
}
.new-class {
display: block;
}
Prefer hexadecimal color codes over color keywords.
Bad: color keyword
color: green;
Good: hexadecimal color
color: #0f0;
Color keywords look like variables but are not variables. See the ColorVariable linter for more justification on why you should always refer to colors via variables.
Prefer color literals (keywords or hexadecimal codes) to be used only in variable declarations. They should be referred to via variables everywhere else.
Bad: literal color
p {
color: green;
}
Good: refer to color by variable name
$body-color: #0f0;
...
p {
color: $body-color;
}
Defining colors directly in properties is usually a smell. When you color your body text in a number of places, if you ever want to change the color of the text you'll have to update the explicitly defined color in a number of places, and finding all those places can be difficult if you use the same color for other elements (i.e. a simple find/replace may not always work).
A better approach is to use global variables like $color-text-body
and refer
to this variable everywhere you want to use it. This makes it easy to update
the color, as you only need change it in one place. It is also more
intention-revealing, as seeing the name $color-text-body
is more descriptive
than #333
or black
. Using color keywords can obfuscate this, as they look
like variables.
Prefer //
comments over /* ... */
.
Bad
/* This is a comment that gets rendered */
Good
// This comment never gets rendered
//
comments should be preferred as they don't get rendered in the final
generated CSS, whereas /* ... */
comments do.
Furthermore, comments should be concise, and using /* ... */
encourages multi-line comments which tend to not be concise.
If you want to allow multi-line comments containing certain text, such as
copyright notices, set the allowed
option to a regular expression. This will
allow multi-line comments that match the regular expression.
Configuration Option | Description |
---|---|
allowed |
Regular expression for matching allowed comments, such as '^[/* ] Copyright' |
style |
Style of comment to enforce (silent or loud ) (default silent) |
scss-lint
includes a set of linters for codebases which use the
Compass framework.
###» Compass Linters Documentation
Reports @debug
statements (which you probably left behind accidentally).
Rule sets should be ordered as follows: @extend
declarations, @include
declarations without inner @content
, properties, @include
declarations
with inner @content
, then nested rule sets.
Bad
.fatal-error {
p {
...
}
color: #f00;
@extend %error;
@include message-box();
}
Good
.fatal-error {
@extend %error;
@include message-box();
color: #f00;
p {
...
}
}
The @extend
statement functionally acts like an inheritance mechanism,
which means the properties defined by the placeholder being extended are
rendered before the rest of the properties in the rule set.
Thus, declaring the @extend
at the top of the rule set reminds the
developer of this behavior.
Placing @include
declarations without inner @content
before properties
serves to group them with @extend
declarations and provides the opportunity
to overwrite them later in the rule set.
@include
s with inner @content
often involve @media
rules that rely on
the cascade or nested rule sets, which justifies their inclusion after
regular properties.
Mixin @content
and nested rule sets are also linted for declaration order.
Disabled by default
scss-lint:disable
control comments should be preceded by a comment explaining
why these linters are being disabled for this file.
Bad
// scss-lint:disable BorderZero
p {
border: none;
}
Good
// We really prefer `border: none` in this file, for reasons.
// scss-lint:disable BorderZero
p {
border: none;
}
Reports when you define the same property twice in a single rule set.
Bad
h1 {
margin: 10px;
text-transform: uppercase;
margin: 0; // Second declaration
}
Having duplicate properties is usually just an error. However, they can be used
as a technique for dealing with varying levels of browser support for CSS
properties. In the example below, some browsers might not support the rgba
function, so the intention is to fall back to the color #fff
.
.box {
background: #fff;
background: rgba(255, 255, 255, .5);
}
In this situation, using duplicate properties is acceptable, but you will have
to configure DuplicateProperty with the ignore_consecutive
option, so that it
won't consider such cases to be lint. ignore_consecutive
can be set to true
,
false
(default), or a list of property names to be allowed. For example, to
ignore consecutive background
and transition
properties, as above, you can
configure DuplicateProperty with:
DuplicateProperty:
ignore_consecutive:
- background
- transition
Configuration Option | Description |
---|---|
ignore_consecutive |
Whether to ignore consecutive duplicate properties (default false), or a whitelist. |
Place @else
statements on the same line as the preceding curly brace.
Bad
@if {
...
}
@else {
...
}
Good
@if {
...
} @else {
...
}
This will ignore single line @if
/@else
blocks, so you can write:
@if { ... } @else { ... }
You can prefer to enforce having @else
on its own line by setting the style
configuration option to new_line
.
Configuration Option | Description |
---|---|
style |
same_line or new_line (default same_line ) |
Separate rule, function, and mixin declarations with empty lines.
Bad: no lines separating blocks
p {
margin: 0;
em {
...
}
}
a {
...
}
Good: lines separating blocks
p {
margin: 0;
em {
...
}
}
a {
...
}
By default, this will ignore single line blocks, so you can write:
.icon-chevron-up { &:before { content: "\e030"; } }
.icon-chevron-down { &:before { content: "\e031"; } }
.icon-chevron-left { &:before { content: "\e032"; } }
.icon-chevron-right { &:before { content: "\e033"; } }
Configuration Option | Description |
---|---|
ignore_single_line_blocks |
Don't enforce for single-line blocks (default true) |
Reports when you have an empty rule set.
.cat {
}
Disabled by default
Reports when you have an @extend
directive.
p {
@extend %placeholder;
}
If you want to restrict the @extend
directive to only use placeholders, see
the PlaceholderInExtend linter instead.
Files should always have a final newline. This results in better diffs when adding lines to the file, since SCM systems such as git won't think that you touched the last line.
You can customize whether or not a final newline exists with the present
option.
Configuration Option | Description |
---|---|
present |
Whether a final newline should be present (default true) |
You can specify whether you prefer shorthand or long-form hexadecimal
colors by setting the style option to short
or long
, respectively.
short
color: #f2e;
long
color: #ff22ee;
Configuration Option | Description |
---|---|
style |
Prefer short or long (default short) |
Checks if hexadecimal colors are written in lowercase. You can specify which
case with the style
option.
Configuration Option | Description |
---|---|
style |
Prefer lowercase or uppercase (default lowercase) |
Ensure hexadecimal colors are valid (either three or six digits).
Bad
p {
background: #ab; // Clearly a typo
}
Good
p {
background: #abc;
}
Avoid using ID selectors.
Bad: highly-specific styling for a single element via ID
#submit-button {
...
}
Good: reusable class
.submit-button {
...
}
While the CSS specification allows for multiple elements with the same ID to appear in a single document, in practice this is a smell. ID selectors should never be used for the purposes of styling an element, as it leads to overly specific styles that aren't easily shared with other elements.
Avoid using !important
in properties. It is usually indicative of a
misunderstanding of CSS
specificity
and can lead to brittle code.
Bad
p {
color: #f00 !important;
}
Good
p {
color: #f00;
}
The basenames of @import
ed SCSS partials should not begin with an underscore
and should not include the filename extension.
Bad
@import "foo/_bar.scss";
@import "_bar.scss";
@import "_bar";
@import "bar.scss";
Good
@import "foo/bar";
@import "bar";
You can configure this linter to instead ensure that you do include the
leading underscore or the filename extension by setting either option to
true
. Being explicit might have its place, as long as you are consistent.
@import
declarations that Sass compiles directly into CSS @import
rules
will be ignored.
Configuration Option | Description |
---|---|
leading_underscore |
false or true (default false) |
filename_extension |
false or true (default false) |
Use two spaces per indentation level.
Bad: four spaces
p {
color: #f00;
}
Good: two spaces
p {
color: #f00;
}
You can configure this linter to prefer tabs if you like.
For projects that follow BEM, you may prefer to allow arbitrary indentation for rule sets that aren't nested in order to give the visual hints of hierarchy without actually nesting selectors (which has a performance cost). For example:
.component {}
.component__image {}
.component__text {}
.component-subblock {}
.component-subblock__text {}
.component-category {}
.component-other {}
You can set allow_non_nested_indentation
to true
if this convention is
preferred.
Configuration Option | Description |
---|---|
allow_non_nested_indentation |
Whether non-nested rule sets can be arbitrarily indented (default false) |
character |
tab or space (default space) |
width |
Number of character s per indentation level (default 2) |
Don't write leading zeros for numeric values with a decimal point.
Bad: unnecessary leading zero
margin: 0.5em;
Good: no leading zero
margin: .5em;
You can configure this to prefer including leading zeros.
Configuration Option | Description |
---|---|
style |
exclude_zero or include_zero (default exclude_zero) |
Prefer length literals (numbers with units) to be used only in variable declarations. They should be referred to via variables, or calculations using variables, everywhere else.
Bad: literal length
div {
width: 100px;
}
Good: refer to length by variable name
$column-width: 100px;
...
div {
width: $column-width;
}
Most lengths in stylesheets are related to and dependant on other lengths.
By only using variables you are forced to name these lengths and relate them
to each other. This linter does not catch uses of percentages as those size
relationships are already present. It encourages calculations:
e.g -$input-height
or $input-height - $input-line-weight * 2
.
Defining length directly in properties usually leads to future magic-number detective work. For example, if you ever want to change the height of all form inputs then you'll have to update the heights and widths and margins of many things in a number of places, and finding all those places can be difficult if you use the same length for other things, or you have values that are related to other values (e.g. the height minus the border width). A simple find/ replace may not always work.
A better approach is to use global variables like $standard-input-height
and
refer to this variable everywhere you want to use it. This makes it easy to
update the color, as you only need change it in one place. It is also more
intention-revealing, as seeing the name $input-height
is more descriptive
than 40px
or 1.5em
.
Limitations
- This doesn't catch
width: $button-width + 2
where the2
is implicitly2px
. SASS is too clever here. - This doesn't flag length literals that are percentages: 1. because that
already expresses how lengths are related to each other, and 2. because
percentages are also used for non-length values. (e.g.
fade-out(black, 70%)
)
Configuration Option | Description |
---|---|
allowed_lengths |
A list of lengths (numbers with units) that aren't caught. e.g. [100vh, 100vw] |
allowed_properties |
A list of properties that can use literal lengths, e.g. [text-shadow, box-shadow] |
Reports when you define the same selector twice in a single sheet.
Bad
h1 {
margin: 10px;
}
.baz {
color: red;
}
// Second copy of h1 rule
h1 {
text-transform: uppercase;
}
Good
h1 {
margin: 10px;
text-transform: uppercase;
}
.baz {
color: red;
}
Combining duplicate selectors can result in an easier to read sheet, but occasionally the rules may be purposely duplicated to set precedence after a rule with the same CSS specificity. However, coding your stylesheets in this way makes them more difficult to comprehend, and can usually be avoided.
You can specify that rule sets which can be nested within another rule
set must be nested via the force_nesting
option, e.g.
Bad
h1 {
color: #fff;
}
h1.new {
color: #000;
}
Good
h1 {
color: #fff;
&.new {
color: #000;
}
}
Configuration Option | Description |
---|---|
force_nesting |
Ensure rule sets which can be nested are nested (default true) |
whitelist |
A list of selectors that can MergeableSelector, list those used in CSS Shims |
Functions, mixins, variables, and placeholders should be declared with all lowercase letters and hyphens instead of underscores.
Bad: uppercase characters
$myVar: 10px;
@mixin myMixin() {
...
}
Good: all lowercase with hyphens
$my-var: 10px;
@mixin my-mixin() {
...
}
The Sass parser automatically treats underscores and hyphens the same, so even if you're using a library that declares a function with an underscore, you can refer to it using the hyphenated form instead.
Depending on whether you use underscores to denote private functions within your
code, you can set the allow_leading_underscore
option (enabled by default)
which will ignore leading underscores in names if they exist, allowing
declarations like @function _private-function() { ... }
. If you want to
further enforce a private naming convention, use
PrivateNamingConvention.
Configuration Option | Description |
---|---|
allow_leading_underscore |
Whether to allow names to start with a single underscore (default true ) |
convention |
Name of convention to use (hyphenated_lowercase (default), camel_case , snake_case ), or a regex the name must match (eg: ^[a-zA-Z]+$ ) |
convention_explanation |
Custom catch-all explanation if you do not want to use the built-in explanations |
{type}_convention |
Convention to use for {type} s, where {type} is on of function , mixin , variable , or placeholder |
{type}_convention_explanation |
Custom explanation for {type} convention, where {type} is one of function , mixin , variable , or placeholder |
Avoid nesting selectors too deeply.
Bad: deeply nested
.one {
.two {
.three {
.four {
...
}
}
}
}
Good
.three:hover {
}
.three {
&:hover {
...
}
}
Overly nested rules will result in over-qualified CSS that could prove hard to maintain, output unnecessary selectors and is generally considered bad practice.
This linter will not report an error if you have selectors with a large depth of applicability. Use SelectorDepth for this purpose.
No error
.one .two .three {
...
}
Error
.one {
.two {
.three {
...
}
}
}
Configuration Option | Description |
---|---|
max_depth |
Maximum depth before reporting errors (default 3) |
ignore_parent_selectors |
Whether to report errors for parent selectors (default false) |
Always use placeholder selectors in @extend
.
Bad: extending a class
.fatal {
@extend .error;
}
Good: extending a placeholder
.fatal {
@extend %error;
}
Using a class selector with the @extend
directive usually results in more
generated CSS than when using a placeholder selector. Furthermore, Sass
specifically introduced placeholder selectors in order to be used with
@extend
.
See Mastering Sass extends and placeholders.
If you want to prevent the use of the @extend
directive entirely, see the
ExtendDirective linter.
Disabled by default
Enforces that functions, mixins, and variables that follow the private naming
convention (default to underscore-prefixed, e.g. $_foo
) are defined and used
within the same file.
Bad
$_foo: #f00;
p {
color: #00f;
}
Bad
p {
color: $_foo;
}
Bad
p {
color: $_foo;
}
$_foo: #f00;
Good
$_foo: #f00;
p {
color: $_foo;
}
Configuration Option | Description |
---|---|
prefix |
Prefix used to denote "private" (default _ ) |
Disabled by default
Limit the number of properties in a rule set.
Specifying a large number of properties in a rule set is usually an opportunity to break down the rule set into smaller more reusable components. It is also a sign that you might not be leveraging the true power of the "cascade", as you are explicitly defining a large number of properties many times.
Bad: large number of properties
.class {
color: #f00;
font: 15px arial, sans-serif;
margin: 0;
padding: 0;
}
Good: small number of properties
.class {
margin: 0;
padding: 0;
}
You can specify that the count of properties include properties in nested rule
sets via the include_nested
option. This is useful if you care about the
overall complexity of a generated rule set, rather than just each individual
set.
Configuration Option | Description |
---|---|
include_nested |
Whether to include the properties in nested rule sets in the count |
max_properties |
Maximum number of properties |
Sort properties in a strict order. By default, will require properties be
sorted in alphabetical order, as it's brain dead simple (highlight lines and
execute :sort
in vim
), and it can
benefit gzip compression.
You can also specify an explicit ordering via the order
option, which allows
you to specify an explicit array of properties representing the preferred
order, or the name of a
preset order.
If a property is not in your explicit list, it will be placed at the bottom of
the list, disregarding its order relative to other unspecified properties.
For example, to define a custom sort order, you can write:
linters:
PropertySortOrder:
order:
- display
- margin
- etc...
Or you can use a preset order by writing:
linters:
PropertySortOrder:
order: concentric
You can enforce that "groups" of properties be visually separated by setting
the separate_groups
option to true
. When specifying a custom order, you
can indicate that you want two groups of properties to be visually separate
by inserting an empty item, e.g.
linters:
PropertySortOrder:
order:
- display
- position
- # This empty element signals a visual separation
- margin
- padding
separate_groups: true
This would result in the following separation being enforced:
p {
display: block;
position: absolute;
margin: 0;
padding: 0;
}
Note that separate_groups
is only enforced if a custom order is specified via
the order
option. Also note that if ignore_unspecified
is true
then
properties which are "ignored" are considered as visual separators.
If you need to write vendor-prefixed properties, the linter will allow you to order the vendor-prefixed properties before the standard CSS property they apply to. For example:
border: 0;
-moz-border-radius: 3px;
-o-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
color: #ccc;
margin: 5px;
In this case, this is usually avoided by using mixins from a framework like Compass or Bourbon so vendor-specific properties rarely need to be explicitly written by hand.
If you are specifying an explicit order for properties, note that vendor-prefixed properties will still be ordered based on the example above (i.e. you only need to specify normal properties in your list).
Configuration Option | Description |
---|---|
ignore_unspecified |
Whether to ignore properties that are not explicitly specified in order (default false) |
min_properties |
Minimum number of sortable properties (i.e. properties which are defined by the given order ) present in the rule set before linting takes place (default 2) |
order |
Array of properties, or the name of a preset order (default is nil , resulting in alphabetical ordering) |
separate_groups |
Whether gaps between groups of properties should be enforced. |
Reports when you use an unknown or disabled CSS property (ignoring vendor-prefixed properties).
diplay: none; // "display" is spelled incorrectly
Since the list of available CSS properties is constantly changing, it's
possible that you might get some false positives here, especially if you're
using experimental CSS features. If that's the case, you can add additional
properties to the whitelist by adding the following to your .scss-lint.yml
configuration:
linters:
PropertySpelling:
extra_properties:
- some-experimental-property
- another-experimental-property
disabled_properties:
- some-existing-property
- another-existing-property
If you're sure the property in question is valid, submit a request to add it to the default whitelist.
Configuration Option | Description |
---|---|
extra_properties |
List of extra properties to allow |
disabled_properties |
List of existing properties to deny |
Configure which units are allowed for property values.
By default a value may have any kind of unit. You can adjust which units are
allowed globally by setting the global
option. Alternately, you can specify a
list of units for a single property by adding it to the properties
option,
e.g.
PropertyUnits:
global: ['em', 'rem', '%'] # Allow relative units globally
properties:
border: ['px'] # Only pixels
line-height: [] # No units allowed
margin: ['em', 'rem']
With the above configuration, the following issues would be reported:
p {
border: 1rem solid blue; // rem not in `border` list
line-height: 55px; // px not in `line-height` list
padding: 10px; // px not in `global` list
margin: 10%; // % not in `margin` list
}
Configuration Option | Description |
---|---|
global |
List of allowed units (by default any unit is allowed) |
properties |
Hash of property names and their list of allowed units. (empty by default) |
Pseudo-elements, like ::before
, and ::first-letter
, should be declared with
two colons. Pseudo-classes, like :hover
and :first-child
, should be
declared with one colon.
If you're sure the pseudo-element in question is valid, submit a request to add it to the default whitelist.
Bad: wrong colons
p:before {
content: '>'
}
p::hover {
color: red;
}
Good: correct colons
p::before {
content: '>'
}
p:hover {
color: red;
}
Avoid qualifying elements in selectors (also known as "tag-qualifying").
Bad: qualifying elements
div#thing {
...
}
ul.list {
...
}
ul li.item {
...
}
a[href="place"] {
...
}
Good
#thing {
...
}
.list {
...
}
ul .item {
...
}
[href="place"] {
...
}
Since IDs are unique, they will not apply to multiple elements, so there is no good reason to qualify an ID selector with an element.
In most cases, qualifying a class or attribute selector with an element adds unnecessary or undesirable specificity. Often the element qualifier is already superfluous; and if it is not, you will probably be better off refactoring so that it can be removed.
Use the options to allow certain qualifying elements.
Configuration Option | Description |
---|---|
allow_element_with_attribute |
Allow elements to qualify attributes (default false) |
allow_element_with_class |
Allow elements to qualify classes (default false) |
allow_element_with_id |
Allow elements to qualify ids (default false) |
Don't write selectors with a depth of applicability greater than 3.
Bad: selectors with depths of 4
.one .two .three > .four {
...
}
.one .two {
.three > .four {
...
}
}
Good
.one .two .three {
...
}
.one .two {
.three {
...
}
}
Selectors with a large depth of applicability lead to CSS tightly-coupled to your HTML structure, making it brittle to change.
Deep selectors also come with a performance penalty, which can affect rendering times, especially on mobile devices. While the default limit is 3, ideally it is better to use less than 3 whenever possible.
Configuration Option | Description |
---|---|
max_depth |
Maximum depth before reporting errors (default 3) |
It is good practice to choose a convention for naming selectors.
Good
// convention: 'hyphenated_lowercase'
.foo-bar-77, foo-bar, #foo-bar {}
// convention: 'snake_case'
.foo_bar77, foo_bar, #foo_bar {}
// convention: 'camel_case'
.fooBar77, fooBar, #fooBar {}
}
You can specify different conventions for different types of selectors using the [type]_convention
options.
Since you might need to overwrite selectors for third party stylesheets, you
can specify ignored_names
as an array of individual selectors to ignore.
Another option is to specify ignored_types
to globally ignore a certain
type of selector.
Configuration Option | Description |
---|---|
convention |
Name of convention to use (hyphenated_lowercase (default) or snake_case , camel_case , or strict_BEM , or hyphenated_BEM ), or a regex the name must match. Note: If your project uses BEM, pay attention to the dialect of BEM you use. It may be strict_BEM or hyphenated_BEM . |
convention_explanation |
Custom catch-all explanation if you do not want to use the built-in explanations |
ignored_names |
Array of whitelisted names to not report lints for. |
ignored_types |
Array containing list of types of selectors to ignore (valid values are attribute , class , element , id , placeholder ) |
{type}_convention |
Convention for {type} selectors only, where {type} is one of attribute , class , id , or placeholder . See the convention option for possible values. |
{type}_convention_explanation |
Custom explanation for {type} selector convention, where {type} is one of attribute , class , id , or placeholder . |
SelectorFormat
will not resolve the parent selector reference (&
),
and will ignore selectors containing any parent references.
This is because these references cannot be resolved without compiling
the Sass into actual CSS. If you would like to see such functionality,
we'd love to merge a pull request!
Prefer the shortest shorthand form possible for properties that support it.
Bad: all 4 sides specified with same value
margin: 1px 1px 1px 1px;
Good: equivalent to specifying 1px for all sides
margin: 1px;
If you don't want to allow all possible shorthands, you can limit them by
setting the allowed_shorthands
array option to a subset of [1, 2, 3, 4]
.
Configuration Option | Description |
---|---|
allowed_shorthands |
Array of allowed shorthand lengths (default [1, 2, 3, 4] ) |
Properties within rule sets should each reside on their own line.
Bad
p {
margin: 0; padding: 0;
}
Good
p {
margin: 0;
padding: 0;
}
A special exception is made for single line rule sets. For example the following is acceptable:
p { margin: 0; padding: 0; }
If you want to also report a lint for single line rule sets, set the
allow_single_line_rule_sets
option to false
.
Configuration Option | Description |
---|---|
allow_single_line_rule_sets |
true or false (default true) |
Split selectors onto separate lines after each comma, and have each individual selector occupy a single line.
Bad: comma-separated selectors not on their own lines
.error p, p.explanation {
...
}
Bad: descendent selector spread over multiple lines
.error
p,
p.explanation {
...
}
Good: each selector sequence is on its own individual line
.error p,
p.explanation {
...
}
Note that selectors containing interpolation are ignored, since the Sass parser
cannot construct the selector parse tree at parse time, only at run time (which
is too late for scss-lint
to do anything with).
Commas in lists should be followed by a space.
Bad: no space after commas
@include box-shadow(0 2px 2px rgba(0,0,0,.2));
color: rgba(0,0,0,.1);
Good: commas followed by a space
@include box-shadow(0 2px 2px rgba(0, 0, 0, .2));
color: rgba(0, 0, 0, .1);
The style
option allows you to specify a different preferred style.
Configuration Option | Description |
---|---|
style |
one_space , or no_space or at_least_one_space (default one_space) |
Properties should be formatted with a single space separating the colon from the property's value.
Bad: no space after colon
margin:0;
Bad: more than one space after colon
margin: 0;
Good
margin: 0;
The style
option allows you to specify a different preferred style.
Configuration Option | Description |
---|---|
style |
one_space , no_space , at_least_one_space , one_space_or_newline , or aligned (default one_space) |
Properties should be formatted with no space between the name and the colon.
Bad: space before colon
margin : 0;
Good
margin: 0;
Variables should be formatted with a single space separating the colon from the variable's value.
Bad: no space after colon
$my-color:#fff;
Bad: more than one space after colon
$my-color: #fff;
Good
$my-color: #fff;
The style
option allows you to specify a different preferred style.
Configuration Option | Description |
---|---|
style |
one_space , no_space , at_least_one_space or one_space_or_newline (default one_space) |
Variables should be formatted with no space between the name and the colon.
Bad: space before colon
$my-var : 0;
Good
$my-var: 0;
Operators should be formatted with a single space on both sides of an infix
operator. These include +
, -
, *
, /
, %
, ==
, !=
, >
, >=
, <
,
and <=
.
Bad: no space around operator
margin: 5px+5px;
Bad: more than one space around operator
margin: 5px + 5px;
Good
margin: 5px + 5px;
Note that this linter only applies to actual, evaluated operators. So values
like nth-child(2n+1)
, 10px/12px
, and my-font
will not be linted, as they
are valid CSS.
The style
option allows you to specify a different preferred style.
Configuration Option | Description |
---|---|
style |
one_space , at_least_one_space , no_space (default one_space) |
Opening braces should be preceded by a single space.
Bad: no space before brace
p{
...
}
Bad: more than one space before brace
p {
...
}
Good
p {
...
}
Setting allow_single_line_padding
to true
allows you to use extra spaces to
nicely align single line blocks, so you can write:
.icon-chevron-up { &:before { content: "\e030"; } }
.icon-chevron-down { &:before { content: "\e031"; } }
.icon-chevron-left { &:before { content: "\e032"; } }
.icon-chevron-right { &:before { content: "\e033"; } }
Set style
to new_line
if you prefer to use a new line before braces, rather than a single space.
p
{
...
}
Configuration Option | Description |
---|---|
allow_single_line_padding |
Allow single line blocks to have extra spaces for nicer formatting (default false) |
style |
space or new_line (default space ) |
Parentheses should not be padded with spaces.
Bad
@include box-shadow( 0 2px 2px rgba( 0, 0, 0, .2 ) );
color: rgba( 0, 0, 0, .1 );
Good
@include box-shadow(0 2px 2px rgba(0, 0, 0, .2));
color: rgba(0, 0, 0, .1);
Configuration Option | Description |
---|---|
spaces |
Spaces to require between parentheses (default 0) |
String literals should be written with single quotes unless using double quotes would save on escape characters.
Bad: double quotes
content: "hello";
Good: single quotes
content: 'hello';
Good: double quotes prevent the need for escaping single quotes
content: "'hello'";
Single quotes are easier to type by virtue of not requiring the Shift
key on
most popular keyboard layouts.
Configuration Option | Description |
---|---|
style |
single_quotes or double_quotes (default single_quotes ) |
Property values; @extend
, @include
, and @import
directives; and variable
declarations should always end with a semicolon.
Bad: no semicolon
p {
color: #fff
}
Bad: space between value and semicolon
p {
color: #fff ;
}
Good
p {
color: #fff;
}
CSS allows you to omit the semicolon if the statement is the last statement in the rule set. However, this introduces inconsistency and requires anyone adding a property after that property to remember to append a semicolon.
Reports lines containing trailing whitespace.
Disabled by default
Don't write trailing zeros for numeric values with a decimal point.
Bad: unnecessary trailing zero
margin: .500em;
Good: no trailing zero
margin: .5em;
The extra zeros are unnecessary and just add additional bytes to the resulting generated CSS.
Disabled by default
Don't use the all
keyword to specify transition properties.
Bad: use of transition all
transition: all .5s ease-in;
Good: explicitly specify properties to transition
transition: color .5s ease-in, margin-bottom .5s ease-in;
Numeric values should not contain unnecessary fractional portions.
Bad
margin: 1.0em;
Good
margin: 1em;
Sass will automatically convert integers to floats when necessary, making the use of a fractional component in a value to "force" it to be a floating point number unnecessary. For example, the following code:
$margin: 1;
p { margin: $margin / 2; }
...will compile to:
p { margin: 0.5; }
Do not use parent selector references (&
) when they would otherwise be
unnecessary.
Bad
.foo {
& > .bar {
...
}
}
Good
.foo {
> .bar {
}
}
URLs should be valid and not contain protocols or domain names.
Including protocols or domains in URLs makes them brittle to change, and also unnecessarily increases the size of your CSS documents, reducing performance.
Bad: protocol and domain present
background: url('https://example.com/assets/image.png');
Good
background: url('assets/image.png');
URLs should always be enclosed within quotes.
Bad: no enclosing quotes
background: url(example.png);
Good
background: url('example.png');
Using quoted URLs is consistent with using other Sass asset helpers, which also expect quoted strings. It also works better with most syntax highlighters, and makes it easier to escape characters, as the escape rules for strings apply, rather than the different set of rules for literal URLs.
See the URL type documentation for more information.
Disabled by default
Properties, like color
and font
, are easier to read and maintain when
defined using variables rather than literals.
Bad
p {
color: red;
}
.warning {
color: #ff0;
}
Good
p {
color: $body-text;
}
.warning {
color: $body-warning;
}
By using variables, you can describe the semantics of the property value rather than just using the literal value (improving readability) and also make it easier to perform side-wide changes as you only need to change the value in one place, rather than several.
By default, this linter does not enforce the use of variables for any property.
To enable it, set the properties
option in your configuration, e.g.
linters:
VariableForProperty:
enabled: true
properties:
- color
- font
Note that values like currentColor
, inherit
, and transparent
will not be
reported, as they are special kinds of values that convey additional meaning.
Configuration Option | Description |
---|---|
properties |
Array of property names to check |
Avoid vendor prefixes. That is, don't write them yourself.
Instead, you can use Autoprefixer or mixins -- such as Compass or Bourbon -- to add vendor prefixes to your code. (If using your own mixins, make sure to exempt their source from this linter.)
At-rules, selectors, properties, and values are all checked. (See the examples below.)
The default identifier_list
, base
, should include everything that Autoprefixer addresses. You could also use a list covering Bourbon's CSS3 mixins: bourbon
. If neither of those suit you, you can write your own identifier list.
Additionally, you can manually include or exclude identifiers from the identifier list -- if, for example, you want to use pretty much all of the base
list but also want to allow yourself to use vendor prefixed transform
properties, for one reason or another.
All identifiers used by the identifier_list
, additional_identifiers
, or
excluded_identifiers
are stripped of vendor prefixes. See the predefined
lists
for examples.
Bad: vendor prefixes
@-webkit-keyframes anim {
0% { opacity: 0; }
}
::-moz-placeholder {
color: red;
}
.foo {
-webkit-transition: none;
}
.bar {
position: -moz-sticky;
}
Good
// With Autoprefixer ...
@keyframes anim {
0% { opacity: 0; }
}
::placeholder {
color: red;
}
.foo {
transition: none;
}
.bar {
position: sticky;
}
// With Bourbon mixin
@include placeholder {
color: red;
}
Configuration Option | Description |
---|---|
identifier_list |
Name of predefined identifier list to use (base or bourbon ) or an array of identifiers (default base ) |
additional_identifiers |
Identifiers to lint, in addition to the identifier_list (default [] ) |
excluded_identifiers |
Identifers in the identifier_list and additional_identifiers to exclude from linting (default [] ) |
Omit length units on zero values.
Bad: unnecessary units
margin: 0px;
Good
margin: 0;
Zero is zero regardless of the units of length.
Note that this only applies to lengths, since it is invalid to omit units for other types such as angles or times.