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

CSS Transitions, Transforms and Animations

📖

Lesson Content

Introduction to CSS Motion

Modern websites are not completely static. Buttons can respond when users move their pointer over them, cards can gently move when focused, menus can appear smoothly, and important interface elements can draw attention through controlled motion.

CSS provides powerful tools for creating these effects without requiring JavaScript for every visual interaction.

The three major CSS features covered in this lesson are:

  • Transitions — create smooth changes between two states.
  • Transforms — change the position, size, rotation, or shape of an element.
  • Animations — create controlled sequences of visual changes using keyframes.

Why Use CSS Motion?

Well-designed motion can improve the user experience by helping users understand what is happening on a page.

For example, a button can smoothly change its appearance when a user hovers over it. A card can slightly move when selected. A loading indicator can communicate that an operation is taking place.

However, animation should support usability rather than distract from the content.

CSS Transitions

A transition creates a smooth change between one CSS state and another.

Consider this example:

.button {
    background: #0b3b82;
}

.button:hover {
    background: #06295c;
}

The background changes immediately when the pointer moves over the button.

A transition can make that change gradual:

.button {
    background: #0b3b82;
    transition: background 0.3s ease;
}

.button:hover {
    background: #06295c;
}

Now the browser smoothly changes the background color over 0.3 seconds.

Transition Property

The transition-property property specifies which CSS property should transition.

.card {
    transition-property: transform;
}

You can transition multiple properties:

.card {
    transition-property: transform, box-shadow;
}

You can also use all, although specifying the exact properties is often better for predictable performance and maintenance.

Transition Duration

The transition-duration property controls how long the transition takes.

.button {
    transition-duration: 300ms;
}

Both seconds and milliseconds can be used.

transition-duration: 0.3s;

and:

transition-duration: 300ms;

represent the same duration.

Transition Timing Functions

The timing function controls how the speed of a transition changes during its duration.

Common timing functions include:

  • ease
  • linear
  • ease-in
  • ease-out
  • ease-in-out
  • cubic-bezier()

For example:

.button {
    transition: transform 0.3s ease-out;
}

Transition Delay

The transition-delay property specifies how long the browser should wait before starting the transition.

.card {
    transition-delay: 100ms;
}

Delays should be used carefully because unnecessary waiting can make interfaces feel slow.

Transition Shorthand

Instead of writing multiple transition properties separately, you can use the shorthand property:

.button {
    transition: transform 0.3s ease, background-color 0.3s ease;
}

A typical transition declaration contains:

property duration timing-function delay

For example:

transition: transform 0.3s ease 0s;

CSS Transforms

CSS transforms change the visual presentation of an element without changing the normal document flow in the same way that properties such as width and margin do.

The main transform functions include:

  • translate()
  • translateX()
  • translateY()
  • scale()
  • rotate()
  • skew()

Translate

The translate() function moves an element.

.card {
    transform: translate(20px, 10px);
}

You can move an element horizontally:

transform: translateX(20px);

Or vertically:

transform: translateY(-10px);

Scale

The scale() function changes the visual size of an element.

.card {
    transform: scale(1.05);
}

A value greater than 1 increases the size, while a value between 0 and 1 decreases it.

Rotate

The rotate() function rotates an element.

.icon {
    transform: rotate(45deg);
}

Rotation is commonly used for icons, decorative elements, and interactive controls.

Skew

The skew() function tilts an element along one or both axes.

.shape {
    transform: skew(10deg);
}

Skew effects are useful for certain visual designs but should not be overused.

Combining Transforms

Multiple transforms can be combined in one declaration.

.card:hover {
    transform: translateY(-8px) scale(1.02);
}

This moves the card upward and slightly increases its size.

Transform Origin

The transform-origin property determines the point around which an element transforms.

.box {
    transform-origin: center;
}

You can also use values such as:

transform-origin: top left;

This is especially useful when creating rotations or scaling effects.

Transitions and Transforms Together

Transforms become especially useful when combined with transitions.

.card {
    transition: transform 0.3s ease;
}

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

Without the transition, the card would move immediately. With the transition, the movement becomes smooth.

Hover Effects

A common use of transitions is creating hover effects.

.button {
    transition:
        transform 0.25s ease,
        box-shadow 0.25s ease;
}

.button:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}

This produces a subtle lifting effect.

Focus Effects

Interactive elements should not rely only on hover because keyboard users may not use a mouse.

Use focus styles as well:

.button:focus-visible {
    outline: 3px solid #7db4ff;
    outline-offset: 4px;
}

