Complete Guide to HTML and CSS Transitions

Table of Contents

Table of Contents

  1. Introduction to CSS Transitions
  2. Transition Properties
  3. Transition Timing Functions
  4. Transition Delay
  5. Multiple Transitions
  6. Transition Shorthand
  7. Transitionable Properties
  8. Interactive Transitions
  9. Hover Effects
  10. Focus and Active States
  11. Transform with Transitions
  12. Button Transitions
  13. Card Transitions
  14. Menu Transitions
  15. Modal Transitions
  16. Loading Animations
  17. Page Transitions
  18. Performance Considerations
  19. Accessibility
  20. Practical Examples
  21. Best Practices
  22. Common Mistakes

Introduction to CSS Transitions

CSS transitions allow you to change property values smoothly over a given duration. They are a fundamental tool for creating interactive and engaging user interfaces by adding subtle animations to state changes.

What are Transitions?

/* Basic transition syntax */
.element {
property: value;
transition: property duration timing-function delay;
}
/* Simple example */
.button {
background-color: blue;
transition: background-color 0.3s ease;
}
.button:hover {
background-color: darkblue;
}

Why Use Transitions?

/* Benefits of transitions */
- Improve user experience with visual feedback
- Guide user attention
- Create smooth, professional interfaces
- Indicate state changes
- Reduce cognitive load
- Add personality to your design

Transition Properties

transition-property

/* Specify which properties to transition */
.element {
transition-property: all;           /* All properties (default) */
transition-property: none;          /* No transitions */
transition-property: background;    /* Single property */
transition-property: width, height; /* Multiple properties */
transition-property: transform, opacity; /* Common combination */
}
/* Examples */
.single-property {
transition-property: background-color;
transition-duration: 0.3s;
}
.multiple-properties {
transition-property: width, height, background;
transition-duration: 0.3s;
}

transition-duration

/* Set transition duration */
.element {
transition-duration: 0s;      /* No transition (default) */
transition-duration: 0.3s;    /* 300 milliseconds */
transition-duration: 200ms;   /* 200 milliseconds */
transition-duration: 1s;      /* 1 second */
transition-duration: 2.5s;    /* 2.5 seconds */
}
/* Different durations for different properties */
.element {
transition-property: width, height, opacity;
transition-duration: 0.3s, 0.5s, 1s;
}
/* Practical examples */
.fast {
transition-duration: 0.15s;   /* Fast, subtle */
}
.medium {
transition-duration: 0.3s;    /* Standard */
}
.slow {
transition-duration: 0.6s;    /* Slow, dramatic */
}

transition-timing-function

/* Timing functions control the acceleration curve */
.element {
transition-timing-function: ease;         /* Default - slow start, fast middle, slow end */
transition-timing-function: linear;       /* Constant speed */
transition-timing-function: ease-in;      /* Slow start */
transition-timing-function: ease-out;     /* Slow end */
transition-timing-function: ease-in-out;  /* Slow start and end */
transition-timing-function: step-start;   /* Instant start */
transition-timing-function: step-end;     /* Instant end */
}
/* Steps function */
.element {
transition-timing-function: steps(4);      /* 4 discrete steps */
transition-timing-function: steps(4, start); /* Step at start */
transition-timing-function: steps(4, end);   /* Step at end */
transition-timing-function: step(4, jump-start); /* Modern syntax */
}
/* Cubic bezier - custom timing */
.element {
transition-timing-function: cubic-bezier(0.25, 0.1, 0.25, 1); /* Ease */
transition-timing-function: cubic-bezier(0.42, 0, 1, 1);      /* Ease-in */
transition-timing-function: cubic-bezier(0, 0, 0.58, 1);      /* Ease-out */
transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1);   /* Ease-in-out */
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); /* Bounce */
}
/* Common cubic-bezier values */
:root {
--ease-in-sine: cubic-bezier(0.47, 0, 0.745, 0.715);
--ease-out-sine: cubic-bezier(0.39, 0.575, 0.565, 1);
--ease-in-out-sine: cubic-bezier(0.445, 0.05, 0.55, 0.95);
--ease-in-quad: cubic-bezier(0.55, 0.085, 0.68, 0.53);
--ease-out-quad: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--ease-in-out-quad: cubic-bezier(0.455, 0.03, 0.515, 0.955);
--ease-in-cubic: cubic-bezier(0.55, 0.055, 0.675, 0.19);
--ease-out-cubic: cubic-bezier(0.215, 0.61, 0.355, 1);
--ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1);
--ease-in-back: cubic-bezier(0.6, -0.28, 0.735, 0.045);
--ease-out-back: cubic-bezier(0.175, 0.885, 0.32, 1.275);
--ease-in-out-back: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

transition-delay

/* Delay before transition starts */
.element {
transition-delay: 0s;      /* No delay (default) */
transition-delay: 0.5s;    /* 500ms delay */
transition-delay: 200ms;   /* 200ms delay */
transition-delay: 1s;      /* 1 second delay */
}
/* Different delays for different properties */
.element {
transition-property: width, height, opacity;
transition-duration: 0.3s, 0.5s, 0.3s;
transition-delay: 0s, 0.2s, 0.4s;
}
/* Staggered animations */
.parent:hover .child {
transition-delay: 0.1s;
}
.parent:hover .child:nth-child(2) {
transition-delay: 0.2s;
}
.parent:hover .child:nth-child(3) {
transition-delay: 0.3s;
}

