CSS Transitions
Create smooth animations between property values. Transitions add polish and improve user experience by making changes feel natural.
💻 Transition Basics
/* Basic transition */
.button {
background: #007bff;
transition: background 0.3s;
}
.button:hover {
background: #0056b3;
}
/* Four transition properties */
.element {
transition-property: background;
transition-duration: 0.3s;
transition-timing-function: ease;
transition-delay: 0s;
}
/* Shorthand */
.element {
transition: property duration timing-function delay;
transition: background 0.3s ease 0s;
}
🎯 Transition Properties
transition-property
/* Single property */
.box {
transition-property: background;
}
/* Multiple properties */
.box {
transition-property: background, color, transform;
}
/* All properties */
.box {
transition-property: all;
}
/* None (no transition) */
.box {
transition-property: none;
}
/* Specific properties recommended */
.button {
transition-property: background-color, transform;
}
transition-duration
/* Duration in seconds */
.fast {
transition-duration: 0.2s;
}
.medium {
transition-duration: 0.5s;
}
.slow {
transition-duration: 1s;
}
/* Duration in milliseconds */
.precise {
transition-duration: 150ms;
}
/* Multiple durations for multiple properties */
.box {
transition-property: background, transform;
transition-duration: 0.3s, 0.5s;
}
/* Common durations */
/* Micro: 100ms - 150ms */
/* Quick: 200ms - 300ms */
/* Standard: 300ms - 500ms */
/* Slow: 500ms - 1s */
transition-timing-function
/* Predefined timing functions */
.ease {
transition-timing-function: ease; /* Default, slow-fast-slow */
}
.linear {
transition-timing-function: linear; /* Constant speed */
}
.ease-in {
transition-timing-function: ease-in; /* Slow start */
}
.ease-out {
transition-timing-function: ease-out; /* Slow end */
}
.ease-in-out {
transition-timing-function: ease-in-out; /* Slow start and end */
}
/* Cubic bezier (custom) */
.custom {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
/* Steps (discrete transitions) */
.steps {
transition-timing-function: steps(4); /* 4 equal steps */
transition-timing-function: steps(4, jump-start);
transition-timing-function: steps(4, jump-end);
}
/* Common custom beziers */
.smooth {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); /* Material Design */
}
.bounce {
transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
transition-delay
/* Delay before transition starts */
.delayed {
transition-delay: 0.5s;
}
.immediate {
transition-delay: 0s; /* Default */
}
/* Multiple delays */
.box {
transition-property: opacity, transform;
transition-duration: 0.3s, 0.5s;
transition-delay: 0s, 0.2s; /* Transform delayed */
}
/* Negative delay (start partway through) */
.advanced {
transition-delay: -0.2s; /* Starts 0.2s in */
}
✍️ Transition Shorthand
/* Full shorthand syntax */
.element {
transition: property duration timing-function delay;
}
/* Examples */
.button {
transition: background 0.3s ease 0s;
}
.card {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Multiple transitions */
.box {
transition:
background 0.3s ease,
transform 0.5s ease-out,
opacity 0.2s linear;
}
/* All properties, same settings */
.element {
transition: all 0.3s ease;
}
/* Common pattern */
.interactive {
transition: all 0.3s; /* Shorthand shorthand */
}
🎨 Common Transitions
Opacity
/* Fade in/out */
.fade {
opacity: 0;
transition: opacity 0.3s;
}
.fade.visible {
opacity: 1;
}
/* Hover fade */
.image {
opacity: 1;
transition: opacity 0.3s;
}
.image:hover {
opacity: 0.7;
}
Transform
/* Scale */
.scale {
transition: transform 0.3s;
}
.scale:hover {
transform: scale(1.1);
}
/* Translate (move) */
.slide {
transition: transform 0.3s;
}
.slide:hover {
transform: translateY(-5px);
}
/* Rotate */
.rotate {
transition: transform 0.3s;
}
.rotate:hover {
transform: rotate(45deg);
}
/* Combine transforms */
.combo {
transition: transform 0.3s;
}
.combo:hover {
transform: scale(1.05) translateY(-5px);
}
Colors
/* Background color */
.button {
background: #007bff;
transition: background-color 0.3s;
}
.button:hover {
background: #0056b3;
}
/* Text color */
.link {
color: #007bff;
transition: color 0.2s;
}
.link:hover {
color: #0056b3;
}
/* Border color */
.input {
border: 2px solid #ccc;
transition: border-color 0.3s;
}
.input:focus {
border-color: #007bff;
}
Dimensions
/* Width */
.expand {
width: 200px;
transition: width 0.3s;
}
.expand:hover {
width: 300px;
}
/* Height */
.accordion {
height: 0;
overflow: hidden;
transition: height 0.3s;
}
.accordion.open {
height: 200px;
}
/* Max-height trick for dynamic content */
.collapsible {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.collapsible.open {
max-height: 1000px; /* Large enough for content */
}
Box Shadow
/* Elevate on hover */
.card {
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: box-shadow 0.3s;
}
.card:hover {
box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
🎯 Practical Examples
/* Button hover effect */
.button {
background: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s, transform 0.2s;
}
.button:hover {
background: #0056b3;
transform: translateY(-2px);
}
.button:active {
transform: translateY(0);
}
/* Card hover effect */
.card {
background: white;
border-radius: 8px;
padding: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: transform 0.3s, box-shadow 0.3s;
}
.card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0,0,0,0.15);
}
/* Link underline animation */
.link {
position: relative;
color: #007bff;
text-decoration: none;
}
.link::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
width: 0;
height: 2px;
background: #007bff;
transition: width 0.3s;
}
.link:hover::after {
width: 100%;
}
/* Image zoom on hover */
.image-container {
overflow: hidden;
border-radius: 8px;
}
.image-container img {
width: 100%;
transition: transform 0.5s;
}
.image-container:hover img {
transform: scale(1.1);
}
/* Smooth color mode transition */
body {
background: white;
color: black;
transition: background-color 0.3s, color 0.3s;
}
body.dark-mode {
background: #1a1a1a;
color: white;
}
/* Accordion */
.accordion-item {
border: 1px solid #ddd;
border-radius: 4px;
margin-bottom: 10px;
}
.accordion-header {
padding: 15px;
cursor: pointer;
background: #f5f5f5;
transition: background-color 0.3s;
}
.accordion-header:hover {
background: #e0e0e0;
}
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out, padding 0.3s;
padding: 0 15px;
}
.accordion-item.open .accordion-content {
max-height: 500px;
padding: 15px;
}
/* Navigation menu */
nav a {
color: #333;
text-decoration: none;
padding: 10px 15px;
display: inline-block;
position: relative;
transition: color 0.3s;
}
nav a::before {
content: '';
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background: #007bff;
transform: translateX(-50%);
transition: width 0.3s;
}
nav a:hover {
color: #007bff;
}
nav a:hover::before {
width: 80%;
}
/* Form input focus */
.input {
padding: 10px;
border: 2px solid #ddd;
border-radius: 4px;
transition: border-color 0.3s, box-shadow 0.3s;
}
.input:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
}
/* Loading button */
.loading-button {
padding: 10px 20px;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
min-width: 120px;
transition: background-color 0.3s, opacity 0.3s;
}
.loading-button.loading {
opacity: 0.6;
pointer-events: none;
}
/* Toggle switch */
.switch {
width: 50px;
height: 26px;
background: #ccc;
border-radius: 13px;
position: relative;
cursor: pointer;
transition: background-color 0.3s;
}
.switch::after {
content: '';
position: absolute;
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
top: 3px;
left: 3px;
transition: transform 0.3s;
}
.switch.active {
background: #4caf50;
}
.switch.active::after {
transform: translateX(24px);
}
/* Modal backdrop */
.modal-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0);
pointer-events: none;
transition: background-color 0.3s;
}
.modal-backdrop.visible {
background: rgba(0,0,0,0.5);
pointer-events: auto;
}
/* Stagger transitions */
.list-item {
opacity: 0;
transform: translateY(20px);
transition: opacity 0.3s, transform 0.3s;
}
.list-item:nth-child(1) { transition-delay: 0s; }
.list-item:nth-child(2) { transition-delay: 0.1s; }
.list-item:nth-child(3) { transition-delay: 0.2s; }
.list-item:nth-child(4) { transition-delay: 0.3s; }
.list-item.visible {
opacity: 1;
transform: translateY(0);
}
💡 Best Practices
/* 1. Use specific properties, not "all" */
/* Bad */
.element {
transition: all 0.3s;
}
/* Good */
.element {
transition: background-color 0.3s, transform 0.3s;
}
/* 2. Reasonable durations */
/* Too fast: < 150ms */
/* Too slow: > 1s */
/* Sweet spot: 200ms - 500ms */
/* 3. Use transform for smooth animations */
/* Bad (causes repaint) */
.box {
transition: left 0.3s;
}
/* Good (GPU accelerated) */
.box {
transition: transform 0.3s;
}
/* 4. Avoid transitioning expensive properties */
/* Expensive: width, height, top, left */
/* Cheap: transform, opacity */
/* 5. Provide feedback on interaction */
.button {
transition: background-color 0.3s, transform 0.2s;
}
.button:hover {
background-color: #0056b3;
}
.button:active {
transform: scale(0.95);
}
/* 6. Consider reduced motion */
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0.01ms !important;
}
}
/* 7. Use will-change for complex transitions */
.complex {
will-change: transform, opacity;
transition: transform 0.3s, opacity 0.3s;
}
/* Remove after transition */
.complex:hover {
will-change: auto;
}
🎯 Key Takeaways
- Transitions: Smooth changes between property values
- Duration: 200ms-500ms for most interactions
- Timing functions: ease, linear, ease-in, ease-out, custom bezier
- Specific properties: Better performance than "all"
- Transform & opacity: Most performant properties to animate
- Delay: Create staggered effects
- Shorthand: property duration timing-function delay
- Accessibility: Respect prefers-reduced-motion