10 CSS Tips That Will Improve Your Code Quality
CSSTipsFrontend

10 CSS Tips That Will Improve Your Code Quality

1. Use CSS Custom Properties for Everything

CSS custom properties (variables) are not just for colors. Use them for your entire design token system: spacing scales, font sizes, border radii, animation durations, Z-index layers, breakpoints. When defined centrally in :root, they become a single source of truth that you can change once and have cascade everywhere.

:root {
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-4: 1rem;
  --space-8: 2rem;
  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 16px;
  --duration-fast: 150ms;
  --duration-normal: 250ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

Unlike preprocessor variables (Sass/Less), CSS custom properties cascade and can be overridden at any point in the tree — making them perfect for component-level theming without JavaScript.

2. Prefer Logical Properties

Instead of margin-left and padding-right, use margin-inline-start and padding-inline-end. Logical properties are relative to the writing mode and text direction, not the physical screen. They automatically adapt to right-to-left languages (Arabic, Hebrew) and vertical writing modes (some CJK layouts).

The translation is straightforward: -left-inline-start, -right-inline-end, -top-block-start, -bottom-block-end. Browser support for logical properties has been excellent since 2021.

3. Use clamp() for Fluid Typography

font-size: clamp(1rem, 2.5vw, 1.5rem) gives you a font size that scales smoothly between a minimum and maximum as the viewport changes, without any media queries. The three arguments are: minimum value, preferred value (usually viewport-relative), maximum value.

This is the modern approach to responsive typography. Instead of three or four breakpoints each overriding font-size, you get a single declaration that handles the entire range. Use the Fluid Type Scale calculator to generate the right values for your type scale.

clamp() works equally well for spacing, element sizes, and any other property you want to scale fluidly:

.container {
  padding-inline: clamp(1rem, 5vw, 4rem);
  max-width: clamp(600px, 90vw, 1200px);
}

4. The :is() Selector Reduces Repetition

Instead of writing h1, h2, h3 { margin-bottom: 1rem; }, use :is(h1, h2, h3) { margin-bottom: 1rem; }. The benefit goes beyond brevity: :is() takes the highest specificity of its arguments, which can simplify your specificity calculations. Its sibling :where() does the same but with zero specificity — ideal for resets.

/* Target headings inside article and main */
:is(article, main) :is(h1, h2, h3) {
  font-family: var(--font-display);
}

5. gap Works on Flexbox Too

Most developers know gap from CSS Grid, but it works equally well on Flexbox. It is far cleaner than adding margin to child elements — you avoid the classic "margin on the last child" problem entirely.

.button-group {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
}

Browser support for gap in flexbox has been universal since 2021. There is no reason to use margin hacks anymore.

6. Use aspect-ratio Instead of the Padding Hack

The old padding-top: 56.25% hack for 16:9 aspect ratios is obsolete. Use aspect-ratio: 16 / 9 directly. It is cleaner, more readable, works with any ratio, and composites correctly with other layout properties.

.video-embed {
  aspect-ratio: 16 / 9;
  width: 100%;
  object-fit: cover;  /* for img and video elements */
}

7. min-height: 100dvh for Full-Screen Layouts

On mobile browsers, 100vh can be larger than the visible viewport because the browser UI (address bar, tab bar) is counted in some implementations. 100dvh (dynamic viewport height) adapts to the actual visible area as the UI shows and hides during scrolling.

Use dvh for full-screen hero sections, app shells, and modals. For safe area padding on mobile (notch, home indicator), combine with environment variables:

.hero {
  min-height: 100dvh;
  padding-bottom: env(safe-area-inset-bottom);
}

8. Layer Your Z-Index with Variables

Magic numbers like z-index: 9999 are a maintenance nightmare that every team eventually faces. Define a clear, named scale at the root level and reference it by name:

:root {
  --z-base: 1;
  --z-raised: 10;
  --z-dropdown: 100;
  --z-sticky: 200;
  --z-modal: 500;
  --z-toast: 900;
  --z-overlay: 1000;
}

When a new component needs stacking, you can see immediately where it belongs in the hierarchy rather than playing the "add another 9" game.

9. Format and Minify Before Committing

Unformatted CSS is hard to review and even harder to maintain. Use PureFormatter's CSS Formatter to clean up any stylesheet — especially third-party CSS you are customizing. Then minify with the CSS Minifier as part of your production build process.

For ongoing projects, configure Prettier and stylelint in your project to enforce formatting on every save and in CI. This removes formatting debates from code reviews entirely.

10. Use @layer for Cascade Management

CSS @layer lets you explicitly control cascade priority, separate from specificity. Layers declared later win over layers declared earlier, regardless of selector specificity. This makes it possible to write utility classes that override component styles without resorting to !important.

@layer reset, base, components, utilities;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
}

@layer utilities {
  .mt-auto { margin-top: auto; }
}

Utilities will always win over components, which always win over base styles — even if the component has a more specific selector. This is the future of CSS architecture, and it is available in all modern browsers today.

Fredy
Written by
Fredy
Senior Developer & Technical Writer

Fredy is a full-stack developer with 8+ years of experience building web applications. He writes about developer tools, best practices, and the craft of clean code.