Follow AiTechWorlds on LinkedIn for professional AI content!Follow Now →
18 minLesson 11 of 40
CSS3 & Responsive Design

Animations & Transitions

Animations & Transitions

CSS animations and transitions add motion to your UI — making it feel polished and responsive to user interaction. Done right, they guide attention and communicate state. Done wrong, they distract and annoy.

Transitions

Transitions animate a property change from one state to another:

/* transition: property duration timing-function delay */
.button {
    background-color: #4a90e2;
    transform: translateY(0);
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    
    /* Animate specific properties */
    transition: background-color 200ms ease,
                transform 200ms ease,
                box-shadow 200ms ease;
    
    /* Or all properties (less performant) */
    transition: all 200ms ease;
}

.button:hover {
    background-color: #2171c7;
    transform: translateY(-2px);
    box-shadow: 0 6px 16px rgba(0,0,0,0.2);
}

Timing Functions

.element {
    /* Built-in easing curves */
    transition: transform 300ms ease;        /* slow start and end */
    transition: transform 300ms ease-in;     /* slow start */
    transition: transform 300ms ease-out;    /* slow end */
    transition: transform 300ms ease-in-out; /* slow start and end (stronger) */
    transition: transform 300ms linear;      /* constant speed */
    
    /* Custom cubic-bezier */
    transition: transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1); /* spring */
    transition: transform 300ms cubic-bezier(0.4, 0, 0.2, 1);      /* Material Design */
    
    /* Step functions */
    transition: opacity 300ms steps(4);     /* 4 discrete steps */
}

GPU-Accelerated Properties

For smooth 60fps animations, only animate these properties — they're handled by the GPU:

/* Fast (composite layer) */
transform: translateX() translateY() scale() rotate();
opacity: 0 to 1;

/* Slow (triggers layout or paint) */
width, height, top, left, margin, padding, background-color

/* The GPU trick for non-composited properties */
.animated-element {
    will-change: transform; /* promote to GPU layer */
    /* Use sparingly — each promotion costs memory */
}

Keyframe Animations

For multi-step or looping animations:

/* Define the animation */
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: translateY(0); }
}

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

@keyframes pulse {
    0%, 100% { transform: scale(1); }
    50%       { transform: scale(1.05); }
}

@keyframes shimmer {
    0%   { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

/* Apply the animation */
.card {
    animation: fadeIn 400ms ease-out both;
    /* animation-name: fadeIn
       animation-duration: 400ms
       animation-timing-function: ease-out
       animation-fill-mode: both (apply first/last keyframe before/after)
    */
}

.spinner {
    animation: spin 1s linear infinite;
}

.badge {
    animation: pulse 2s ease-in-out infinite;
}

Staggered Animations

/* Animate list items one by one */
.list-item {
    animation: fadeIn 400ms ease-out both;
}

.list-item:nth-child(1) { animation-delay: 0ms; }
.list-item:nth-child(2) { animation-delay: 50ms; }
.list-item:nth-child(3) { animation-delay: 100ms; }
.list-item:nth-child(4) { animation-delay: 150ms; }
.list-item:nth-child(5) { animation-delay: 200ms; }

/* Or with CSS custom properties + JavaScript */
.list-item {
    animation: fadeIn 400ms ease-out both;
    animation-delay: calc(var(--index) * 50ms);
}
document.querySelectorAll(".list-item").forEach((el, i) => {
    el.style.setProperty("--index", i);
});

Loading Skeleton

.skeleton {
    background: linear-gradient(
        90deg,
        #f0f0f0 25%,
        #e0e0e0 50%,
        #f0f0f0 75%
    );
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
    border-radius: 4px;
}

.skeleton-text   { height: 1rem; margin-bottom: 0.5rem; }
.skeleton-title  { height: 1.5rem; width: 60%; margin-bottom: 1rem; }
.skeleton-image  { height: 200px; width: 100%; }

Page Transitions

/* Fade in on page load */
body {
    animation: fadeIn 300ms ease-out;
}

/* Route transitions (React Router / Next.js) */
.page-enter {
    opacity: 0;
    transform: translateY(8px);
}
.page-enter-active {
    opacity: 1;
    transform: translateY(0);
    transition: opacity 300ms, transform 300ms;
}
.page-exit { opacity: 1; }
.page-exit-active {
    opacity: 0;
    transition: opacity 200ms;
}

Respecting User Preferences

Always disable animations for users who prefer reduced motion:

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

/* Or opt-in approach */
@media (prefers-reduced-motion: no-preference) {
    .card {
        transition: transform 200ms ease;
    }
}

Next lesson: DOM Manipulation — using JavaScript to interact with HTML elements.

📱

Get this course's notes on Telegram!

Free cheat sheets, summaries & practice exercises

Get Notes Free →
!