CSS Transform and Transitions

transform lets you move, rotate, scale, or skew an element without affecting the document layout. Other elements on the page don’t shift when you transform something.

transition makes those changes animate smoothly instead of snapping instantly.

@keyframes lets you define multi-step animations.

transform

translate()

Move an element from its current position. Positive translateX moves right; positive translateY moves down.

/* Move 200px to the right */
img {
  transform: translateX(200px);
}

/* Move 200px to the left */
img {
  transform: translateX(-200px);
}

/* Move 200px down */
img {
  transform: translateY(200px);
}

/* Move 200px up */
img {
  transform: translateY(-200px);
}

/* Move 50px right and 100px down */
img {
  transform: translate(50px, 100px);
}

rotate()

Rotate an element clockwise. Use negative values to rotate counterclockwise.

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

.flipped {
  transform: rotate(-90deg);
}

scale()

Resize an element. scale(1) is normal size. scale(2) doubles it. scale(0.5) halves it.

/* Double the size */
img {
  transform: scale(2);
}

/* Half the size */
img {
  transform: scale(0.5);
}

/* Stretch only horizontally */
img {
  transform: scaleX(3);
}

/* Shrink only vertically */
img {
  transform: scaleY(0.5);
}

skew()

Tilt an element along the x or y axis.

.slant {
  transform: skewX(10deg);
}

.skewed-both {
  transform: skew(10deg, 5deg);
}

Chaining multiple transforms

List them space-separated in a single transform property. They are applied right to left.

.combined {
  transform: translateX(20px) rotate(15deg) scale(1.1);
}

transform-origin

By default, transforms happen around the center of the element (50% 50%). Use transform-origin to change that point.

/* Rotate from the top-left corner instead of the center */
.rotate-from-top {
  transform-origin: top left;
  transform: rotate(45deg);
}

/* Scale from the bottom center */
.grow-up {
  transform-origin: bottom center;
  transform: scale(1.5);
}

transition

transition animates a CSS property change smoothly over time. Define the property to watch, the duration, and the timing curve.

.button {
  background-color: #3b82f6;
  transition: background-color 0.2s ease;
}

.button:hover {
  background-color: #1d4ed8;
}

The shorthand order is: property duration timing-function delay.

Common timing functions:

  • ease: starts fast, slows down at the end (the default)
  • linear: constant speed throughout
  • ease-in: starts slow, ends fast
  • ease-out: starts fast, ends slow
  • ease-in-out: slow at both ends

You can transition multiple properties by separating them with commas.

.card {
  transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}

Avoid transition: all in production. It watches every property, which can cause unexpected animations and hurt performance. List the specific properties instead.

@keyframes animations

For animations that run on load, loop, or have more than two states, use @keyframes.

Define the keyframes first, then apply the animation to an element.

@keyframes fade-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.hero {
  animation: fade-in 0.4s ease forwards;
}

You can also use percentage stops for finer control.

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

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

The animation shorthand takes: name duration timing-function delay iteration-count fill-mode.

Key properties:

  • animation-iteration-count: how many times it runs. Use infinite to loop.
  • animation-fill-mode: forwards keeps the final keyframe state after the animation ends. Without it, the element snaps back to its original styles.
  • animation-delay: wait before starting, e.g. 0.3s.