CSS3 Coding Standards#

Reference#

File Organization#

public/
├── styles/                   # Global shared styles
│   ├── variables.css         # Shared variables
│   ├── typography.css        # Typography rules
│   ├── colors.css            # Color definitions
│   └── utilities.css         # Shared utilities
│
├── apps/
│   ├── app1/
│   │   ├── components/
│   │   │   └── Button/
│   │   │       ├── Button.tsx
│   │   │       └── Button.module.css
│   │   └── styles/           # App-specific global styles
│   │       └── theme-dark.css
│   │       └── theme-light.css
│   └── app2/
│       └── [similar structure]

Component Style Organization#

  1. Component-Specific CSS - Keep component styles in the same folder as the component - Use the same name as the component - Import styles directly in the component file

// Button/Button.tsx
import './Button.css';

const Button = ({ variant = 'primary' }) => (
    <button className={`button button--${variant}`}>
        Click me
    </button>
);
  1. Global Styles - Use the shared /public/styles for cross-app styles - Keep app-specific global styles in apps/<app-name>/src/styles - Import global styles in the app’s entry point

  2. Style Hierarchy - Shared variables and utilities (highest level) - App-specific global styles - Component-specific styles (most specific)

Best Practices#

  1. CSS Organization - Keep component styles scoped and specific - Avoid deep nesting

/* Button/Button.css */
.button {
    /* Base styles */
}

.button--primary {
    /* Primary variant */
}

.button--secondary {
    /* Secondary variant */
}
  1. Global Styles - Define shared variables in public/styles - Use CSS custom properties for theming - Keep global styles minimal

/* public/styles/variables.css */
:root {
    --color-primary: #007bff;
    --font-size-base: 1rem;
}
  1. Importing Styles - Import global styles once at app entry - Import component styles in component files - Maintain consistent import order

// apps/app1/src/index.tsx
import '../../../styles/variables.css';
import '../../../styles/typography.css';
import './styles/theme.css';

Naming Conventions#

File Names#

  1. Component CSS Modules - Match exactly the component name - Use .module.css extension - Use PascalCase to match component

Component File:    Button.tsx
CSS Module File:   Button.module.css

Component File:    UserProfile.tsx
CSS Module File:   UserProfile.module.css
  1. Global CSS Files - Use lowercase - Use hyphens for spaces - Descriptive and purpose-based names

public/styles/
├── variables.css
├── typography.css
├── color-tokens.css
└── utility-classes.css

apps/app1/src/styles/
├── theme-dark.css
├── theme-light.css
└── app-utilities.css

Class Names#

  1. All CSS Classes - Use lowercase with hyphens (kebab-case) - Be specific and descriptive - Follow same convention for both modules and global styles

/* ❌ Bad */
.buttonPrimary {}
.btn_wrapper {}
.HEADER {}
.userCard {}
.marginTop20 {}
.flex_container {}

/* ✅ Good */
.button {}
.button-primary {}
.button-wrapper {}
.user-card {}
.margin-top-lg {}
.container-flex {}
  1. State Classes - Use lowercase with hyphens - Prefix with ‘is-’ or ‘has-’ - Keep consistent across all styles

/* ❌ Bad */
.active {}
.isHidden {}
.has_error {}

/* ✅ Good */
.is-active {}
.is-hidden {}
.has-error {}
  1. Utility Classes - Use lowercase with hyphens - Start with property or purpose - Use size modifiers consistently

/* ❌ Bad */
.marginLg {}
.p2 {}
.flex {}

/* ✅ Good */
.margin-lg {}
.padding-sm {}
.display-flex {}

Naming Best Practices#

  1. Consistency - Use kebab-case for all class names - Follow naming pattern consistently across all files - Use same conventions in both modules and global styles

  2. Clarity - Names should clearly indicate purpose - Avoid abbreviations unless widely understood - Use full, descriptive names

  3. Modularity - Keep names scoped to their purpose - Avoid overly generic names - Use prefixes for related groups of styles

/* ❌ Bad - Too generic */
.title {}
.container {}
.wrapper {}

