CSS Best Practices

This guide summarizes practical rules that keep your CSS predictable, scalable, accessible, and fast.

1) Use a Light Reset & Universal Box Sizing


/* Normalize margins and set border-box so padding/border don't expand size */
*, *::before, *::after{ box-sizing: border-box; }
html, body, h1, h2, h3, h4, p, ul, ol{ margin: 0; padding: 0; }
img, video{ max-width: 100%; display: block; }

`border-box` prevents layout surprises when adding padding/borders.

2) Organize with @layer (Cascade Layers)


@layer reset, base, components, utilities;
@layer reset{ /* minimal reset here */ }
@layer base{ body{ font: 16px/1.5 system-ui; } }
@layer components{ .btn{ padding: .6rem 1rem; } }
@layer utilities{ .mt-2{ margin-top: .5rem; } }

Layers set a predictable override order: reset → base → components → utilities.

3) Control Specificity (BEM-style Naming)


/* BEM example: .block__element--modifier */
.card{ border: 1px solid #e5e7eb; border-radius: 10px; }
.card__title{ font-weight: 700; }
.card--featured{ border-color: #90CAF9; background: #E3F2FD; }

Avoid deep selectors like header nav ul li a. Keep selectors short and class-based.

4) Use CSS Variables for Tokens


:root{
  --color-primary: #1E88E5;
  --space-1: 8px; --space-2: 12px;
}
.btn{
  background: var(--color-primary);
  padding: var(--space-1) var(--space-2);
}
Tokens via variables

5) Responsive Sizing with min/max/clamp & Container Queries


h1{ font-size: clamp(20px, 2.8vw, 36px); }
/* Container Query: style based on parent width */
.card{ container-type: inline-size; }
@container (min-width: 380px){
  .card__title{ font-size: 20px; }
}

Resize container

Title grows after 380px container width.

Narrow card

Smaller container keeps smaller title.

6) Accessibility: Focus, Motion, Contrast


/* Visible focus ring only when keyboard focusing */
:focus-visible{ outline: 3px solid #ff9800; outline-offset: 3px; }
/* Respect users who prefer less motion */
@media (prefers-reduced-motion: reduce){
  .anim{ animation: none !important; transition: none !important; }
}
Focusable Button
Hover

Try keyboard Tab to see focus, and set OS “Reduce Motion” to test.

7) Use Logical Properties for RTL/LTR


.card{
  padding-inline: 16px; margin-block: 8px;
}
Logical properties adapt to writing directions (RTL/LTR) automatically.

8) Performance: Animate Cheap Properties


/* Prefer transform/opacity for animations */
.card:hover{ transform: translateY(-4px); opacity: .98; }
/* Use will-change sparingly before interaction */
.card{ will-change: transform; }

Avoid animating layout-affecting properties (width/height/top/left) when possible.

9) Keep Utilities Last to Override Safely


@layer ..., utilities;
@layer utilities{
  .mt-2{ margin-top: .5rem; }
  .text-center{ text-align: center; }
}
Utility classes should safely override components.

10) Debugging Helpers


* { outline: 1px solid rgba(0,0,0,.06); } /* temporary layout outlines */
html{ scroll-behavior: smooth; } /* UX polish (disable under reduced motion) */

Use outlines locally for layout debugging; remove before production.

Quick Checklist:

  • Reset margins, set box-sizing: border-box.
  • Structure CSS with @layer or clear partials (reset/base/components/utilities).
  • Prefer classes (BEM) and keep selectors shallow.
  • Use variables for colors/spacing/typography tokens.
  • Make sizing fluid with clamp() and container queries where useful.
  • Ensure visible focus, adequate color contrast, and respect reduced-motion.
  • Animate transform/opacity, avoid heavy repaint/reflow.
  • Adopt logical properties for internationalization.