CSS Tips

Modern CSS Tips & Tricks

A curated collection of modern CSS features every frontend developer should know. Container queries, cascade layers, :has(), and more — each with a real code example.

20

Tips

6

Categories

Free

Always

Devanshu Verma

Devanshu Verma

Sharing CSS & frontend tips weekly

Follow
LayoutBaseline 2023

Container Queries

Respond to a container's own size instead of the viewport. Build truly portable components that adapt wherever they're placed.

.wrapper {
  container-type: inline-size;
  container-name: card;
}

@container card (min-width: 480px) {
  .card {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 1rem;
  }
}
LayoutBaseline 2023

CSS Grid Subgrid

Let nested grid items snap to the parent's tracks. Solves the classic 'cards with misaligned footers' problem without JavaScript.

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
}

.card {
  display: grid;
  grid-row: span 3;
  /* Inherit parent row sizes */
  grid-template-rows: subgrid;
}
LayoutWidely available

CSS Grid auto-fit vs auto-fill

auto-fit collapses empty tracks so columns stretch to fill space. auto-fill keeps them. Use auto-fit for responsive grids with zero media queries.

/* Columns stretch to fill — no media queries needed */
.responsive-grid {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
}

/* Empty slots remain (useful for fixed layouts) */
.fixed-slots {
  grid-template-columns:
    repeat(auto-fill, minmax(260px, 1fr));
}
LayoutWidely available

aspect-ratio

Lock element proportions in one line. Replaces the old padding-top percentage hack entirely.

.embed   { aspect-ratio: 16 / 9; width: 100%; }
.avatar  { aspect-ratio: 1;       width: 3rem; }
.card-img { aspect-ratio: 4 / 3; }
.golden  { aspect-ratio: 1.618; }

/* Works with object-fit too */
img.cover {
  aspect-ratio: 16 / 9;
  object-fit: cover;
  width: 100%;
}
LayoutWidely available

CSS Logical Properties

Use flow-relative props instead of directional ones. Layouts mirror automatically for RTL languages — no extra CSS needed.

/* Logical — works in any writing mode */
.card {
  margin-inline-start: 1rem;
  padding-block-start: 1.5rem;
  border-inline-end: 4px solid;
}

/* No [dir="rtl"] override needed — ever */

/* Shorthand */
.box {
  margin-inline: auto;   /* left & right */
  padding-block: 2rem;   /* top & bottom */
}
SelectorsBaseline 2023

:has() — The Parent Selector

Select an element based on its descendants. The most requested CSS feature in history — now universally supported.

/* Card layout shifts when it has an image */
.card:has(img) {
  display: grid;
  grid-template-columns: 120px 1fr;
}

/* Disable submit when form has invalid input */
form:has(input:invalid) .btn-submit {
  opacity: 0.5;
  pointer-events: none;
}

/* Dark nav when hero is visible */
:has(.hero:in-viewport) nav {
  color: white;
}
SelectorsBaseline 2024

CSS Nesting

Write nested rules natively — no Sass or PostCSS needed. Use & to reference the parent and keep related styles together.

.button {
  padding: .5rem 1rem;
  background: oklch(55% 0.18 85);

  &:hover {
    background: oklch(45% 0.18 85);
    translate: 0 -2px;
  }

  &.large {
    padding: .75rem 1.5rem;
    font-size: 1.125rem;
  }

  & .icon {
    margin-inline-end: .5rem;
  }
}
SelectorsWidely available

:is() and :where()

:is() groups selectors and keeps the highest specificity of the list. :where() does the same but with zero specificity — ideal for resets.

/* Clean with :is() */
h1 a, h2 a, h3 a, h4 a { color: inherit; }

/* Clean with :is() */
:is(h1, h2, h3, h4) a { color: inherit; }

/* :where() = zero specificity, easy to override */
:where(h1, h2, h3, h4) {
  line-height: 1.2;
  margin-block-end: .5em;
}

/* Combine both */
:is(article, section) :where(h2, h3) {
  font-size: clamp(1.25rem, 3vw, 2rem);
}
VariablesWidely available

Cascade Layers (@layer)

Control specificity at the layer level. Layers declared earlier always lose — no more specificity wars with third-party CSS.

/* Declare order upfront — first = lowest priority */
@layer reset, base, components, utilities;

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

@layer components {
  .btn { padding: .5rem 1rem; background: blue; }
}

/* Utilities always win regardless of specificity */
@layer utilities {
  .mt-4 { margin-top: 1rem !important; }
}
VariablesBaseline 2024

@property — Typed Custom Properties

Register CSS variables with a type and initial value. Unlocks smooth animation of properties that were previously unanimatable.

@property --hue {
  syntax: "<number>";
  initial-value: 0;
  inherits: false;
}

.swatch {
  background: hsl(var(--hue), 70%, 55%);
  transition: --hue 0.6s ease;
}
.swatch:hover { --hue: 220; }

/* Also works for gradients! */
@property --stop {
  syntax: "<percentage>";
  initial-value: 0%;
  inherits: false;
}
VariablesWidely available