/* ✅ Good - Scoped and specific */
.user-profile-title {}
.card-container {}
.form-field-wrapper {}

Styling Approach#

Core Principles#

  1. Component-First - Each component owns its styles via CSS Modules - Styles live alongside their components - Component styles should be self-contained

  2. Global Styles - Minimal global styles - Focus on design tokens and utilities - Shared across all applications

  3. Cascading Order - Design tokens (variables) - Global styles - Component styles - Utility classes (overrides)

Implementation Strategy#

  1. Design Tokens - Define in global variables.css - Use CSS custom properties - Include colors, spacing, typography

/* public/styles/variables.css */
:root {
    /* Colors */
    --color-primary: #007bff;
    --color-secondary: #6c757d;

    /* Spacing */
    --spacing-unit: 0.25rem;
    --spacing-sm: calc(var(--spacing-unit) * 2);
    --spacing-md: calc(var(--spacing-unit) * 4);

    /* Typography */
    --font-family-base: system-ui, sans-serif;
    --font-size-base: 1rem;
}
  1. Component Styles - Use CSS Modules for encapsulation - Import global variables - Keep styles focused and specific

// UserCard/UserCard.tsx
import styles from './UserCard.module.css';

const UserCard = ({ user }) => (
    <div className={styles.card}>
        <h2 className={styles.title}>{user.name}</h2>
        <p className={styles.description}>{user.bio}</p>
    </div>
);
/* UserCard/UserCard.module.css */
.card {
    padding: var(--spacing-md);
    border-radius: var(--border-radius);
    background: var(--color-background);
}

.title {
    font-size: var(--font-size-lg);
    color: var(--color-text-primary);
}
  1. Global Utilities - Create focused utility classes - Use for common patterns - Keep utilities minimal

/* public/styles/utility-classes.css */
.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}

.text-center {
    text-align: center;
}

Responsive Design#

  1. Mobile-First Approach - Start with mobile styles - Add complexity for larger screens - Use consistent breakpoints

/* public/styles/variables.css */
:root {
    --breakpoint-sm: 576px;
    --breakpoint-md: 768px;
    --breakpoint-lg: 992px;
}

/* Component.module.css */
.container {
    padding: var(--spacing-sm);

    @media (min-width: 768px) {
        padding: var(--spacing-md);
    }
}
  1. Responsive Utilities - Create responsive utility classes - Use consistent naming patterns - Keep responsive overrides minimal

/* public/styles/utility-classes.css */
@media (min-width: 768px) {
    .md\:hidden {
        display: none;
    }

    .md\:block {
        display: block;
    }
}

Theme Management#

  1. Theme Variables - Define themes using CSS custom properties - Allow easy theme switching - Keep theme definitions separate

/* apps/app1/styles/theme-light.css */
:root {
    --color-background: #ffffff;
    --color-text: #1a1a1a;
}

/* apps/app1/styles/theme-dark.css */
:root {
    --color-background: #1a1a1a;
    --color-text: #ffffff;
}
  1. Theme Implementation - Use semantic variable names - Apply themes consistently - Support system preferences

/* Component.module.css */
.container {
    background: var(--color-background);
    color: var(--color-text);
}

Performance Considerations#

  1. CSS Loading - Load global styles first - Use code splitting for themes - Minimize CSS bundle size

  2. Selector Performance - Keep selectors simple - Avoid deep nesting - Use class selectors primarily

/* ❌ Bad - Complex selector */
.card > div > span.text {
    color: var(--color-text);
}

/* ✅ Good - Simple selector */
.cardText {
    color: var(--color-text);
}
  1. Animation Performance - Use transform and opacity for animations - Avoid layout-triggering properties - Consider reduced motion preferences

.animatedElement {
    transition: transform 0.3s ease;

    @media (prefers-reduced-motion: reduce) {
        transition: none;
    }
}

Best Practices#

CSS Module Usage#

  1. Scoping - Keep styles specific to the component - Avoid global styles in modules - Use composition for shared styles