This provides a visible indication when the element receives keyboard focus.

CSS Animations

Transitions are useful when moving between two states. CSS animations are useful when you need a sequence of states or an animation that can run independently.

Animations use @keyframes.

Creating Keyframes

A simple animation can be created like this:

@keyframes slideIn {
    from {
        transform: translateX(-30px);
        opacity: 0;
    }

    to {
        transform: translateX(0);
        opacity: 1;
    }
}

The animation can then be applied to an element:

.hero {
    animation: slideIn 0.7s ease-out;
}

Using Percentage Keyframes

Animations can contain multiple stages.

@keyframes pulse {
    0% {
        transform: scale(1);
    }

    50% {
        transform: scale(1.05);
    }

    100% {
        transform: scale(1);
    }
}

This creates a sequence where the element grows slightly and then returns to its original size.

Animation Duration

The animation-duration property controls how long one animation cycle takes.

.loader {
    animation-duration: 1s;
}

Animation Timing Function

Like transitions, animations can use timing functions.

.loader {
    animation-timing-function: linear;
}

Animation Delay

The animation-delay property delays the start of an animation.

.hero {
    animation-delay: 0.2s;
}

Animation Iteration Count

The animation-iteration-count property determines how many times an animation runs.

.loader {
    animation-iteration-count: infinite;
}

You can also specify a number:

.notice {
    animation-iteration-count: 3;
}

Animation Direction

The animation-direction property determines the direction in which an animation runs.

Common values include:

  • normal
  • reverse
  • alternate
  • alternate-reverse

For example:

.loader {
    animation-direction: alternate;
}

Animation Fill Mode

The animation-fill-mode property determines how styles are applied before and after an animation.

One useful value is forwards:

.hero {
    animation-fill-mode: forwards;
}

This allows the element to retain the styles from the final keyframe after the animation finishes.

Animation Shorthand

CSS provides the animation shorthand property.

.hero {
    animation: slideIn 0.7s ease-out 0.2s 1 normal forwards;
}

The exact order can contain the animation name, duration, timing function, delay, iteration count, direction, fill mode, and play state.

Animation Play State

The animation-play-state property can pause or resume an animation.

.loader {
    animation-play-state: running;
}

.loader.paused {
    animation-play-state: paused;
}

Transitions vs Animations

TransitionsAnimations
Usually respond to a state change.Can run independently.
Usually move from one state to another.Can contain multiple keyframe stages.
Common for hover and focus interactions.Useful for loaders, entrances, attention effects, and sequences.
Do not require @keyframes.Use @keyframes.

Animating Opacity

Opacity is frequently used with transforms to create entrance effects.