Multiple Transitions

Transitioning Multiple Properties

/* Different transitions for different properties */
.element {
transition-property: width, height, background, opacity;
transition-duration: 0.3s, 0.5s, 0.2s, 0.4s;
transition-timing-function: ease, ease-in, ease-out, linear;
transition-delay: 0s, 0.1s, 0.2s, 0.3s;
}
/* Alternative syntax */
.element {
transition: width 0.3s ease,
height 0.5s ease-in 0.1s,
background 0.2s ease-out 0.2s,
opacity 0.4s linear 0.3s;
}
/* Practical example */
.card {
transition: transform 0.3s ease,
box-shadow 0.3s ease,
background 0.2s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
background: #f0f0f0;
}

Transition All

/* Transition all properties - use with caution */
.element {
transition: all 0.3s ease;  /* Transitions everything */
}
/* Better - be specific about what to transition */
.element {
transition: transform 0.3s ease,
opacity 0.3s ease;
}

Transition Shorthand

Shorthand Syntax

/* Full shorthand: property duration timing-function delay */
.element {
transition: all 0.3s ease 0s;                    /* All properties */
transition: background 0.3s;                     /* Property + duration */
transition: opacity 0.5s ease-in;                /* Property + duration + timing */
transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55) 0.2s; /* All values */
}
/* Common shorthands */
.element {
transition: 0.3s;                                 /* Invalid - need property */
transition: all 0.3s;                            /* Valid - transition all */
transition: background 0.3s, transform 0.5s;     /* Multiple transitions */
}
/* Examples */
.fade {
transition: opacity 0.3s ease;
}
.slide {
transition: transform 0.3s ease-out;
}
.combo {
transition: transform 0.3s ease, opacity 0.2s ease 0.1s;
}

Transitionable Properties

Commonly Transitioned Properties

