Table of Contents
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Blender Web Assets CSS and Sass guidelines
TODO: update to reflect v2 changes
Introduction
Blender Web Assets CSS and Sass guidelines is a flexible and modern set of rules to support Blender's Web Assets in streamlined custom web development. It helps using Web Assets in a consistent and maintainable way across projects, or in extending and improving the framework itself.
Blender Web Assets CSS and Sass guidelines is unique to Blender, but shares a lot of principles with other complete and more verbose guidelines: mainly CSS Guidelines by Harry Roberts, and Sass Guidelines by Kitty Giraduel, both of which we recommend to read first.
General
This section is an extension to CSS Style Guide - 4.1 CSS Style Rules by Google. Anything from this document overrides what was in the latter. Apply all referenced rules to Sass indented syntax.
- Use vanilla CSS for advanced functions that also exist in Sass whenever possible. For example, use CSS custom properties e.g.
var(--custom-property)
instead of Sass variables, and the CSS functioncalc()
instead of Sass Calculations. - Use Sass for advanced functions that don't exist in CSS, but help keep stylesheets maintainable at scale (functions, loops, mixins, etc.). Think of Sass mainly as a framework that helps in repetitive tasks while leveraging and relying on modern vanilla CSS functions as much as possible.
- Keep Sass as light and simple as possible. Don't use advanced Sass features just because they exist.
- Use the Sass indented syntax.
- Use CSS Flexbox for layout whenever possible. Use layout modes consistently. Don't mix different layout modes within the same component (e.g. Flexbox and Grid layouts).
Colours
- Use the HSL notation for colour values when designing in the browser.
--color-accent: hsl(31, 89%, 48%)
- Use the hexadecimal notation for colour values when the design system is developed and maintained in an external interface design tool (e.g. Figma or Penpot).
--color-accent: #e87d0d
- Use the following naming scheme when working with design system colour variables:
color-{type}-{level}
, where{type}
can beaccent
,bg
andtext
, and{level}
is optional. Example:--color-accent-primary
. - Use the following naming scheme when working with status colour variables:
color-{status}-{element}-{state}
, where{element}
and{state}
are optional. For example:--color-accent-bg
. - Use the following naming scheme when working with component colour variables:
color-{component}-{type}-{state}
, where{type}
and{state}
are optional. For example:--btn-color-bg
. Element colour variables should use the design system colour variables whenever possible. - Don't create new root variables for colours based on location or use case. The number of root colour variables should be not more than the actual colours in the design system, which is only a handful of items.
// Don't
\:root
--component-color: hsl(31, 89%, 48%)
// Do
.component
--component-color: var(--color-accent)
Numbers
Calculations
- Use vanilla CSS instead of Sass functions for calculation.
// Don't
--value: var(--spacer) * 9
// Do
--value: calc(var(--spacer) * 9)
Explicit numbers
- Use explicit numbers for values as little as possible.
// Don't
.m-3
margin: 1.0rem
// Do
.m-3
margin: var(--spacer)
Selector nesting
- Use selector nesting only within components, when it is not possible to name the component part meaningfully, or style it with utility classes.
- Don't nest selectors unless very necessary, to keep specificity low.
- Don't nest more than 3 levels deep, if selector nesting is needed.
- Don't generate new class or ID selectors from the current selector reference (
&
), to keep the selectors searchable in the codebase. Using the current selector reference to combinate selectors, pseudo-classes and pseudo-elements is fine.
// Don't
.component
&-part
color: var(--primary)
// Do
.component
.component-part
color: var(--primary)
// Do also
.component
&:hover
color: var(--secondary)
Type selectors
- Use type selectors as little as possible.
- Use type selectors only within components, when it is not possible to name the component part meaningfully, or style it with utility classes.
Formatting & syntax
This section is an extension to CSS Style Guide - 4.2 CSS Formatting Rules by Google. Anything from this document overrides what was in the latter. Apply all referenced rules to Sass indented syntax.
Commenting
- Use the following comment style for separating blocks of code.
/* Example separator. */
- Use the following comment style for inline explanation of code.
color: var(--primary) // Example explanation.
Naming conventions
- Use a BEM-like naming convention for related UI pieces of components following the <block>-<element>-<modifier> pattern.
- Use simple hyphens to separate words in class names instead of BEM-style delimiters (
--
or__
). - Use words in their singular forms (e.g.
.component
instead of.components
). - Don't register new class names for elements nested more than 3 levels deep in the main component, but use selector nesting or utility classes to style them.
Architecture
Components
Web Assets is a CSS component framework that also has utility styles. The component-based approach helps improve and maintain Blender’s opinionated design system across projects without requiring markup changes on a per-project basis after updates. Although we suggest reusing existing Web Assets components for standardized elements, blending component and utility systems for customizations and layout on the project level is legitimate and useful until the following criteria are met.
Component styles and utility styles
- Create new partials for components (e.g.
_comments.sass
). - Use the BEM methodology to create component styles.
- Create new class names for component parts by extending the class names of their parents (e.g.
.component-part-child
). It's acceptable to drop class name part of a parent if the component part is deeply nested. - Don't create class names with more than 3 class name parts.
- Use utility classes when it is not possible to name the component part meaningfully. It's acceptable to use utility classes within components on a permanent basis.
- Use utility classes for customizing existing components.
- Don't use
!important
in utility styles, unless very necessary. Utility classes override component styles without!important
until other rules from these guidelines apply (low inheritance and specificity).
Files & folders
.
└── <custom>
│ ├── <custom>.sass
│ ├── _<partial-app-page>.sass
│ ├── _<partial-app-page-1>.sass
│ ├── _<partial-component>.sass
│ ├── _<partial-component-1>.sass
│ ├── _variables.sass
│ └── _web-assets-overrides.sass
└── vendor
├── vendor
└── ...
custom.sass
Use custom.sass
as the main stylesheet to import and manage all other stylesheets.
_<partial-app-page>.sass
Create new partials for app-specific styling if needed (e.g. _page-blog.sass
). Create as little app-specific styling and rules as possible: only do it if very necessary.
_<partial-component>.sass
Create new partials for components that are not part of Web Assets yet (e.g. _comments.sass
). Think of new components as possible candidates to be added and moved to Web Assets later.
_variables.sass
Use _variables.sass
to customize existing variables and create new ones. Register only new vanilla CSS custom properties, and no Sass variables unless very necessary.
_web-assets-overrides.sass
Add Web Assets overrides to web-assets-overrides.sass
. Component overrides should be kept to a minimum, and there is no need to create new files for individual components.
Sass guidelines
Mixins
TODO
Variables
TODO: clarify more precisely when it is acceptable to use Sass variables
- Use vanilla CSS custom properties instead of Sass variables whenever possible.
- Use Sass variables when explicitly declaring variables to be used with advanced Sass features (e.g. loops, mixins, etc.).
- Use variables for all values that are repeated.
- Use variables in functions and rules whenever possible instead of explicit numbers.
Conditional statements
- Use vanilla CSS functions
:is
,:not
and:where
functions if very necessary. - Do not use Sass conditional statements.
Extend
- Don't create relationships between component partials on the same level, even if you repeat yourself otherwise.
// Don't
// component.sass
.component
color: var(--primary)
// component-1.sass
.component-1
@extend .component
// Do
// component.sass
.component
color: var(--primary)
// component-1.sass
.component-1
color: var(--primary)
Loops
- Use
@each
loops to iterate over a list or a map to generate a list of rules.
// Generate utility classes for align-items
$align-items: center, end, start
@each $align-item in $align-items
.align-item-#{$align-item}
align-item: $align-item
- Use
@for
loops to iterate over a specific range to generate a list of rules.
// Generate utility classes for heights
@for $i from 1 through 9
.h-#{i}
height: calc(var(--spacer) * $i)