/* ❌ Bad - Too generic */
.container { }
.title { }

/* ✅ Good - Component-specific */
.user-profile-container { }
.user-profile-title { }
  1. Class Names - Use meaningful, descriptive names - Follow kebab-case convention - Avoid abbreviations

/* ❌ Bad */
.cnt { }
.usr-box { }
.userBox { }

/* ✅ Good */
.container { }
.user-box { }

Component Styling#

  1. Single Responsibility - Each component should own its styles - Avoid styles that affect multiple components - Use composition for shared styles

/* ❌ Bad - Styles affecting multiple components */
.card {
    /* styles that might affect other cards */
}

/* ✅ Good - Component-specific styles */
.user-card {
    /* styles specific to UserCard component */
}
  1. Props and Variants - Use props to control variants - Keep variant styles in the module - Use meaningful variant names

// ✅ Good - Component with variants
const Button = ({ variant, size }) => (
    <button className={`${styles.button} ${styles[variant]} ${styles[size]}`}>
        Click me
    </button>
);

Global Styles#

  1. CSS Custom Properties - Define tokens at root level - Use semantic names - Group related variables

/* ✅ Good - Semantic variable names */
:root {
    --color-primary: #007bff;
    --color-primary-hover: #0056b3;
    --spacing-unit: 8px;
    --spacing-large: calc(var(--spacing-unit) * 2);
}
  1. Utility Classes - Keep utilities focused and single-purpose - Use consistent naming patterns - Document usage

/* ✅ Good - Single-purpose utilities */
.margin-top-md { margin-top: var(--spacing-md); }
.text-center { text-align: center; }
.display-flex { display: flex; }

Responsive Design#

  1. Mobile First - Start with mobile styles - Use min-width media queries - Follow standard breakpoints

.component {
    /* Mobile styles by default */
    padding: var(--spacing-sm);

    /* Tablet and up */
    @media (min-width: 768px) {
        padding: var(--spacing-md);
    }
}
  1. Breakpoint Usage - Use variables for breakpoints - Keep media queries with related styles - Avoid device-specific breakpoints

Performance#

  1. Selector Efficiency - Use class selectors - Avoid deep nesting - Minimize specificity conflicts

/* ❌ Bad - Deep nesting and high specificity */
.container .wrapper div.content span { }

/* ✅ Good - Flat structure */
.content-text { }
  1. Animation Performance - Use transform and opacity - Avoid layout-triggering properties - Consider reduced motion

/* ✅ Good - Performance optimized animation */
.fade-in {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.3s ease, transform 0.3s ease;
}

Maintainability#

  1. Code Organization - Group related styles - Use consistent ordering - Add comments for complex styles

/* ✅ Good - Organized styles */
.component {
    /* Layout */
    display: flex;
    padding: var(--spacing-md);

    /* Typography */
    font-size: var(--font-size-md);
    line-height: 1.5;

    /* Theme */
    background: var(--color-background);
    color: var(--color-text);
}
  1. Documentation - Document complex selectors - Explain non-obvious solutions - Include usage examples

/**
 * Component container
 * 1. Uses CSS Grid for responsive layout
 * 2. Maintains aspect ratio on resize
 * 3. Handles overflow content
 */
.grid-container {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--spacing-md);
}
  1. File Size - Keep files under 300 lines - Split large components - Use composition

Accessibility#

  1. Color Contrast - Meet WCAG guidelines - Test with color contrast tools - Provide sufficient contrast ratios

  2. Focus States - Always visible focus indicators - Consistent focus styles - Support keyboard navigation

/* ✅ Good - Clear focus states */
.button:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}
  1. Motion - Respect reduced motion preferences - Provide alternatives to animations - Keep animations subtle

@media (prefers-reduced-motion: reduce) {
    .animate {
        animation: none;
        transition: none;
    }
}

Theming#

Theme Structure#

  1. Base Variables - Define in global variables.css - Use semantic naming - Include fallback values

