8 CSS and Sass guidelines
Márton Lente edited this page 2024-04-19 17:52:29 +02:00
This file contains ambiguous Unicode characters

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 function calc() 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 be accent, bg and text, 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 Blenders 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)