/* Transform properties - best performance */
.element {
transition: transform 0.3s ease;
}
.element:hover {
transform: translateX(10px) scale(1.1) rotate(5deg);
}
/* Opacity - good performance */
.element {
transition: opacity 0.3s ease;
}
.element:hover {
opacity: 0.8;
}
/* Color properties */
.element {
transition: color 0.3s ease,
background-color 0.3s ease,
border-color 0.3s ease;
}
.element:hover {
color: #ff6b6b;
background: #f0f0f0;
border-color: #ff6b6b;
}
/* Box shadow */
.element {
transition: box-shadow 0.3s ease;
}
.element:hover {
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
/* Size properties */
.element {
transition: width 0.3s ease,
height 0.3s ease,
padding 0.3s ease;
}
.element:hover {
width: 200px;
height: 200px;
padding: 20px;
}
/* Position properties */
.element {
position: relative;
transition: top 0.3s ease, left 0.3s ease;
}
.element:hover {
top: 10px;
left: 10px;
}

Properties That Can Be Transitioned

/* Complete list of transitionable properties */
/* Layout properties */
width, height, min-width, min-height, max-width, max-height
padding, margin
top, right, bottom, left
/* Color properties */
color, background-color, border-color, outline-color
column-rule-color, text-decoration-color
/* Visual properties */
opacity, visibility, box-shadow, text-shadow
clip, filter, backdrop-filter
/* Transform properties */
transform, transform-origin
/* Border properties */
border-width, border-radius, border-spacing
/* Font properties */
font-size, font-weight, line-height, letter-spacing, word-spacing
/* Flex/Grid properties */
flex-grow, flex-shrink, grid-gap, gap
/* Other */
z-index, order, outline-offset, perspective

Interactive Transitions

Hover Effects

/* Basic hover transition */
.button {
background: #3498db;
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s ease, transform 0.2s ease;
}
.button:hover {
background: #2980b9;
transform: translateY(-2px);
}
.button:active {
transform: translateY(0);
}
/* Card hover effect */
.card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
/* Image hover effect */
.image-container {
overflow: hidden;
border-radius: 8px;
}
.image-container img {
transition: transform 0.5s ease;
}
.image-container:hover img {
transform: scale(1.1);
}

Focus and Active States

/* Focus transitions for accessibility */
.input-field {
border: 2px solid #ddd;
padding: 10px;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.input-field:focus {
border-color: #3498db;
box-shadow: 0 0 0 3px rgba(52,152,219,0.2);
outline: none;
}
/* Active state for buttons */
.button:active {
transform: scale(0.95);
transition: transform 0.1s ease;
}
/* Focus-visible for keyboard navigation */
.button:focus-visible {
outline: 3px solid #3498db;
outline-offset: 2px;
}

Custom Checkbox with Transitions

.custom-checkbox {
position: relative;
display: inline-block;
width: 20px;
height: 20px;
}
.custom-checkbox input {
opacity: 0;
width: 0;
height: 0;
}
.checkmark {
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
background: #fff;
border: 2px solid #ddd;
border-radius: 4px;
transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
.custom-checkbox input:checked ~ .checkmark {
background: #3498db;
border-color: #3498db;
}
.checkmark:after {
content: '';
position: absolute;
display: none;
left: 6px;
top: 2px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
.custom-checkbox input:checked ~ .checkmark:after {
display: block;
animation: checkmark 0.2s ease-in-out;
}
@keyframes checkmark {
0% {
opacity: 0;
transform: rotate(45deg) scale(0);
}
100% {
opacity: 1;
transform: rotate(45deg) scale(1);
}
}

Transform with Transitions

2D Transforms

/* Translate - move element */
.translate {
transition: transform 0.3s ease;
}
.translate:hover {
transform: translateX(20px);
/* or */
transform: translateY(20px);
/* or */
transform: translate(20px, 20px);
}
/* Scale - resize element */
.scale {
transition: transform 0.3s ease;
}
.scale:hover {
transform: scale(1.1);
/* or */
transform: scaleX(1.2);
/* or */
transform: scaleY(1.2);
}
/* Rotate - spin element */
.rotate {
transition: transform 0.3s ease;
}
.rotate:hover {
transform: rotate(45deg);
/* or */
transform: rotate(-45deg);
}
/* Skew - skew element */
.skew {
transition: transform 0.3s ease;
}
.skew:hover {
transform: skewX(10deg);
/* or */
transform: skewY(10deg);
/* or */
transform: skew(10deg, 10deg);
}
/* Multiple transforms */
.combined {
transition: transform 0.3s ease;
}
.combined:hover {
transform: translateX(20px) scale(1.1) rotate(5deg);
}

3D Transforms

/* 3D transforms */
.perspective {
perspective: 1000px;
}
.rotate-3d {
transition: transform 0.3s ease;
}
.rotate-3d:hover {
transform: rotateX(45deg);
/* or */
transform: rotateY(45deg);
/* or */
transform: rotateZ(45deg);
/* or */
transform: rotate3d(1, 1, 1, 45deg);
}
/* 3D card flip */
.card-3d {
position: relative;
width: 200px;
height: 300px;
transform-style: preserve-3d;
transition: transform 0.6s;
}
.card-3d:hover {
transform: rotateY(180deg);
}
.card-front, .card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.card-front {
background: #3498db;
color: white;
}
.card-back {
background: #e74c3c;
color: white;
transform: rotateY(180deg);
}

Transform Origin

/* Transform origin - sets the point transforms originate from */
.element {
transform-origin: center;        /* Default */
transform-origin: top left;
transform-origin: top right;
transform-origin: bottom left;
transform-origin: bottom right;
transform-origin: 50% 50%;       /* Percentages */
transform-origin: 20px 30px;     /* Pixels */
transform-origin: left 50%;       /* Mixed */
}
/* Examples */
.scale-from-left {
transform-origin: left center;
transition: transform 0.3s ease;
}
.scale-from-left:hover {
transform: scaleX(1.5);
}
.rotate-from-top {
transform-origin: top center;
transition: transform 0.3s ease;
}
.rotate-from-top:hover {
transform: rotate(-10deg);
}

Button Transitions

Basic Button Styles

/* Base button styles */
.btn {
display: inline-block;
padding: 12px 24px;
border: none;
border-radius: 4px;
font-size: 16px;
font-weight: 600;
text-align: center;
text-decoration: none;
cursor: pointer;
transition: all 0.3s ease;
}
/* Primary button */
.btn-primary {
background: #3498db;
color: white;
}
.btn-primary:hover {
background: #2980b9;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(52,152,219,0.4);
}
.btn-primary:active {
transform: translateY(0);
}
/* Secondary button */
.btn-secondary {
background: transparent;
color: #3498db;
border: 2px solid #3498db;
}
.btn-secondary:hover {
background: #3498db;
color: white;
transform: translateY(-2px);
}
/* Outline button */
.btn-outline {
background: transparent;
color: #333;
border: 2px solid #333;
position: relative;
overflow: hidden;
z-index: 1;
}
.btn-outline::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: #333;
transition: left 0.3s ease;
z-index: -1;
}
.btn-outline:hover {
color: white;
}
.btn-outline:hover::before {
left: 0;
}

Advanced Button Effects

/* Pulse effect */
.btn-pulse {
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(52,152,219,0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(52,152,219,0);
}
100% {
box-shadow: 0 0 0 0 rgba(52,152,219,0);
}
}
/* Ripple effect */
.btn-ripple {
position: relative;
overflow: hidden;
}
.btn-ripple::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 5px;
height: 5px;
background: rgba(255,255,255,0.5);
opacity: 0;
border-radius: 100%;
transform: scale(1, 1) translate(-50%);
transform-origin: 50% 50%;
}
.btn-ripple:focus:not(:active)::after {
animation: ripple 1s ease-out;
}
@keyframes ripple {
0% {
transform: scale(0, 0);
opacity: 0.5;
}
20% {
transform: scale(25, 25);
opacity: 0.3;
}
100% {
opacity: 0;
transform: scale(40, 40);
}
}
/* Gradient button */
.btn-gradient {
background: linear-gradient(45deg, #3498db, #9b59b6);
background-size: 200% auto;
color: white;
transition: background-position 0.5s ease, transform 0.3s ease;
}
.btn-gradient:hover {
background-position: right center;
transform: translateY(-2px);
}
/* 3D button */
.btn-3d {
background: #3498db;
color: white;
border-bottom: 4px solid #2980b9;
transform: translateY(0);
}
.btn-3d:hover {
transform: translateY(-2px);
border-bottom-width: 6px;
}
.btn-3d:active {
transform: translateY(2px);
border-bottom-width: 2px;
}
/* Icon button */
.btn-icon {
display: inline-flex;
align-items: center;
gap: 8px;
}
.btn-icon i {
transition: transform 0.3s ease;
}
.btn-icon:hover i {
transform: translateX(5px);
}
/* Loading button */
.btn-loading {
position: relative;
color: transparent !important;
}
.btn-loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px 0 0 -10px;
border: 3px solid white;
border-top-color: transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}

Card Transitions

Card Hover Effects

/* Base card styles */
.card {
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-10px);
box-shadow: 0 15px 30px rgba(0,0,0,0.2);
}
/* Card with image zoom */
.card-image {
overflow: hidden;
height: 200px;
}
.card-image img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.card:hover .card-image img {
transform: scale(1.1);
}
/* Card with content slide */
.card-content {
padding: 20px;
transition: transform 0.3s ease;
}
.card:hover .card-content {
transform: translateY(-10px);
}
/* Card with overlay */
.card-overlay {
position: relative;
}
.card-overlay::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
opacity: 0;
transition: opacity 0.3s ease;
z-index: 1;
}
.card-overlay:hover::before {
opacity: 1;
}
.card-overlay-content {
position: absolute;
bottom: -50px;
left: 0;
right: 0;
padding: 20px;
color: white;
transition: bottom 0.3s ease;
z-index: 2;
}
.card-overlay:hover .card-overlay-content {
bottom: 0;
}

