CSS Naming Conventions
The complete guide to kebab-case, BEM, and CSS class naming best practices
CSS Naming at a Glance:
- Classes: kebab-case →
.user-profile-card - IDs: kebab-case →
#main-navigation - BEM: Block__Element--Modifier →
.card__title--large - Custom Properties: kebab-case →
--primary-color
Why CSS Naming Matters
Good CSS naming conventions make your stylesheets more maintainable, readable, and scalable. They prevent naming conflicts, make debugging easier, and help teams collaborate effectively. Poor naming leads to specificity wars, unexpected style overrides, and technical debt.
1. kebab-case: The Standard
CSS classes and IDs should use kebab-case (lowercase with hyphens): words are lowercase and separated by hyphens.
/* ✅ Good - kebab-case */
.user-profile { }
.navigation-menu { }
.button-primary { }
.card-header-title { }
.form-input-error { }
/* ❌ Bad - Other conventions */
.userProfile { } /* camelCase (JavaScript style) */
.user_profile { } /* snake_case (Python style) */
.UserProfile { } /* PascalCase */
.USERPROFILE { } /* all caps */Why kebab-case?
- CSS standard: Hyphen is the convention across CSS community
- Readable in HTML: Easy to spot in markup
- No conflicts: Hyphens can't be used in JavaScript identifiers
- SEO-friendly: Similar to URL naming conventions
2. BEM (Block Element Modifier)
BEM is a popular naming methodology that creates a clear relationship between HTML and CSS, making code more predictable and maintainable.
BEM Syntax
.block { } /* Independent component */
.block__element { } /* Part of a block */
.block--modifier { } /* Variation of a block */
.block__element--modifier { } /* Variation of an element */BEM Example: Card Component
/* Block: Independent component */
.card {
border: 1px solid #ddd;
padding: 20px;
border-radius: 8px;
}
/* Elements: Parts of the card */
.card__header {
font-size: 24px;
font-weight: bold;
margin-bottom: 10px;
}
.card__body {
font-size: 16px;
line-height: 1.5;
}
.card__footer {
margin-top: 20px;
border-top: 1px solid #eee;
padding-top: 10px;
}
/* Modifiers: Variations */
.card--featured {
border-color: blue;
background: #f0f8ff;
}
.card--compact {
padding: 10px;
}
.card__header--large {
font-size: 32px;
}BEM in HTML
<!-- Standard card -->
<div class="card">
<h2 class="card__header">Card Title</h2>
<p class="card__body">Card content goes here.</p>
<div class="card__footer">Card footer</div>
</div>
<!-- Featured card with large header -->
<div class="card card--featured">
<h2 class="card__header card__header--large">Featured Card</h2>
<p class="card__body">Special content.</p>
<div class="card__footer">Card footer</div>
</div>3. Common CSS Naming Patterns
Utility Classes
/* Descriptive utility classes */
.text-center { text-align: center; }
.text-bold { font-weight: bold; }
.margin-top-large { margin-top: 32px; }
.padding-small { padding: 8px; }
.display-none { display: none; }
.color-primary { color: #007bff; }
/* Tailwind-style (also valid) */
.mt-4 { margin-top: 1rem; }
.text-xl { font-size: 1.25rem; }
.font-bold { font-weight: bold; }State Classes
/* State indicators */
.is-active { }
.is-disabled { }
.is-hidden { }
.is-loading { }
.is-valid { }
.is-invalid { }
/* Example usage */
.button {
background: blue;
color: white;
}
.button.is-disabled {
background: gray;
cursor: not-allowed;
opacity: 0.6;
}JavaScript Hooks
/* Prefix with js- to indicate JavaScript dependency */
.js-modal-trigger { }
.js-dropdown-toggle { }
.js-scroll-to-top { }
/* Never style js- classes */
.js-modal-trigger {
/* ❌ Bad: Don't add styles to JS hooks */
}
/* Use separate classes for styling */
<button class="button button-primary js-modal-trigger">
Open Modal
</button>4. Component-Based Naming
Namespacing Components
/* Navigation component */
.nav { }
.nav-list { }
.nav-item { }
.nav-link { }
.nav-link-active { }
/* Header component */
.header { }
.header-logo { }
.header-menu { }
.header-search { }
/* Footer component */
.footer { }
.footer-links { }
.footer-social { }
.footer-copyright { }5. Custom Properties (CSS Variables)
CSS custom properties should use kebab-case with double dashes as prefix.
:root {
/* ✅ Good - kebab-case */
--primary-color: #007bff;
--secondary-color: #6c757d;
--font-family-base: "Helvetica Neue", sans-serif;
--spacing-small: 8px;
--spacing-medium: 16px;
--spacing-large: 32px;
--border-radius: 4px;
--transition-speed: 0.3s;
}
/* Usage */
.button {
background: var(--primary-color);
padding: var(--spacing-medium);
border-radius: var(--border-radius);
transition: all var(--transition-speed);
}
/* ❌ Bad - Other conventions */
:root {
--primaryColor: blue; /* camelCase */
--Primary_Color: blue; /* mixed */
--PRIMARYCOLOR: blue; /* all caps */
}6. SMACSS (Scalable and Modular Architecture)
SMACSS categorizes CSS rules into five types, each with its own naming convention:
Base Rules
/* No class names - element selectors */
body { font-family: sans-serif; }
h1, h2, h3 { margin-top: 0; }
a { color: blue; text-decoration: none; }Layout Rules (Prefix with l-)
.l-header { }
.l-sidebar { }
.l-content { }
.l-footer { }
.l-grid { }
.l-container { }Module Rules (Component names)
.card { }
.button { }
.nav { }
.modal { }
.alert { }State Rules (Prefix with is- or has-)
.is-active { }
.is-hidden { }
.is-collapsed { }
.has-error { }
.has-warning { }Theme Rules (Prefix with theme-)
.theme-dark { }
.theme-light { }
.theme-high-contrast { }7. ID vs Class Naming
/* Classes: Reusable, low specificity (preferred) */
.button { }
.card { }
.nav-item { }
/* IDs: Unique, high specificity (use sparingly) */
#main-header { }
#page-content { }
#site-footer { }
/* ❌ Avoid styling with IDs */
#submit-button {
background: blue; /* Too specific, hard to override */
}
/* ✅ Better: Use classes for styling */
.submit-button {
background: blue;
}
/* IDs are good for:
- JavaScript hooks
- Fragment links (#section-name)
- Form labels (for attribute)
*/8. Responsive Naming
/* Mobile-first approach */
.grid { }
.grid-mobile-full { }
.grid-tablet-half { }
.grid-desktop-third { }
/* Or use modifiers */
.text-center { }
.text-center-mobile { }
.text-left-tablet { }
/* Tailwind-style breakpoint prefixes */
.sm-hidden { } /* hidden on small screens */
.md-flex { } /* flex on medium screens */
.lg-grid { } /* grid on large screens */9. Common Mistakes to Avoid
- ❌ Using camelCase:
.userProfileCard - ❌ Using underscores:
.user_profile_card - ❌ Over-nesting:
.header .nav .list .item .link(too specific) - ❌ Non-descriptive names:
.box1,.item2 - ❌ Styling IDs:
#header {}(too specific) - ❌ Using !important: Indicates poor specificity management
10. CSS Naming Best Practices
- Be consistent: Pick one methodology (BEM, SMACSS) and stick with it
- Be descriptive:
.primary-navigationover.nav - Avoid presentational names:
.error-messageover.red-text - Keep specificity low: Prefer single class selectors
- Use kebab-case: The CSS standard convention
- Namespace components: Prevent naming conflicts
- Separate structure from skin:
.card+.card--blue
11. Framework Conventions
Bootstrap
.btn { }
.btn-primary { }
.btn-lg { }
.form-control { }
.navbar-nav { }
.card-header { }Tailwind CSS
.flex { }
.items-center { }
.justify-between { }
.text-xl { }
.font-bold { }
.bg-blue-500 { }
.hover:bg-blue-700 { }12. Tools & Linters
/* stylelint configuration */
{
"rules": {
"selector-class-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
"selector-id-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
"custom-property-pattern": "^[a-z][a-z0-9]*(-[a-z0-9]+)*$",
"selector-max-id": 0,
"selector-max-specificity": "0,3,0"
}
}
/* Install and run */
npm install --save-dev stylelint
npx stylelint "**/*.css"Comparison Table
| Methodology | Example | Best For |
|---|---|---|
| Simple kebab-case | .user-card-title | Small projects |
| BEM | .card__title--large | Large projects |
| SMACSS | .l-header, .is-active | Enterprise apps |
| Utility-first | .text-center, .mt-4 | Rapid development |
Need to Convert Text?
Use our free converter to transform text to CSS-style kebab-case:
Conclusion
CSS naming conventions are essential for maintainable stylesheets. Use kebab-case as the standard, consider BEM for component-based architecture, and follow SMACSS for large-scale applications. Keep specificity low, be descriptive, and stay consistent. Good naming makes your CSS predictable, debuggable, and a joy to work with.