@keyframes fadeIn {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

A combined effect is often more natural:

@keyframes fadeUp {
    from {
        opacity: 0;
        transform: translateY(20px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

Performance Considerations

Not every CSS property is equally efficient to animate.

For many interface effects, transforms and opacity are good choices because browsers can often handle them efficiently.

For example:

.card {
    transition:
        transform 0.3s ease,
        opacity 0.3s ease;
}

Avoid creating unnecessary animations on large numbers of complex elements.

Using Motion Carefully

Animation should have a purpose. Excessive motion can make a website distracting or uncomfortable.

Good motion is usually:

  • Subtle.
  • Short enough to feel responsive.
  • Relevant to the user’s action.
  • Consistent across the interface.
  • Accessible.

Prefers Reduced Motion

Some users prefer reduced motion because animation can cause discomfort or make interfaces harder to use.

CSS provides the prefers-reduced-motion media feature.

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

This allows a website to respect the user’s operating-system preference.

Practical Example: Interactive Course Card

A Dwallnet Academy course card can use a subtle transition when a visitor interacts with it.

.course-card {
    background: #ffffff;
    border-radius: 16px;
    padding: 1.5rem;
    transition:
        transform 0.3s ease,
        box-shadow 0.3s ease;
}

.course-card:hover {
    transform: translateY(-8px);
    box-shadow: 0 16px 35px rgba(0, 0, 0, 0.12);
}

.course-card:focus-within {
    transform: translateY(-4px);
}

Practical Example: Animated Button

.enroll-button {
    display: inline-block;
    padding: 0.85rem 1.3rem;
    border-radius: 8px;
    background: #0b3b82;
    color: #ffffff;
    text-decoration: none;
    transition:
        transform 0.25s ease,
        box-shadow 0.25s ease;
}

.enroll-button:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 18px rgba(0, 0, 0, 0.15);
}

.enroll-button:focus-visible {
    outline: 3px solid #7db4ff;
    outline-offset: 3px;
}

Practical Example: Loading Animation

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.loader {
    width: 40px;
    height: 40px;
    border: 4px solid #dbe7f7;
    border-top-color: #0b3b82;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

Complete Project Example

The following example combines transitions, transforms, keyframe animations, responsive design, focus styles, and reduced-motion support.

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

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

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

    <title>Dwallnet Academy Motion UI</title>

    <style>
        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            font-family: Arial, sans-serif;
            background: #f4f7fb;
            color: #172033;
        }

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

        .hero {
            min-height: 70vh;
            display: grid;
            place-items: center;
            padding: 3rem 0;
            background: #0b3b82;
            color: #ffffff;
        }

        .hero-content {
            text-align: center;
        }

        .hero h1 {
            font-size: clamp(2rem, 6vw, 4.5rem);
            line-height: 1.05;
            animation: fadeUp 0.8s ease-out;
        }

        .hero p {
            max-width: 650px;
            margin-inline: auto;
            animation: fadeUp 0.8s ease-out 0.15s both;
        }

        .button {
            display: inline-block;
            margin-top: 1.5rem;
            padding: 0.9rem 1.4rem;
            border-radius: 8px;
            background: #ffffff;
            color: #0b3b82;
            text-decoration: none;
            font-weight: 700;

            transition:
                transform 0.25s ease,
                box-shadow 0.25s ease;
        }

        .button:hover {
            transform: translateY(-3px);
            box-shadow:
                0 12px 25px rgba(0, 0, 0, 0.18);
        }

        .button:focus-visible {
            outline: 3px solid #ffffff;
            outline-offset: 4px;
        }

        .courses {
            display: grid;
            grid-template-columns:
                repeat(auto-fit, minmax(230px, 1fr));
            gap: 1.5rem;
            padding-block: 4rem;
        }

        .course-card {
            background: #ffffff;
            padding: 1.5rem;
            border-radius: 14px;

            transition:
                transform 0.3s ease,
                box-shadow 0.3s ease;
        }

        .course-card:hover {
            transform:
                translateY(-8px)
                scale(1.01);

            box-shadow:
                0 16px 35px rgba(0, 0, 0, 0.12);
        }

        .course-card:focus-within {
            transform: translateY(-4px);
        }

        .course-card a {
            color: #0b3b82;
            font-weight: 700;
        }

        @keyframes fadeUp {
            from {
                opacity: 0;
                transform: translateY(25px);
            }

            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

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

<body>

    <section class="hero">
        <div class="container hero-content">

            <h1>
                Learn. Build. Transform.
            </h1>

            <p>
                Develop practical technology skills
                through hands-on learning at Dwallnet Academy.
            </p>

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

        </div>
    </section>

    <main class="container">

        <section class="courses">

            <article class="course-card">
                <h2>Web Development</h2>
                <p>
                    Learn how to create modern websites
                    using HTML, CSS and JavaScript.
                </p>

                <a href="#">
                    Explore Course
                </a>
            </article>

            <article class="course-card">
                <h2>Data Analysis</h2>
                <p>
                    Learn how to work with data and
                    turn information into insights.
                </p>

                <a href="#">
                    Explore Course
                </a>
            </article>

            <article class="course-card">
                <h2>Cyber Security</h2>
                <p>
                    Understand important principles
                    for protecting digital systems.
                </p>

                <a href="#">
                    Explore Course
                </a>
            </article>

        </section>

    </main>

</body>

</html>

Lesson Summary

CSS transitions, transforms, and animations allow developers to create polished and interactive interfaces.

Transitions are ideal for smooth changes between states. Transforms can move, rotate, scale, or skew elements. Animations use keyframes to create more complex sequences.

Professional web developers should use motion intentionally, keep interactions smooth, consider performance, provide visible focus states, and respect users who prefer reduced motion.

Practice Exercise

Create an animated Dwallnet Academy course section containing:

  1. At least three course cards.
  2. A smooth hover lift effect on each card.
  3. A button with a hover transition.
  4. A visible keyboard focus state.
  5. A hero section with a fade-up animation.
  6. A rotating loading indicator.
  7. At least one use of transform: scale().
  8. At least one use of transform: translateY().
  9. A @media (prefers-reduced-motion: reduce) rule.

Keep the animation subtle and make sure the page remains usable even when animations are disabled.

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