• Tutorials
  • Modern CSS Features - Part 1

    Views93

    Modern CSS has evolved dramatically over the past few years, shipping features that previously required JavaScript or preprocessors. Here's a look at some of the most impactful additions.


    #Container Queries

    For years, responsive design meant reacting to the viewport width. Container queries change that by letting elements respond to the size of their parent container instead.

     1.card-wrapper {
     2  container-type: inline-size;
     3  container-name: card;
     4}
     5
     6@container card (min-width: 400px) {
     7  .card {
     8    display: grid;
     9    grid-template-columns: 1fr 2fr;
    10  }
    11}
    

    This is a fundamental shift — a component can now be truly self-contained and layout-aware, regardless of where it's placed on the page.

    Browser support: All major browsers as of late 2023.


    #The :has() Selector

    Often called the "parent selector," :has() lets you style an element based on what it contains.

     1/* Style a form group that contains an invalid input */
     2.form-group:has(input:invalid) {
     3  border-color: red;
     4}
     5
     6/* Style a card that has an image */
     7.card:has(img) {
     8  padding: 0;
     9}
    10
    11/* Style a label whose sibling input is checked */
    12label:has(+ input:checked) {
    13  font-weight: bold;
    14}
    

    Before :has(), achieving this required JavaScript to add and remove classes manually. It's one of the most powerful selectors ever added to CSS.

    Browser support: All major browsers as of December 2023.


    #CSS Nesting

    Native CSS nesting, inspired by Sass, is now supported without a build step.

     1.button {
     2  background: blue;
     3  color: white;
     4
     5  &:hover {
     6    background: darkblue;
     7  }
     8
     9  &.disabled {
    10    opacity: 0.5;
    11    pointer-events: none;
    12  }
    13
    14  .icon {
    15    margin-right: 8px;
    16  }
    17}
    

    The & refers to the parent selector. Nesting without & (like .icon above) is also valid and targets descendants.

    Browser support: All major browsers as of late 2023.


    #CSS Cascade Layers

    @layer gives you explicit control over the cascade, solving the specificity arms race in large codebases.

     1@layer reset, base, components, utilities;
     2
     3@layer reset {
     4  * { box-sizing: border-box; margin: 0; }
     5}
     6
     7@layer base {
     8  a { color: blue; }
     9}
    10
    11@layer utilities {
    12  .mt-4 { margin-top: 1rem; }
    13}
    

    Styles in a later layer always win over styles in an earlier layer, regardless of specificity. Styles outside any layer beat all layered styles.

    This makes third-party CSS, design tokens, and utility classes much easier to manage without resorting to !important.

    Browser support: All major browsers since 2022.


    #The color-mix() Function

    Mix two colors directly in CSS without a preprocessor.

     1:root {
     2  --brand: #3b82f6;
     3  --brand-light: color-mix(in srgb, var(--brand) 30%, white);
     4  --brand-dark: color-mix(in srgb, var(--brand) 70%, black);
     5}
     6
     7.button {
     8  background: var(--brand);
     9}
    10
    11.button:hover {
    12  background: var(--brand-dark);
    13}
    

    The in srgb part specifies the color space. You can also use in oklch, which produces more perceptually uniform results — particularly useful for generating accessible color scales.

    Browser support: All major browsers since 2023.


    #Logical Properties

    Logical properties replace physical directions (left, right, top, bottom) with writing-mode-relative ones (inline-start, inline-end, block-start, block-end). This makes layouts work correctly in right-to-left and vertical writing modes without extra overrides.

     1/* Instead of this */
     2.element {
     3  margin-left: 1rem;
     4  padding-top: 2rem;
     5  border-right: 1px solid;
     6}
     7
     8/* Use this */
     9.element {
    10  margin-inline-start: 1rem;
    11  padding-block-start: 2rem;
    12  border-inline-end: 1px solid;
    13}
    

    Shorthand versions are also available:

     1.element {
     2  margin-inline: 1rem;     /* left and right */
     3  padding-block: 2rem;     /* top and bottom */
     4  inset-inline: 0;         /* left: 0; right: 0 */
     5}
    

    Browser support: All major browsers, widely available since 2021–2022.


    #@property — Custom Property Types

    @property lets you define typed CSS custom properties with default values and inheritance control. The most powerful use case is animating properties that CSS wouldn't otherwise know how to interpolate.

     1@property --gradient-angle {
     2  syntax: "<angle>";
     3  initial-value: 0deg;
     4  inherits: false;
     5}
     6
     7.spinner {
     8  background: conic-gradient(from var(--gradient-angle), blue, red, blue);
     9  animation: spin 2s linear infinite;
    10}
    11
    12@keyframes spin {
    13  to { --gradient-angle: 360deg; }
    14}
    

    Without @property, animating a custom property inside a gradient would not work — the browser wouldn't know it's an angle. Declaring the type makes the interpolation possible.

    Browser support: All major browsers since 2023.


    #What's Coming Next

    Part 2 will cover:

    • @starting-style — animate elements as they enter the DOM
    • anchor() positioning — tether floating elements to any anchor
    • light-dark() — inline light/dark theming without media queries
    • Scroll-driven animations — tie animation progress to scroll position, no JavaScript needed

    All browser support notes refer to evergreen browsers as of early 2025. For production use, always verify on caniuse.com.

    profile image of Petar Vasilev

    Petar Vasilev

    Petar is a web developer at Mitkov Systems GmbH. He is fascinated with the web. Works with Laravel and its ecosystem. Loves learning new stuff.

    More posts from Petar Vasilev