Advanced Card Transitions

/* Card with reveal effect */
.card-reveal {
position: relative;
height: 300px;
overflow: hidden;
}
.card-reveal-front,
.card-reveal-back {
position: absolute;
width: 100%;
height: 100%;
transition: transform 0.5s ease;
}
.card-reveal-back {
background: linear-gradient(135deg, #3498db, #9b59b6);
color: white;
display: flex;
align-items: center;
justify-content: center;
transform: translateY(100%);
}
.card-reveal:hover .card-reveal-back {
transform: translateY(0);
}
/* Card with border glow */
.card-glow {
position: relative;
border: 2px solid transparent;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.card-glow:hover {
border-color: #3498db;
box-shadow: 0 0 20px rgba(52,152,219,0.3);
}
/* Card with scale and shadow */
.card-scale {
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.3s ease;
}
.card-scale:hover {
transform: scale(1.05);
box-shadow: 0 20px 30px rgba(0,0,0,0.2);
}

Menu Transitions

Dropdown Menu

/* Dropdown container */
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-trigger {
padding: 10px 20px;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
min-width: 200px;
background: white;
border: 1px solid #ddd;
border-radius: 4px;
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: opacity 0.3s ease, transform 0.3s ease, visibility 0.3s;
z-index: 100;
}
.dropdown:hover .dropdown-menu {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
/* Dropdown items */
.dropdown-menu a {
display: block;
padding: 10px 15px;
color: #333;
text-decoration: none;
transition: background 0.2s ease, padding-left 0.2s ease;
}
.dropdown-menu a:hover {
background: #f0f0f0;
padding-left: 20px;
}

Slide-out Menu

/* Side menu */
.side-menu {
position: fixed;
top: 0;
left: -300px;
width: 300px;
height: 100vh;
background: #333;
color: white;
transition: left 0.3s ease;
z-index: 1000;
}
.side-menu.open {
left: 0;
}
.side-menu-toggle {
position: fixed;
top: 20px;
left: 20px;
z-index: 1001;
background: #3498db;
color: white;
border: none;
padding: 10px;
border-radius: 4px;
cursor: pointer;
transition: left 0.3s ease;
}
.side-menu.open ~ .side-menu-toggle {
left: 320px;
}
/* Menu items animation */
.side-menu ul {
list-style: none;
padding: 20px;
}
.side-menu li {
margin-bottom: 15px;
opacity: 0;
transform: translateX(-20px);
transition: opacity 0.3s ease, transform 0.3s ease;
transition-delay: calc(0.1s * var(--item-index));
}
.side-menu.open li {
opacity: 1;
transform: translateX(0);
}

Accordion Menu

/* Accordion */
.accordion-item {
border: 1px solid #ddd;
margin-bottom: 10px;
border-radius: 4px;
overflow: hidden;
}
.accordion-header {
padding: 15px;
background: #f5f5f5;
cursor: pointer;
font-weight: bold;
transition: background 0.3s ease;
}
.accordion-header:hover {
background: #e0e0e0;
}
.accordion-content {
max-height: 0;
padding: 0 15px;
background: white;
overflow: hidden;
transition: max-height 0.3s ease, padding 0.3s ease;
}
.accordion-item.active .accordion-content {
max-height: 200px;
padding: 15px;
}

Modal Transitions

Modal Fade In

/* Modal overlay */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
z-index: 1000;
}
.modal-overlay.active {
opacity: 1;
visibility: visible;
}
/* Modal content */
.modal {
background: white;
border-radius: 8px;
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
transform: scale(0.7);
transition: transform 0.3s ease;
}
.modal-overlay.active .modal {
transform: scale(1);
}
/* Modal with slide effect */
.modal-slide {
background: white;
border-radius: 8px;
max-width: 500px;
width: 90%;
transform: translateY(-50px);
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.modal-overlay.active .modal-slide {
transform: translateY(0);
opacity: 1;
}

Modal with Different Animations

/* Scale in from center */
.modal-scale {
transform: scale(0);
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
.modal-overlay.active .modal-scale {
transform: scale(1);
}
/* Slide in from right */
.modal-slide-right {
position: fixed;
top: 0;
right: -500px;
width: 500px;
height: 100vh;
background: white;
transition: right 0.3s ease;
}
.modal-overlay.active .modal-slide-right {
right: 0;
}
/* Rotate in */
.modal-rotate {
transform: rotate(-10deg) scale(0.8);
opacity: 0;
transition: transform 0.4s ease, opacity 0.4s ease;
}
.modal-overlay.active .modal-rotate {
transform: rotate(0) scale(1);
opacity: 1;
}

Loading Animations

Spinner

/* Simple spinner */
.spinner {
width: 40px;
height: 40px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Dual ring spinner */
.spinner-dual {
width: 40px;
height: 40px;
border: 4px solid transparent;
border-top: 4px solid #3498db;
border-bottom: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s ease-in-out infinite;
}
/* Ellipsis */
.ellipsis {
display: inline-flex;
align-items: center;
}
.ellipsis span {
width: 8px;
height: 8px;
margin: 0 2px;
background: #3498db;
border-radius: 50%;
animation: ellipsis 1.4s infinite;
}
.ellipsis span:nth-child(2) {
animation-delay: 0.2s;
}
.ellipsis span:nth-child(3) {
animation-delay: 0.4s;
}
@keyframes ellipsis {
0%, 60%, 100% {
transform: scale(1);
opacity: 1;
}
30% {
transform: scale(1.5);
opacity: 0.3;
}
}
/* Pulse */
.pulse {
width: 40px;
height: 40px;
background: #3498db;
border-radius: 50%;
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.5;
}
100% {
transform: scale(1);
opacity: 1;
}
}

Progress Bar

/* Progress bar container */
.progress {
width: 100%;
height: 20px;
background: #f0f0f0;
border-radius: 10px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: linear-gradient(45deg, #3498db, #9b59b6);
border-radius: 10px;
width: 0%;
transition: width 0.5s ease;
}
/* Animated progress */
.progress-bar.striped {
background-image: linear-gradient(
45deg,
rgba(255,255,255,0.15) 25%,
transparent 25%,
transparent 50%,
rgba(255,255,255,0.15) 50%,
rgba(255,255,255,0.15) 75%,
transparent 75%,
transparent
);
background-size: 40px 40px;
animation: progress-stripes 1s linear infinite;
}
@keyframes progress-stripes {
0% { background-position: 0 0; }
100% { background-position: 40px 0; }
}

Page Transitions

Fade Transition

/* Page fade */
.page {
opacity: 0;
animation: fadeIn 0.5s ease forwards;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
/* Fade out on exit */
.page-exit {
animation: fadeOut 0.5s ease forwards;
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}

Slide Transitions

/* Slide in from right */
.page-slide-right {
animation: slideInRight 0.3s ease forwards;
}
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* Slide in from left */
.page-slide-left {
animation: slideInLeft 0.3s ease forwards;
}
@keyframes slideInLeft {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
/* Slide in from bottom */
.page-slide-up {
animation: slideInUp 0.3s ease forwards;
}
@keyframes slideInUp {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}

Route Transition Example

<div class="route-container">
<div class="page home">
<h1>Home Page</h1>
</div>
</div>
.route-container {
position: relative;
overflow: hidden;
}
.page {
position: absolute;
width: 100%;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.page-enter {
transform: translateX(100%);
opacity: 0;
}
.page-enter-active {
transform: translateX(0);
opacity: 1;
}
.page-exit {
transform: translateX(0);
opacity: 1;
}
.page-exit-active {
transform: translateX(-100%);
opacity: 0;
}

Performance Considerations

Hardware Acceleration

/* Use transforms and opacity for smooth animations */
.good {
transform: translateX(100px);
opacity: 0.5;
transition: transform 0.3s ease, opacity 0.3s ease;
}
/* Avoid animating layout properties */
.bad {
left: 100px;
width: 200px;
transition: left 0.3s ease, width 0.3s ease;  /* Causes repaints */
}
/* Hint at hardware acceleration */
.accelerated {
transform: translateZ(0);
will-change: transform;
}
/* Use will-change sparingly */
.element {
will-change: transform;  /* Only when element will change */
}
.element:hover {
transform: scale(1.1);
}

Performance Tips

/* Performance best practices */
1. Use transform and opacity instead of layout properties
2. Keep animations simple
3. Avoid animating large numbers of elements
4. Use will-change sparingly
5. Test on low-powered devices
6. Consider reduced motion preferences
7. Batch property changes
8. Use requestAnimationFrame for JavaScript animations
/* Reduce motion for accessibility */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}

Efficient Transitions

/* Good - using transform */
.good-move {
transform: translateX(0);
transition: transform 0.3s ease;
}
.good-move:hover {
transform: translateX(10px);
}
/* Bad - using position */
.bad-move {
position: relative;
left: 0;
transition: left 0.3s ease;
}
.bad-move:hover {
left: 10px;
}
/* Opacity fade is efficient */
.fade {
opacity: 1;
transition: opacity 0.3s ease;
}
.fade:hover {
opacity: 0.8;
}

Accessibility

Reduced Motion

/* Respect user preferences */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
/* Keep essential animations but make them instant */
.modal-overlay {
transition: opacity 0.01ms ease;
}
/* Remove decorative animations */
.pulse, .spinner {
animation: none !important;
}
}
/* Provide alternative experience */
@media (prefers-reduced-motion: reduce) {
.hover-effect {
transform: none !important;
transition: none !important;
}
}

Focus Indicators

/* Ensure focus is visible */
:focus-visible {
outline: 3px solid #3498db;
outline-offset: 2px;
transition: outline-offset 0.2s ease;
}
/* Animate focus indicator */
.button:focus-visible {
outline: 2px solid #3498db;
outline-offset: 4px;
}
/* Remove outline for mouse users */
:focus:not(:focus-visible) {
outline: none;
}

Screen Reader Considerations

/* Don't hide content from screen readers */
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Ensure animated content is accessible */
.loading-spinner {
role: status;
aria-live: polite;
}
/* Provide alternative text for animations */
.animated-icon::before {
content: "Loading...";
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
}

Practical Examples

Example 1: Interactive Card with Multiple Transitions

<div class="interactive-card">
<div class="card-media">
<img src="image.jpg" alt="Card image">
<div class="card-overlay">
<button class="card-btn">View Details</button>
</div>
</div>
<div class="card-content">
<h3>Card Title</h3>
<p>Card description text that appears here.</p>
<div class="card-meta">
<span class="date">Jan 1, 2024</span>
<span class="likes">❤️ 42</span>
</div>
</div>
</div>
.interactive-card {
width: 300px;
background: white;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.3s ease;
}
.interactive-card:hover {
transform: translateY(-10px) scale(1.02);
box-shadow: 0 20px 30px rgba(0,0,0,0.2);
}
.card-media {
position: relative;
overflow: hidden;
height: 200px;
}
.card-media img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.interactive-card:hover .card-media img {
transform: scale(1.1);
}
.card-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.interactive-card:hover .card-overlay {
opacity: 1;
}
.card-btn {
padding: 10px 20px;
background: white;
color: #333;
border: none;
border-radius: 4px;
cursor: pointer;
transform: translateY(20px);
transition: transform 0.3s ease, background 0.3s ease;
}
.interactive-card:hover .card-btn {
transform: translateY(0);
}
.card-btn:hover {
background: #3498db;
color: white;
}
.card-content {
padding: 20px;
}
.card-content h3 {
margin: 0 0 10px 0;
color: #333;
transition: color 0.3s ease;
}
.interactive-card:hover .card-content h3 {
color: #3498db;
}
.card-content p {
color: #666;
line-height: 1.6;
}
.card-meta {
display: flex;
justify-content: space-between;
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid #eee;
color: #999;
}
.date, .likes {
transition: transform 0.2s ease;
}
.likes:hover {
transform: scale(1.2);
}

Example 2: Animated Navigation Menu

<nav class="animated-nav">
<div class="nav-brand">Logo</div>
<button class="nav-toggle" aria-label="Toggle menu">
<span></span>
<span></span>
<span></span>
</button>
<ul class="nav-menu">
<li><a href="#home">Home</a></li>
<li><a href="#about">About</a></li>
<li><a href="#services">Services</a></li>
<li><a href="#portfolio">Portfolio</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</nav>
.animated-nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 2rem;
background: #333;
color: white;
position: relative;
}
.nav-brand {
font-size: 1.5rem;
font-weight: bold;
}
.nav-toggle {
display: none;
flex-direction: column;
justify-content: space-around;
width: 30px;
height: 25px;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;
}
.nav-toggle span {
width: 100%;
height: 3px;
background: white;
transition: all 0.3s ease;
}
.nav-toggle.active span:nth-child(1) {
transform: rotate(45deg) translate(5px, 5px);
}
.nav-toggle.active span:nth-child(2) {
opacity: 0;
transform: translateX(-20px);
}
.nav-toggle.active span:nth-child(3) {
transform: rotate(-45deg) translate(7px, -6px);
}
.nav-menu {
display: flex;
list-style: none;
margin: 0;
padding: 0;
gap: 2rem;
}
.nav-menu a {
color: white;
text-decoration: none;
position: relative;
padding: 5px 0;
}
.nav-menu a::before {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: #3498db;
transition: width 0.3s ease;
}
.nav-menu a:hover::before {
width: 100%;
}
.nav-menu a::after {
content: '';
position: absolute;
bottom: -2px;
right: 0;
width: 0;
height: 2px;
background: #e74c3c;
transition: width 0.3s ease 0.1s;
}
.nav-menu a:hover::after {
width: 100%;
}
@media (max-width: 768px) {
.nav-toggle {
display: flex;
}
.nav-menu {
position: fixed;
top: 0;
right: -300px;
width: 300px;
height: 100vh;
background: #333;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 2rem;
transition: right 0.3s ease;
z-index: 5;
}
.nav-menu.active {
right: 0;
}
.nav-menu a {
font-size: 1.2rem;
opacity: 0;
transform: translateX(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
transition-delay: calc(0.1s * var(--item-index, 1));
}
.nav-menu.active a {
opacity: 1;
transform: translateX(0);
}
}

Example 3: Animated Form with Floating Labels

<form class="animated-form">
<div class="form-group">
<input type="text" id="name" required>
<label for="name">Full Name</label>
<span class="focus-border"></span>
</div>
<div class="form-group">
<input type="email" id="email" required>
<label for="email">Email Address</label>
<span class="focus-border"></span>
</div>
<div class="form-group">
<textarea id="message" rows="3" required></textarea>
<label for="message">Message</label>
<span class="focus-border"></span>
</div>
<button type="submit" class="submit-btn">
<span>Send Message</span>
<span class="btn-icon">→</span>
</button>
</form>
.animated-form {
max-width: 500px;
margin: 0 auto;
padding: 2rem;
}
.form-group {
position: relative;
margin-bottom: 2rem;
}
.form-group input,
.form-group textarea {
width: 100%;
padding: 10px 0;
border: none;
border-bottom: 2px solid #ddd;
background: transparent;
font-size: 16px;
transition: border-color 0.3s ease;
}
.form-group input:focus,
.form-group textarea:focus {
outline: none;
border-color: #3498db;
}
.form-group label {
position: absolute;
top: 10px;
left: 0;
color: #999;
pointer-events: none;
transition: all 0.3s ease;
}
.form-group input:focus ~ label,
.form-group input:valid ~ label,
.form-group textarea:focus ~ label,
.form-group textarea:valid ~ label {
top: -20px;
font-size: 12px;
color: #3498db;
}
.focus-border {
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: #3498db;
transition: width 0.3s ease;
}
.form-group input:focus ~ .focus-border,
.form-group textarea:focus ~ .focus-border {
width: 100%;
}
.submit-btn {
position: relative;
width: 100%;
padding: 15px;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
overflow: hidden;
transition: background 0.3s ease;
}
.submit-btn:hover {
background: #2980b9;
}
.submit-btn span {
display: inline-block;
transition: transform 0.3s ease;
}
.btn-icon {
position: absolute;
right: -30px;
top: 50%;
transform: translateY(-50%);
opacity: 0;
transition: right 0.3s ease, opacity 0.3s ease;
}
.submit-btn:hover span:first-child {
transform: translateX(-10px);
}
.submit-btn:hover .btn-icon {
right: 20px;
opacity: 1;
}
.submit-btn:active {
transform: scale(0.95);
}

Example 4: Animated Modal with Multiple Effects

<button class="open-modal">Open Modal</button>
<div class="modal-overlay" id="modal">
<div class="modal-container">
<div class="modal-header">
<h2>Modal Title</h2>
<button class="close-modal">&times;</button>
</div>
<div class="modal-body">
<p>This is a modal with multiple animated elements.</p>
<div class="modal-features">
<div class="feature">Feature 1</div>
<div class="feature">Feature 2</div>
<div class="feature">Feature 3</div>
</div>
</div>
<div class="modal-footer">
<button class="modal-btn cancel">Cancel</button>
<button class="modal-btn confirm">Confirm</button>
</div>
</div>
</div>
.open-modal {
padding: 12px 24px;
background: #3498db;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: transform 0.2s ease, background 0.2s ease;
}
.open-modal:hover {
background: #2980b9;
transform: scale(1.05);
}
.open-modal:active {
transform: scale(0.95);
}
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
z-index: 1000;
}
.modal-overlay.active {
opacity: 1;
visibility: visible;
}
.modal-container {
background: white;
border-radius: 8px;
max-width: 500px;
width: 90%;
max-height: 90vh;
overflow-y: auto;
transform: scale(0.7) translateY(-50px);
opacity: 0;
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
opacity 0.3s ease;
}
.modal-overlay.active .modal-container {
transform: scale(1) translateY(0);
opacity: 1;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
border-bottom: 1px solid #eee;
}
.close-modal {
background: none;
border: none;
font-size: 30px;
cursor: pointer;
color: #999;
transition: color 0.2s ease, transform 0.2s ease;
}
.close-modal:hover {
color: #e74c3c;
transform: rotate(90deg);
}
.modal-body {
padding: 20px;
}
.modal-features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
gap: 15px;
margin-top: 20px;
}
.feature {
padding: 15px;
background: #f5f5f5;
border-radius: 4px;
text-align: center;
opacity: 0;
transform: translateY(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
transition-delay: calc(0.1s * var(--feature-index));
}
.modal-overlay.active .feature {
opacity: 1;
transform: translateY(0);
}
.modal-footer {
padding: 20px;
border-top: 1px solid #eee;
display: flex;
justify-content: flex-end;
gap: 10px;
}
.modal-btn {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s ease;
}
.modal-btn.cancel {
background: #95a5a6;
color: white;
}
.modal-btn.cancel:hover {
background: #7f8c8d;
transform: translateY(-2px);
}
.modal-btn.confirm {
background: #3498db;
color: white;
}
.modal-btn.confirm:hover {
background: #2980b9;
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(52,152,219,0.4);
}
.modal-btn:active {
transform: translateY(0);
}

Best Practices

Transition Guidelines

/* 1. Keep transitions subtle */
.good {
transition: transform 0.2s ease;
}
.bad {
transition: transform 2s ease;  /* Too slow */
}
/* 2. Be consistent with timing */
:root {
--transition-fast: 0.15s;
--transition-base: 0.3s;
--transition-slow: 0.5s;
}
.element {
transition: transform var(--transition-base) ease;
}
/* 3. Use appropriate timing functions */
.element {
transition: transform 0.3s ease-out;  /* Natural feel */
}
/* 4. Consider mobile performance */
@media (max-width: 768px) {
.element {
transition-duration: 0.15s;  /* Faster on mobile */
}
}
/* 5. Group related transitions */
.element {
transition: transform 0.3s ease,
opacity 0.3s ease,
box-shadow 0.3s ease;
}

Transition Checklist

/* Transition design checklist */
- [ ] Duration is appropriate (not too slow/fast)
- [ ] Timing function matches the feel
- [ ] Only transition necessary properties
- [ ] Test on mobile devices
- [ ] Consider reduced motion preferences
- [ ] Ensure focus states are visible
- [ ] Don't trigger accessibility issues
- [ ] Test with screen readers
- [ ] Performance is optimized
- [ ] Consistent across similar elements

Accessibility Checklist

/* Accessibility checklist */
- [ ] Respect prefers-reduced-motion
- [ ] Ensure focus indicators are visible
- [ ] Don't hide important content
- [ ] Provide alternative for animations
- [ ] Test with keyboard navigation
- [ ] Ensure proper contrast during transitions
- [ ] Don't cause seizures (avoid flashing)

Common Mistakes

Mistake 1: Transitioning All Properties

/* Bad */
.element {
transition: all 0.3s ease;  /* Performance hit */
}
/* Good */
.element {
transition: transform 0.3s ease, opacity 0.3s ease;
}

Mistake 2: No Fallback for Reduced Motion

/* Bad */
.element {
animation: spin 1s infinite;
}
/* Good */
.element {
animation: spin 1s infinite;
}
@media (prefers-reduced-motion: reduce) {
.element {
animation: none;
}
}

Mistake 3: Animating Expensive Properties

/* Bad - causes repaints */
.element {
left: 0;
transition: left 0.3s ease;
}
/* Good - hardware accelerated */
.element {
transform: translateX(0);
transition: transform 0.3s ease;
}

Mistake 4: Transitions Too Slow or Fast

/* Bad - too slow */
.element {
transition: transform 2s ease;
}
/* Bad - too fast */
.element {
transition: transform 0.05s ease;
}
/* Good */
.element {
transition: transform 0.3s ease;
}

Mistake 5: No Focus Styles

/* Bad - removes focus indicator */
.element:focus {
outline: none;
}
/* Good - custom focus style */
.element:focus-visible {
outline: 3px solid #3498db;
outline-offset: 2px;
}

Mistake 6: Transitioning Display

/* Bad - display can't be transitioned */
.element {
display: none;
transition: display 0.3s ease;  /* Won't work */
}
/* Good - use opacity + visibility */
.element {
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.element.active {
opacity: 1;
visibility: visible;
}

Mistake 7: Forgetting to Set Initial Values

/* Bad - no initial value */
.element {
transition: transform 0.3s ease;
}
.element:hover {
transform: scale(1.1);
}
/* Good - initial value set */
.element {
transform: scale(1);
transition: transform 0.3s ease;
}
.element:hover {
transform: scale(1.1);
}

Conclusion

CSS transitions are powerful tools for creating smooth, engaging user interfaces. This comprehensive guide covered:

Key Takeaways

  1. Transition Properties - property, duration, timing-function, delay
  2. Timing Functions - ease, linear, ease-in, ease-out, cubic-bezier
  3. Performance - use transform and opacity, avoid layout properties
  4. Accessibility - respect reduced motion, maintain focus indicators
  5. Interactive Elements - buttons, cards, menus, modals
  6. Practical Examples - real-world implementations
  7. Best Practices - consistency, subtlety, performance

Best Practices Summary

  • Use appropriate durations - 0.2s to 0.4s for most interactions
  • Choose natural timing functions - ease-out for entrances, ease-in for exits
  • Limit transitioned properties - only transform and opacity for performance
  • Test on real devices - ensure smoothness on mobile
  • Consider accessibility - respect user preferences
  • Be consistent - use similar transitions throughout your site

Common Use Cases

ComponentPropertiesDurationTiming
Buttonstransform, background0.2sease
Cardstransform, box-shadow0.3sease-out
Modalsopacity, transform0.3sease-out
Dropdownsopacity, transform0.2sease
Tooltipsopacity, transform0.15sease

Remember: Good transitions are subtle, purposeful, and enhance the user experience without being distracting!

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper