Web Development /CSS — Styling Modern Websites / Lesson
Web Development

CSS Variables, Functions and Modern Styling

Learn how to create maintainable modern CSS using custom properties, CSS functions, calc(), min(), max(), clamp(), color functions, logical properties, nesting, modern selectors, and reusable design systems.

🎯

Learning Objectives

["Understand CSS custom properties and how they differ from ordinary CSS declarations.","Create reusable global and component-level CSS variables.","Understand inheritance and the cascade when using CSS custom properties.","Use var() to consume custom property values.","Provide fallback values for CSS variables.","Use calc() for dynamic CSS calculations.","Use min(), max(), and clamp() for responsive sizing.","Use modern color functions such as rgb(), hsl(), hwb(), and color-mix().","Understand CSS logical properties such as margin-inline and padding-block.","Use modern CSS selectors such as :is(), :where(), and :has().","Understand CSS nesting and how it can improve component organization.","Build reusable design tokens for colors, spacing, typography, and borders.","Create scalable light and dark themes using CSS variables.","Improve CSS maintainability through reusable patterns.","Build a practical modern Dwallnet Academy interface using modern CSS techniques."]

📖

Lesson Content

Introduction to Modern CSS

CSS has developed significantly beyond the basic styling techniques used in the early days of the web. Modern CSS provides developers with powerful tools for creating scalable, reusable, responsive, and maintainable interfaces.

Some of the most useful modern CSS features include:

  • CSS custom properties.
  • var().
  • calc().
  • min().
  • max().
  • clamp().
  • Modern color functions.
  • Logical properties.
  • Modern selectors.
  • CSS nesting.
  • Container queries.
  • Reusable design tokens.

These features make it possible to create a CSS architecture that is easier to understand, update, and scale.

What Are CSS Custom Properties?

CSS custom properties are variables defined directly in CSS.

They are commonly called CSS variables.

A custom property begins with two hyphens:

:root {
    --primary-color: #0b3b82;
    --text-color: #172033;
}

The values can then be reused throughout the stylesheet.

body {
    color: var(--text-color);
}

.button {
    background: var(--primary-color);
}

This means that if the primary color changes later, you can update the variable rather than searching through the entire stylesheet for every occurrence of the old color.

The :root Selector

The :root selector represents the root element of the document.

It is commonly used to define global CSS variables.

:root {
    --primary: #0b3b82;
    --secondary: #1266c4;
    --surface: #ffffff;
    --text: #172033;
    --muted: #64748b;
}

These variables can then be used throughout the document.

Using var()

The var() function retrieves the value of a custom property.

:root {
    --primary: #0b3b82;
}

.button {
    background: var(--primary);
}

Using variables creates consistency throughout a website.

Fallback Values

You can provide a fallback value in case a custom property is not available or has an invalid value.

.button {
    background: var(--primary, #0b3b82);
}

If --primary is unavailable, the browser uses #0b3b82.

Component-Level Variables

Variables do not have to be global. They can be defined inside individual components.

.course-card {
    --card-padding: 1.5rem;
    --card-radius: 16px;

    padding: var(--card-padding);
    border-radius: var(--card-radius);
}

This is useful when a component has its own internal design values.

CSS Variable Inheritance

Custom properties participate in CSS inheritance.

.academy {
    --accent: #0b3b82;
}

.academy-button {
    background: var(--accent);
}

The child element can access the variable defined by its ancestor.

Changing Variables Dynamically

One of the major advantages of CSS variables is that they can be changed dynamically.

:root {
    --surface: #ffffff;
    --text: #172033;
}

.dark {
    --surface: #101827;
    --text: #f8fafc;
}

body {
    background: var(--surface);
    color: var(--text);
}

Applying the dark class changes the values used by the interface.

Creating a Design System

CSS variables are useful for creating a small design system.

:root {
    --color-primary: #0b3b82;
    --color-secondary: #1266c4;
    --color-accent: #38bdf8;

    --color-surface: #ffffff;
    --color-background: #f4f7fb;
    --color-text: #172033;
    --color-muted: #64748b;

    --space-xs: 0.25rem;
    --space-sm: 0.5rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2rem;

    --radius-sm: 6px;
    --radius-md: 12px;
    --radius-lg: 20px;
}

This makes the visual language of the website consistent.

The calc() Function

The calc() function allows CSS to perform calculations.

.content {
    width: calc(100% - 2rem);
}

It can combine different units.

.sidebar {
    width: 280px;
}

.main {
    width: calc(100% - 280px);
}

This can be useful when creating layouts that combine fixed and flexible dimensions.

Using calc() With Variables

CSS variables can be combined with calculations.

:root {
    --container-padding: 1rem;
}

.section {
    width: calc(100% - (var(--container-padding) * 2));
}

The min() Function

The min() function allows CSS to select the smallest value from a list of values.

.container {
    width: min(92%, 1200px);
}

This is a very useful pattern for responsive containers.

The max() Function

The max() function selects the largest value.

.section {
    padding-left: max(1rem, 4vw);
}

This can prevent spacing from becoming too small while still allowing it to grow on larger screens.

The clamp() Function

The clamp() function allows a value to grow or shrink between a minimum and maximum.

h1 {
    font-size: clamp(2rem, 5vw, 4rem);
}

The three values represent:

  1. Minimum value.
  2. Preferred flexible value.
  3. Maximum value.

This is especially useful for responsive typography and spacing.

Responsive Spacing With clamp()

.hero {
    padding-block: clamp(3rem, 8vw, 8rem);
}

The spacing can adapt to the viewport while remaining within defined limits.

Modern CSS Color Functions

CSS supports several ways of defining colors.

Traditional hexadecimal notation:

color: #0b3b82;

RGB:

color: rgb(11 59 130);

RGB with alpha:

background: rgb(11 59 130 / 0.8);

HSL:

color: hsl(215 84% 28%);

Modern CSS color functions can make color manipulation more flexible.

color-mix()

The color-mix() function can combine colors.

.button:hover {
    background: color-mix(
        in srgb,
        var(--primary) 85%,
        white
    );
}

This can be useful for creating hover colors from existing design tokens.

Logical Properties

Traditional CSS properties often refer directly to physical directions such as left and right.

margin-left: 1rem;
margin-right: 1rem;

Logical properties describe layout according to writing direction.

margin-inline: 1rem;

Similarly:

padding-block: 2rem;
padding-inline: 1rem;

Common logical properties include:

  • margin-inline
  • margin-block
  • padding-inline
  • padding-block
  • inset-inline
  • inset-block

Logical properties are particularly useful when supporting different writing directions.

Modern CSS Selectors

Modern CSS includes selectors that can reduce repetitive code.

The :is() Selector

The :is() pseudo-class allows several selectors to share the same rules.

.card :is(h2, h3, h4) {
    margin-block-start: 0;
}

This avoids writing separate selectors for each heading.

The :where() Selector

The :where() pseudo-class works similarly to :is(), but its specificity is zero.

.card :where(h2, h3, h4) {
    margin-block-start: 0;
}

This can be useful when creating reusable component styles that should be easy to override.

The :has() Selector

The :has() pseudo-class allows CSS to style an element based on what it contains.

.card:has(img) {
    padding-top: 0;
}

This means that a card containing an image can receive a different style.

CSS Nesting

Modern CSS supports nesting rules directly inside another rule.

.card {
    padding: 1.5rem;

    & h2 {
        margin-top: 0;
    }

    &:hover {
        transform: translateY(-4px);
    }
}

Nesting can make component styles easier to organize when used carefully.

Modern CSS Architecture

A large stylesheet can become difficult to maintain if values are repeated everywhere.

Modern CSS encourages developers to create reusable systems for:

  • Colors.
  • Typography.
  • Spacing.
  • Border radius.
  • Shadows.
  • Container widths.
  • Transitions.
  • Component states.

Design Tokens

Design tokens are reusable values that represent decisions in a design system.

:root {
    --color-primary: #0b3b82;
    --color-accent: #38bdf8;

    --font-size-sm: 0.875rem;
    --font-size-md: 1rem;
    --font-size-lg: 1.5rem;

    --radius-sm: 6px;
    --radius-md: 12px;

    --shadow-sm: 0 4px 12px rgb(0 0 0 / 0.08);
    --shadow-md: 0 12px 30px rgb(0 0 0 / 0.12);

    --transition-fast: 180ms ease;
    --transition-normal: 300ms ease;
}

Components can then use these values consistently.

Theme Switching

CSS variables make theme switching much easier.

:root {
    --background: #f4f7fb;
    --surface: #ffffff;
    --text: #172033;
    --primary: #0b3b82;
}

[data-theme="dark"] {
    --background: #0f172a;
    --surface: #111827;
    --text: #f8fafc;
    --primary: #60a5fa;
}

body {
    background: var(--background);
    color: var(--text);
}

.card {
    background: var(--surface);
}

JavaScript can then change the data-theme attribute to switch between themes.

Modern Shadows

Shadows can also be stored as reusable variables.

:root {
    --shadow-card:
        0 10px 30px rgb(0 0 0 / 0.08);
}

.card {
    box-shadow: var(--shadow-card);
}

Modern Border Radius

Consistent corner rounding can be managed with variables.

:root {
    --radius-card: 16px;
    --radius-button: 8px;
}

.card {
    border-radius: var(--radius-card);
}

.button {
    border-radius: var(--radius-button);
}

Reusable Container Pattern

A modern website can define a reusable container class:

.container {
    width: min(92%, 1200px);
    margin-inline: auto;
}

This can then be reused throughout the entire website.

Modern Section Pattern

.section {
    padding-block: clamp(3rem, 7vw, 7rem);
}

.section-title {
    font-size: clamp(1.8rem, 4vw, 3rem);
    margin-block-end: 1rem;
}

This creates responsive spacing and typography without requiring many breakpoints.

Using CSS Variables With Components

Consider a reusable button component:

.button {
    --button-bg: var(--color-primary);
    --button-color: #ffffff;
    --button-padding: 0.8rem 1.2rem;
    --button-radius: var(--radius-md);

    display: inline-block;
    padding: var(--button-padding);
    background: var(--button-bg);
    color: var(--button-color);
    border-radius: var(--button-radius);
}

A variation can override only the variables it needs:

.button-secondary {
    --button-bg: var(--color-secondary);
}

This makes component variations easier to manage.

CSS Variables and JavaScript

JavaScript can read and modify CSS variables.

document.documentElement.style.setProperty(
    '--color-primary',
    '#1266c4'
);

This allows interactive applications to modify themes, colors, sizes, and other design values dynamically.

Reading a CSS Variable With JavaScript

const styles = getComputedStyle(document.documentElement);

const primaryColor = styles
    .getPropertyValue('--color-primary')
    .trim();

console.log(primaryColor);

This can be useful when JavaScript needs to work with values defined by the CSS design system.

Modern CSS and Maintainability

The goal of modern CSS is not to use every new feature simply because it exists.

Instead, choose features that make your stylesheet:

  • Easier to understand.
  • Easier to reuse.
  • Easier to maintain.
  • More responsive.
  • More consistent.
  • More accessible.

Common Mistakes With CSS Variables

1. Creating Too Many Variables

Not every single CSS value needs to become a variable. Create variables for values that represent reusable design decisions.

2. Poor Variable Names

Names such as --blue1 or --value2 provide little meaning.

Prefer semantic names such as:

--color-primary
--color-surface
--color-text
--space-lg
--radius-card

3. Ignoring Fallbacks

When appropriate, provide fallback values for important variables.

color: var(--text-color, #172033);

4. Overusing Nesting

Deep nesting can make CSS difficult to understand. Keep component structures reasonably shallow.

Complete Modern CSS Example

The following example demonstrates variables, responsive functions, modern selectors, transitions, themes, and reusable components.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">

    <meta
        name="viewport"
        content="width=device-width, initial-scale=1.0"
    >

    <title>Dwallnet Academy</title>

    <style>
        :root {
            --color-primary: #0b3b82;
            --color-secondary: #1266c4;
            --color-accent: #38bdf8;

            --color-background: #f4f7fb;
            --color-surface: #ffffff;
            --color-text: #172033;
            --color-muted: #64748b;

            --space-sm: 0.5rem;
            --space-md: 1rem;
            --space-lg: 1.5rem;
            --space-xl: 2rem;

            --radius-sm: 6px;
            --radius-md: 12px;
            --radius-lg: 20px;

            --shadow-card:
                0 10px 30px rgb(0 0 0 / 0.08);

            --transition-fast: 180ms ease;
            --transition-normal: 300ms ease;
        }

        [data-theme="dark"] {
            --color-background: #0f172a;
            --color-surface: #111827;
            --color-text: #f8fafc;
            --color-muted: #cbd5e1;
            --color-primary: #60a5fa;

            --shadow-card:
                0 10px 30px rgb(0 0 0 / 0.3);
        }

        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            font-family: Arial, sans-serif;
            background: var(--color-background);
            color: var(--color-text);
            transition:
                background var(--transition-normal),
                color var(--transition-normal);
        }

        img {
            max-width: 100%;
            height: auto;
            display: block;
        }

        .container {
            width: min(92%, 1200px);
            margin-inline: auto;
        }

        .section {
            padding-block:
                clamp(3rem, 7vw, 7rem);
        }

        .hero {
            background: var(--color-primary);
            color: #ffffff;
        }

        .hero h1 {
            font-size:
                clamp(2rem, 6vw, 4.5rem);
            line-height: 1.05;
        }

        .hero p {
            max-width: 650px;
        }

        .courses {
            display: grid;
            grid-template-columns:
                repeat(
                    auto-fit,
                    minmax(230px, 1fr)
                );

            gap: var(--space-lg);
        }

        .card {
            padding: var(--space-lg);
            background: var(--color-surface);
            border-radius: var(--radius-lg);
            box-shadow: var(--shadow-card);

            transition:
                transform var(--transition-normal),
                box-shadow var(--transition-normal);

            &:hover {
                transform: translateY(-6px);
            }

            & :is(h2, h3) {
                margin-block-start: 0;
            }

            &:has(img) {
                overflow: hidden;
            }
        }

        .button {
            display: inline-block;
            padding:
                var(--space-sm)
                var(--space-lg);

            background: var(--color-primary);
            color: #ffffff;

            border-radius:
                var(--radius-md);

            text-decoration: none;

            transition:
                transform var(--transition-fast),
                background var(--transition-fast);
        }

        .button:hover {
            transform: translateY(-2px);

            background:
                color-mix(
                    in srgb,
                    var(--color-primary) 85%,
                    white
                );
        }

        .button:focus-visible {
            outline: 3px solid var(--color-accent);
            outline-offset: 4px;
        }

        .footer {
            padding-block: var(--space-xl);
            background: var(--color-primary);
            color: #ffffff;
        }

        @media (prefers-reduced-motion: reduce) {
            *,
            *::before,
            *::after {
                transition-duration: 0.01ms !important;
                animation-duration: 0.01ms !important;
            }
        }
    </style>
</head>

<body data-theme="light">

    <header class="hero section">
        <div class="container">

            <h1>
                Build Your Digital Future
            </h1>

            <p>
                Learn modern technology skills
                through practical training at
                Dwallnet Academy.
            </p>

            <a href="#" class="button">
                Explore Courses
            </a>

        </div>
    </header>

    <main class="section">

        <div class="container">

            <div class="courses">

                <article class="card">
                    <h2>Web Development</h2>

                    <p>
                        Learn modern web development
                        from the foundation to advanced
                        frontend techniques.
                    </p>

                    <a href="#" class="button">
                        Learn More
                    </a>
                </article>

                <article class="card">
                    <h2>Data Analysis</h2>

                    <p>
                        Learn how to collect,
                        process, analyze, and present
                        useful information from data.
                    </p>

                    <a href="#" class="button">
                        Learn More
                    </a>
                </article>

                <article class="card">
                    <h2>Cyber Security</h2>

                    <p>
                        Understand the principles
                        behind protecting digital
                        systems and information.
                    </p>

                    <a href="#" class="button">
                        Learn More
                    </a>
                </article>

            </div>

        </div>

    </main>

    <footer class="footer">
        <div class="container">
            &copy; Dwallnet Technologies
        </div>
    </footer>

</body>

</html>

Lesson Summary

Modern CSS provides powerful tools for building scalable and maintainable interfaces. CSS custom properties allow developers to create reusable design values, while functions such as calc(), min(), max(), and clamp() make layouts more flexible.

Modern selectors, logical properties, color functions, nesting, and design tokens further improve CSS architecture.

The most important principle is not to use modern CSS features simply because they are available. Use them when they make the interface more reusable, responsive, accessible, and easier to maintain.

Practice Exercise

Create a modern Dwallnet Academy design system using CSS variables.

  1. Create primary, secondary, accent, background, surface, text, and muted color variables.
  2. Create spacing variables.
  3. Create border-radius variables.
  4. Create reusable shadow variables.
  5. Create reusable transition variables.
  6. Build a responsive container using min().
  7. Build responsive headings using clamp().
  8. Use calc() for at least one layout calculation.
  9. Use logical properties such as margin-inline and padding-block.
  10. Create a light and dark theme using CSS variables.
  11. Use at least one modern selector such as :is(), :where(), or :has().
  12. Create reusable button and course-card components.

Finish the project by checking that your design system remains responsive, accessible, consistent, and easy to maintain.

💻

Code Example

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">

    <meta
        name="viewport"
        content="width=device-width, initial-scale=1.0"
    >

    <title>Dwallnet Academy Modern CSS</title>

    <style>
        :root {
            --color-primary: #0b3b82;
            --color-secondary: #1266c4;
            --color-accent: #38bdf8;

            --color-background: #f4f7fb;
            --color-surface: #ffffff;
            --color-text: #172033;
            --color-muted: #64748b;

            --space-sm: 0.5rem;
            --space-md: 1rem;
            --space-lg: 1.5rem;
            --space-xl: 2rem;

            --radius-sm: 6px;
            --radius-md: 12px;
            --radius-lg: 20px;

            --shadow-card:
                0 10px 30px rgb(0 0 0 / 0.08);

            --transition-fast: 180ms ease;
            --transition-normal: 300ms ease;
        }

        [data-theme="dark"] {
            --color-background: #0f172a;
            --color-surface: #111827;
            --color-text: #f8fafc;
            --color-muted: #cbd5e1;
            --color-primary: #60a5fa;

            --shadow-card:
                0 10px 30px rgb(0 0 0 / 0.3);
        }

        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            font-family: Arial, sans-serif;
            background: var(--color-background);
            color: var(--color-text);

            transition:
                background var(--transition-normal),
                color var(--transition-normal);
        }

        .container {
            width: min(92%, 1200px);
            margin-inline: auto;
        }

        .section {
            padding-block:
                clamp(3rem, 7vw, 7rem);
        }

        .hero {
            background: var(--color-primary);
            color: #ffffff;
        }

        .hero h1 {
            font-size:
                clamp(2rem, 6vw, 4.5rem);
            line-height: 1.05;
        }

        .courses {
            display: grid;
            grid-template-columns:
                repeat(
                    auto-fit,
                    minmax(230px, 1fr)
                );

            gap: var(--space-lg);
        }

        .card {
            padding: var(--space-lg);
            background: var(--color-surface);
            border-radius: var(--radius-lg);
            box-shadow: var(--shadow-card);

            transition:
                transform var(--transition-normal),
                box-shadow var(--transition-normal);
        }

        .card:hover {
            transform: translateY(-6px);
        }

        .card :is(h2, h3) {
            margin-block-start: 0;
        }

        .button {
            display: inline-block;

            padding:
                var(--space-sm)
                var(--space-lg);

            background: var(--color-primary);
            color: #ffffff;

            border-radius: var(--radius-md);
            text-decoration: none;

            transition:
                transform var(--transition-fast),
                background var(--transition-fast);
        }

        .button:hover {
            transform: translateY(-2px);

            background:
                color-mix(
                    in srgb,
                    var(--color-primary) 85%,
                    white
                );
        }

        .button:focus-visible {
            outline: 3px solid var(--color-accent);
            outline-offset: 4px;
        }

        @media (prefers-reduced-motion: reduce) {
            *,
            *::before,
            *::after {
                transition-duration: 0.01ms !important;
                animation-duration: 0.01ms !important;
            }
        }
    </style>
</head>

<body data-theme="light">

    <header class="hero section">
        <div class="container">

            <h1>
                Build Your Digital Future
            </h1>

            <p>
                Learn modern technology skills
                through practical training at
                Dwallnet Academy.
            </p>

            <a href="#" class="button">
                Explore Courses
            </a>

        </div>
    </header>

    <main class="section">

        <div class="container">

            <div class="courses">

                <article class="card">
                    <h2>Web Development</h2>

                    <p>
                        Learn modern web development
                        from the foundation to advanced
                        frontend techniques.
                    </p>

                    <a href="#" class="button">
                        Learn More
                    </a>
                </article>

                <article class="card">
                    <h2>Data Analysis</h2>

                    <p>
                        Learn how to collect,
                        process, analyze, and present
                        useful information from data.
                    </p>

                    <a href="#" class="button">
                        Learn More
                    </a>
                </article>

                <article class="card">
                    <h2>Cyber Security</h2>

                    <p>
                        Understand the principles
                        behind protecting digital
                        systems and information.
                    </p>

                    <a href="#" class="button">
                        Learn More
                    </a>
                </article>

            </div>

        </div>

    </main>

</body>

</html>
⭐

Key Takeaways

["CSS custom properties provide reusable variables directly inside CSS.","The var() function retrieves custom property values.","Fallback values can make CSS variables safer to use.","CSS variables can be global or scoped to individual components.","calc() allows CSS to perform dynamic calculations.","min(), max(), and clamp() are powerful tools for responsive layouts.","Modern color functions provide flexible ways to create and manipulate colors.","Logical properties such as margin-inline and padding-block improve writing-direction flexibility.",":is(), :where(), and :has() can simplify modern CSS selectors.","CSS nesting can organize component styles when used carefully.","Design tokens help maintain consistency across colors, spacing, typography, shadows, and other design values.","CSS variables make light and dark theme systems easier to build.","Modern CSS should be used to improve maintainability, responsiveness, accessibility, and consistency."]

Enjoying this lesson?

Sign in to your Dwallnet Academy student account to track your learning progress and mark lessons as complete.

Sign In to Track Progress