CSS / SCSS
Create stylesheets that are scalable, maintainable, readable, and easy to debug.
By following consistent syntax rules, teams reduce specificity issues, prevent naming collisions, and build styling systems that support long-term growth.
Class name style: kebab-case or camelCase
Use kebab-case
(or BEM) for global CSS/SCSS class names to follow web conventions. When using CSS Modules with React, prefer camelCase
to enable dot-notation access, autocompletion, and better TypeScript support.
1/* styles.module.scss */
2.Card-title {
3 font-size: 1.5rem;
4}
<div className={styles['Card-title']}>...</div>
1/* CSS Module */
2.cardTitle {
3 font-size: 1.5rem;
4}
<div className={styles.cardTitle}>...</div>
Or for global styles:
1/* global.scss */
2.card-title {
3 font-size: 1.5rem;
4}
Avoid deep nesting in SCSS
Limit SCSS nesting to 2–3 levels. Deep nesting increases specificity and makes styles harder to override or reuse.
1.header {
2 .nav {
3 .item {
4 .link {
5 color: blue;
6 }
7 }
8 }
9}
1.card-icon {
2 color: red;
3}
Use variables for colors, spacing and sizes
Avoid hardcoded values. Use SCSS variables or CSS custom properties for consistent and theme-friendly design tokens.
1.button {
2 padding: 12px 24px;
3 background-color: #2196f3;
4}
1$spacing-sm: 12px;
2$spacing-md: 24px;
3$color-primary: #2196f3;
4
5.button {
6 padding: $spacing-sm $spacing-md;
7 background-color: $color-primary;
8}
Use shorthand properties when appropriate
Prefer shorthand syntax for properties like margin
, padding
, border
, and font
when all values are intentional. Avoid shorthands that override defaults accidentally.
1margin-top: 10px;
2margin-right: 10px;
3margin-bottom: 10px;
4margin-left: 10px;
margin: 10px;
Use meaningful class names (not presentational)
Class names should describe what the element is, not how it looks. Avoid names like .red-text
or .margin-10
.
1.red-text {
2 color: red;
3}
4
5.margin-10 {
6 margin: 10px;
7}
1.error-message {
2 color: red;
3}
4
5.card {
6 margin: 10px;
7}
Group and order CSS properties
Keep related properties visually grouped together (e.g., layout, box model, typography, visual) and follow a consistent property order within each block. This improves readability, makes diffs cleaner, and helps avoid accidental overrides.
Use one of the following strategies:
By category (recommended): Position → Box Model → Typography → Visual
Alphabetically: Useful with linters and auto-formatters
1.card {
2 font-size: 16px;
3 padding: 1rem;
4 color: #333;
5 position: relative;
6 margin: 1rem;
7}
1// grouped by category:
2.card {
3 position: relative;
4
5 margin: 1rem;
6 padding: 1rem;
7
8 font-size: 16px;
9 color: #333;
10}
1// alphabetical:
2.card {
3 color: #333;
4 font-size: 16px;
5 margin: 1rem;
6 padding: 1rem;
7 position: relative;
8}
Avoid '!important' unless absolutely necessary
The use of !important
should be rare. It breaks the natural cascade and makes debugging and overrides much harder. If necessary, document why.
Use mobile-first responsive breakpoints
Start styling for the smallest screen first, then layer in enhancements with min-width media queries. This results in more efficient CSS and better progressive enhancement.
1.card {
2 font-size: 18px;
3}
4
5@media (max-width: 768px) {
6 .card {
7 font-size: 16px;
8 }
9}
1.card {
2 font-size: 16px;
3}
4
5@media (min-width: 768px) {
6 .card {
7 font-size: 18px;
8 }
9}
Use pseudo-elements and pseudo-classes properly
Use ::before
, ::after
, :hover
, :focus
, etc. only for visual or interactive enhancements — never for content critical to UX or accessibility. Always use double colon (::
) with pseudo-elements for clarity.
1.card::before {
2 content: "★ Important";
3}
1.card::before {
2 content: "";
3 display: block;
4 background: url(icon.svg);
5}
Prefer '@use' and '@forward' over '@import' (SCSS)
SCSS @import
is deprecated. Use the @use
and @forward
syntax to create well-scoped, modular style systems with clear dependencies.
@import "colors";
1// _colors.scss
2$primary: #3498db;
3$danger: #e74c3c;
4
5// _index.scss
6@forward "colors";
7
8// usage
9@use "styles" as *;
Use mixins for reusable patterns — not for everything
Mixins are powerful but should be used only when dynamic values are needed or when abstracting logic. Prefer placeholders (%
) or utility classes for static reuse.
1@mixin flex-center {
2 display: flex;
3 justify-content: center;
4 align-items: center;
5}
6
7.button {
8 @include flex-center;
9}
1%flex-center {
2 display: flex;
3 justify-content: center;
4 align-items: center;
5}
6
7.button {
8 @extend %flex-center;
9}
Comment complex rules and intent
Use comments to document why something exists, not what it is. Focus on intent, edge cases, hacks, or non-obvious constraints. Prefer //
for SCSS or /* */
for CSS
1// sets color to red
2.text-error {
3 color: red;
4}
1// Override for legacy warning system
2// Do not refactor without checking report styles
3.text-warning {
4 color: orange;
5}
Scope styles to components or features
Avoid global styles leaking across unrelated modules. Scope CSS to a feature/component using class prefixes, BEM, or CSS Modules to prevent collisions and improve maintainability.
1.button {
2 padding: 1rem;
3}
1.profile-card__button {
2 padding: 1rem;
3}
Or in CSS Modules:
1.cardButton {
2 padding: 1rem;
3}
Use custom properties (--var) for theming
Prefer native CSS variables (--primary-color
) when working with themes, light/dark modes, or runtime dynamic styling. Combine with SCSS for fallback values or defaults.
1:root {
2 --bg-color: #f5f5f5;
3}
4
5body {
6 background: var(--bg-color);
7}
Store and manage colors in variables
Centralize your color palette using SCSS variables or CSS custom properties. Avoid scattering hardcoded values across files.
1$color-danger: #e74c3c;
2
3.alert {
4 color: $color-danger;
5}
6
7.button {
8 background-color: $color-danger;
9}
Control 'z-index' with a design scale
Avoid arbitrary z-index
values. Define a semantic scale (modal: 1000
, dropdown: 200
, etc.) to prevent stacking issues and collisions.
1.modal {
2 z-index: 9999;
3}
1$z-modal: 1000;
2$z-dropdown: 200;
3
4.modal {
5 z-index: $z-modal;
6}
Use system fonts or font loading fallbacks
Always provide font fallbacks and prioritize performance. Use system fonts when possible, or load web fonts efficiently with font-display: swap
.
1body {
2 font-family: "CustomFont";
3}
1body {
2 font-family: "CustomFont", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
3 font-display: swap;
4}
Use logical properties for better adaptability
Prefer logical properties (margin-inline
, padding-block
, inset
, etc.) for better support of RTL and vertical writing modes.
1.container {
2 padding-left: 2rem;
3 padding-right: 2rem;
4}
1.container {
2 padding-inline: 2rem;
3}
Use 'prefers-color-scheme' for dark mode
Respect user system preferences for light/dark themes using @media (prefers-color-scheme).
1body.dark {
2 background: black;
3}
1@media (prefers-color-scheme: dark) {
2 body {
3 background: black;
4 color: white;
5 }
6}