(S)CSS
Syntax
- Use soft tabs with two spaces for
CSS— they’re the only way to guarantee code renders the same in any environment. - Use soft tabs with four spaces for
SCSS - When grouping selectors, keep individual selectors to a single line.
- Include one space before the opening brace of declaration blocks for legibility.
- Place closing braces of declaration blocks on a new line.
- Include one space after
:for each declaration. - Each declaration should appear on its own line for more accurate error reporting.
- End all declarations with a semi-colon.
- Comma-separated property values should include a space after each comma (e.g.
box-shadow). - Use space-separated values for color properties (e.g., color:
rgb(0 0 0 / .5)). See the Colors section for more information. - Prefix property values or color parameters with a leading zero (e.g.,
0.5instead of.5and-0.5pxinstead of-.5px). - Use
msfor timings < 1 second andsfor timings > 1 second (e.g.300msinstead of0.3s/1.5sinstead of1500ms) - Lowercase all hex values, e.g.,
#ffffff. Lowercase letters are much easier to discern when scanning a document as they tend to have more unique shapes. - Use long formed hex values, e.g.,
#003388instead of#038. - Use single quotes instead of double quotes
- Quote attribute values in selectors, e.g.,
input[type='text']for SCSS andinput[type="text"]for CSS. They’re only optional in some cases, and it’s a good practice for consistency. - Avoid specifying units for zero values, e.g.,
margin: 0; instead ofmargin: 0px;.
// Bad CSS
.selector, .selector-secondary, .selector[type=text]{
padding:15px;
margin:0px 0px 15px;
background-color:rgba(0, 0, 0, .5);
box-shadow:0px 1px 2px #038,inset 0 1px 0 #FFF
}
// Good CSS
.selector,
.selector-secondary,
.selector[type='text'] {
padding: 1rem;
margin-bottom: 1rem;
background-color: rgb(0 0 0 / 0.5);
box-shadow: 0 0.125rem 0.125rem #003388, inset 0 0.125rem 0 #ffffff;
}
Declaration order
As an alternative to alphabetical ordered properties:
Property declarations should be grouped together in the following order:
- Positioning
- Box model
- Typographic
- Visual
- Misc
Positioning comes first because it can remove an element from the normal document flow and override box model related styles. The box model—whether it’s flex, float, grid, or table—follows as it dictates a component’s dimensions, placement, and alignment. Everything else takes place inside the component or without impacting the previous two sections, and thus they come last.
While border is part of the box model, most systems globally reset the box-sizing to border-box so that border-width doesn’t affect overall dimensions. This, combined with keeping border near border-radius, is why it’s under the Visual section instead.
Preprocessor mixins and functions should appear wherever most appropriate. For example, a border-top-radius() mixin would go in place of border-radius properties, while a responsive-font-size() function would go in place of font-size properties.
.declaration-order {
// Positioning
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 100;
// Box model
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 6.25rem;
height: 6.25rem;
// Typography
font: normal 0.875rem 'Helvetica Neue', sans-serif;
line-height: 1.5;
color: #333;
text-align: center;
text-decoration: underline;
// Visual
background-color: #f5f5f5;
border: 0.125rem solid #e5e5e5;
border-radius: 0.25rem;
// Misc
opacity: 1;
}
Logical properties
Logical properties are alternatives to directional and dimensonal properties based on abstract terms like block and inline. By default, block refers to the vertical direction (top and bottom) while inline refers to the horizontal direction (right and left). You can begin to use these values in your CSS in all modern, evergreen browsers.
Why use logical properties? Not every language flows left-ro-right like English, so the writing mode needs to be flexible. With logical properties, you can easily support languages that can be written horizontally or vertically (like Chinese, Japanese, and Korean). Plus, they’re usually shorter and simpler to write.
Additional reading:
- CSS Logical Properties and Values – MDN
- CSS Logical Properties and Values — CSS Tricks
- CSS Writing Modes – MDN
Colors
With the support of CSS Color Levels 4 in all major browsers, rgba() and hsla() are now aliases for rgb() and hsl(), meaning you can modify alpha values in rgb() and hsl(). Along with this comes support for new space-separated syntax for color values. For compability with future CSS color functions, use this new syntax.
Additional reading:
.element {
color: rgb(255 255 255 / 0.65);
background-color: rgb(0 0 0 / 0.95);
}
Value units
Prefer using rem over px as it respects user preferences and you can change the apparent px value of rem to whatever you'd like. Read this Stack Overflow answer for more details.
To avoid values with high precision like 0.0625rem, we use maximum steps of 0.125rem restricting it to be the lowest value possible.
Media query placement
Place media queries as close to their relevant rule sets whenever possible. Don’t bundle them all in a separate stylesheet or at the end of the document. Doing so only makes it easier for folks to miss them in the future.
.element { ... }
.element-avatar { ... }
.element-selected { ... }
@media (min-width: 30rem) {
.element { ... }
.element-avatar { ... }
.element-selected { ... }
}
Single declarations
In instances where a rule set includes only one declaration, consider removing line breaks for readability and faster editing. Any rule set with multiple declarations should be split to separate lines.
The key factor here is error detection—e.g., a CSS validator stating you have a syntax error on Line 183. With a single declaration, there’s no missing it. With multiple declarations, separate lines is a must for your sanity.
// Single declarations on one line
.span1 { width: 3.75rem; }
.span2 { width: 8.75rem; }
.span3 { width: 13.75rem; }
// Multiple declarations, one per line
.sprite {
display: inline-block;
width: 1rem;
height: 0.875rem;
background-image: url('../img/sprite.png');
}
.icon { background-position: 0 0; }
.icon-home { background-position: 0 -1.25rem; }
.icon-account { background-position: 0 -2.5rem; }
Shorthand notation
Limit shorthand declaration usage to instances where you must explicitly set all available values. Frequently overused shorthand properties include:
- padding
- margin
- font
- background
- border
- border-radius
Usually we don’t need to set all the values a shorthand property represents. For example, HTML headings only set top and bottom margin, so when necessary, only override those two values. A 0 value implies an override of either a browser default or previously specified value.
Excessive use of shorthand properties leads to sloppier code with unnecessary overrides and unintended side effects.
The Mozilla Developer Network has a great article on shorthand properties for those unfamiliar with notation and behavior.
// Bad example
.element {
margin: 0 0 0.625rem;
background: red;
background: url('image.jpg');
border-radius: 0.25rem 0.25rem 0 0;
}
// Good example
.element {
margin-bottom: 0.625rem;
background-color: red;
background-image: url('image.jpg');
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}