/* public/styles/variables.css */
:root {
    /* Colors */
    --color-primary: #007bff;
    --color-secondary: #6c757d;
    --color-success: #28a745;
    --color-error: #dc3545;

    /* Semantic Colors */
    --color-text-primary: var(--color-gray-900);
    --color-text-secondary: var(--color-gray-700);
    --color-background: var(--color-white);
    --color-border: var(--color-gray-200);

    /* Typography */
    --font-family-base: system-ui, sans-serif;
    --font-size-base: 1rem;
    --line-height-base: 1.5;

    /* Spacing */
    --spacing-unit: 0.25rem;
    --spacing-sm: calc(var(--spacing-unit) * 2);
    --spacing-md: calc(var(--spacing-unit) * 4);
    --spacing-lg: calc(var(--spacing-unit) * 6);

    /* Border Radius */
    --border-radius-sm: 0.25rem;
    --border-radius-md: 0.5rem;
    --border-radius-lg: 1rem;
}

Theme Implementation#

  1. Theme Files - Separate theme definitions - Override base variables - Keep themes modular

/* apps/app1/styles/theme-light.css */
:root {
    /* Background Colors */
    --color-background-primary: var(--color-white);
    --color-background-secondary: var(--color-gray-100);
    --color-background-tertiary: var(--color-gray-200);

    /* Text Colors */
    --color-text-primary: var(--color-gray-900);
    --color-text-secondary: var(--color-gray-700);
    --color-text-tertiary: var(--color-gray-500);

    /* Border Colors */
    --color-border-primary: var(--color-gray-200);
    --color-border-secondary: var(--color-gray-300);

    /* Interactive Colors */
    --color-hover: rgba(0, 0, 0, 0.05);
    --color-active: rgba(0, 0, 0, 0.1);
    --color-focus-ring: rgba(0, 123, 255, 0.25);
}

/* apps/app1/styles/theme-dark.css */
:root {
    /* Background Colors */
    --color-background-primary: var(--color-gray-900);
    --color-background-secondary: var(--color-gray-800);
    --color-background-tertiary: var(--color-gray-700);

    /* Text Colors */
    --color-text-primary: var(--color-gray-100);
    --color-text-secondary: var(--color-gray-300);
    --color-text-tertiary: var(--color-gray-500);

    /* Border Colors */
    --color-border-primary: var(--color-gray-700);
    --color-border-secondary: var(--color-gray-600);

    /* Interactive Colors */
    --color-hover: rgba(255, 255, 255, 0.05);
    --color-active: rgba(255, 255, 255, 0.1);
    --color-focus-ring: rgba(0, 123, 255, 0.25);
}

Theme Switching#

  1. System Preference - Support prefers-color-scheme - Provide manual override - Use data attributes for theme switching

/* Auto dark mode */
@media (prefers-color-scheme: dark) {
    :root {
        /* Dark theme variables */
    }
}

/* Manual theme switching */
[data-theme="dark"] {
    /* Dark theme variables */
}

[data-theme="light"] {
    /* Light theme variables */
}
  1. Theme Application - Use semantic variable names - Apply consistently across components - Avoid hard-coded values

/* ❌ Bad - Hard-coded colors */
.button {
    background-color: #007bff;
    color: white;
}

/* ✅ Good - Theme variables */
.button {
    background-color: var(--color-primary);
    color: var(--color-text-on-primary);
}

Component Theming#

  1. Theme-Aware Components - Use CSS custom properties - Support theme overrides - Maintain accessibility

.card {
    /* Base styles using theme variables */
    background-color: var(--color-background-primary);
    color: var(--color-text-primary);
    border: 1px solid var(--color-border-primary);

    /* Component-specific theme variables */
    --card-padding: var(--spacing-md);
    --card-border-radius: var(--border-radius-md);

    padding: var(--card-padding);
    border-radius: var(--card-border-radius);
}
  1. Theme Variants - Use modifiers for variants - Maintain theme consistency - Support dark/light modes

.card-elevated {
    background-color: var(--color-background-primary);
    box-shadow: var(--shadow-md);
}