CSS Custom Properties + calc()

Custom properties are more than static variables. Combine them with calc() to build a single-source-of-truth design system.

:root {
  --space: 0.25rem;
  --cols: 12;
  --gap: calc(var(--space) * 4);
  --radius-base: 0.5rem;
  --radius-lg: calc(var(--radius-base) * 2);
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  gap: var(--gap);
}

@media (max-width: 768px) {
  :root { --cols: 4; }
}
TypographyWidely available

clamp() — Fluid Typography

Fluid font sizes and spacing that scale smoothly between a min and max — no breakpoints, no JavaScript.

/* clamp(minimum, preferred, maximum) */

h1 {
  /* 2rem on mobile → 4.5rem on wide screens */
  font-size: clamp(2rem, 5vw + 1rem, 4.5rem);
  line-height: clamp(1.1, 1.2 + 0.3vw, 1.35);
}

section {
  padding: clamp(2rem, 8vw, 6rem);
}

.container {
  width: min(90%, 1280px);
  margin-inline: auto;
}
TypographyBaseline 2024

text-wrap: balance & pretty

balance distributes words evenly across lines for headings. pretty prevents orphaned last words in paragraphs. Both with one property.

/* Even line lengths for headings */
h1, h2, h3 {
  text-wrap: balance;
  /* Browser limit: max 4 lines */
}

/* No orphaned words at end of paragraphs */
p, li {
  text-wrap: pretty;
}

/* Before: needed ugly hacks like this */
/* h1 { max-width: 28ch; } */
Visual EffectsWidely available

backdrop-filter

Apply blur, brightness, and saturation to whatever is behind an element. The foundation of modern glassmorphism UI.

.glass {
  background: rgb(255 255 255 / 0.1);
  backdrop-filter: blur(16px) saturate(180%);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  border: 1px solid rgb(255 255 255 / 0.2);
  border-radius: 1rem;
}

.frosted-nav {
  backdrop-filter: blur(24px) brightness(0.85);
  background: rgb(0 0 0 / 0.25);
}
Visual EffectsBaseline 2023

color-mix()

Mix two colors in any color space directly in CSS. Generate tints, shades, and transparent variants from a single token.

:root {
  --brand: #ca8a04;

  /* 20% white = tint */
  --brand-light:
    color-mix(in oklch, var(--brand) 80%, white);

  /* 30% black = shade */
  --brand-dark:
    color-mix(in oklch, var(--brand) 70%, black);

  /* Transparent variant */
  --brand-alpha:
    color-mix(in srgb, var(--brand) 15%, transparent);
}
Visual EffectsWidely available

accent-color

Theme all native form controls — checkboxes, radios, range sliders, progress bars — with one line. No custom component needed.

/* Global brand accent on all controls */
:root {
  accent-color: #ca8a04;
}

/* Or target specific elements */
input[type="checkbox"],
input[type="radio"] {
  accent-color: #ca8a04;
  width: 1.2rem;
  height: 1.2rem;
}

input[type="range"],
progress { accent-color: #ca8a04; }
PerformanceWidely available

Scroll Snap

Smooth scroll-stop points with zero JavaScript. Perfect for carousels, image galleries, and full-screen sections.

/* Horizontal carousel */
.carousel {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  display: flex;
  gap: 1rem;
  scrollbar-width: none;
}
.slide {
  scroll-snap-align: start;
  flex: 0 0 300px;
}

/* Full-screen vertical sections */
.page {
  scroll-snap-type: y mandatory;
  height: 100vh;
  overflow-y: scroll;
}
PerformanceWidely available

overscroll-behavior

Stop scroll chaining — the UX bug where scrolling inside a modal also scrolls the page. One line, no JS needed.

/* Modal: don't scroll the page when it ends */
.modal {
  overflow-y: auto;
  overscroll-behavior-y: contain;
}

/* PWA: disable pull-to-refresh */
body {
  overscroll-behavior-y: none;
}

/* Carousel: no horizontal bounce */
.carousel {
  overscroll-behavior-x: contain;
}
PerformanceBaseline 2024

content-visibility: auto

Tell the browser to skip rendering off-screen content entirely. Can cut initial render time by 50%+ on content-heavy pages.

.article-section {
  content-visibility: auto;

  /* Hint at rendered height to
     prevent layout shifts */
  contain-intrinsic-size: 0 500px;
}

/* Works great for long lists too */
.list-item {
  content-visibility: auto;
  contain-intrinsic-size: 0 80px;
}
LayoutWidely available

grid-template-areas

Name your grid regions for visual, readable layout code. Rearranging the layout for different breakpoints is as easy as editing a string.

.page {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar main  "
    "footer footer ";
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

header { grid-area: header; }
aside  { grid-area: sidebar; }
main   { grid-area: main;   }
footer { grid-area: footer; }

Want all 20 tips in one file?

Download the full PDF — great for offline reference.

© 2026 Devanshu Verma. All rights reserved.