.card-outlined {
    background-color: transparent;
    border: 2px solid var(--color-border-primary);
}

Best Practices#

  1. Variable Organization - Group related variables - Use consistent naming patterns - Document variable purposes

  2. Accessibility - Maintain sufficient contrast ratios - Test themes with screen readers - Support high contrast modes

@media (forced-colors: active) {
    .button {
        border: 1px solid ButtonText;
    }
}
  1. Performance - Minimize theme-switching flicker - Use efficient selectors - Consider initial load performance

  2. Maintainability - Keep theme definitions DRY - Document theme structure - Use consistent variable naming

Linting and Formatting#

Formatting Rules#

  1. Indentation and Spacing - Use soft tabs (2 spaces) for indentation - One space before the opening brace - One space after each colon - No space before semicolons - One selector per line - One blank line between rules - No trailing whitespace

/* ❌ Bad */
.avatar{
    border-radius:50%;
    border:2px solid white;}
.example , .example2{padding:10px;}

/* ✅ Good */
.avatar {
  border-radius: 50%;
  border: 2px solid white;
}

.example,
.example2 {
  padding: 10px;
}
  1. Selectors - Prefer classes over IDs - Use kebab-case naming - Avoid deep nesting - Keep selectors concise

/* ❌ Bad */
#header .navigation div.menu-item span { }
.userProfile { }
.user_avatar { }

/* ✅ Good */
.header-nav-item { }
.user-profile { }
.user-avatar { }
  1. Properties - Group related properties - Use shorthand when possible - Include leading zero - Use lowercase colors - Use hex or rgb(a)

/* ❌ Bad */
.element {
  margin-top: 10px;
  margin-right: 20px;
  margin-bottom: 10px;
  margin-left: 20px;
  color: #FFFFFF;
  border-color: rgb(0,0,0);
  opacity: .5;
}

/* ✅ Good */
.element {
  margin: 10px 20px;
  color: #fff;
  border-color: rgb(0, 0, 0);
  opacity: 0.5;
}

Property Order#

Follow a consistent property order:

  1. Positioning

  2. Box Model

  3. Typography

  4. Visual

  5. Animation

  6. Misc

.element {
  /* Positioning */
  position: absolute;
  top: 0;
  right: 0;
  z-index: 10;

  /* Box Model */
  display: block;
  width: 100px;
  height: 100px;
  margin: 10px;
  padding: 10px;

  /* Typography */
  font-family: sans-serif;
  font-size: 16px;
  line-height: 1.4;
  text-align: center;

  /* Visual */
  background-color: #fff;
  border: 1px solid #ccc;
  border-radius: 3px;

  /* Animation */
  transition: all 0.3s;

  /* Misc */
  cursor: pointer;
}

Comments#

  1. Section Comments - Use consistent formatting - Describe section purpose - Add visual separation

/* ==========================================================================
   Section Comment Block
   ========================================================================== */

/* Sub-section comment block
   ========================================================================== */

/* Basic comment */
  1. Component Comments - Document component purpose - Note dependencies - Explain complex solutions

/**
 * Component: Card
 * Dependencies: variables.css
 * Description: Basic card component with variants
 */

.card { }

Linting Configuration#

  1. Stylelint Rules - Use stylelint for consistent formatting - Extend recommended configs - Customize for project needs

{
  "extends": "stylelint-config-standard",
  "rules": {
    "indentation": 2,
    "string-quotes": "single",
    "no-duplicate-selectors": true,
    "color-hex-case": "lower",
    "color-hex-length": "short",
    "selector-combinator-space-after": "always",
    "declaration-block-trailing-semicolon": "always",
    "declaration-colon-space-before": "never",
    "declaration-colon-space-after": "always",
    "property-no-vendor-prefix": true,
    "value-no-vendor-prefix": true,
    "number-leading-zero": "always",
    "function-url-quotes": "always"
  }
}
  1. Editor Configuration - Use .editorconfig for basic formatting - Configure IDE/editor settings - Share configurations with team

# .editorconfig
root = true

[*.css]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true