Skip to main content

Command Palette

Search for a command to run...

CSS Transforms & Animation Reference Notes

Updated
3 min read
CSS Transforms & Animation Reference Notes
T

Just a guy who loves to write code and watch anime.

Transform Properties

Traditional Chained Transforms

.element {
  transform: translateY(10px) rotate(45deg) scale(1.2);
  transform-origin: center; /* or specific coordinates like 12px 7px */
}

Individual Transform Properties

.element {
  translate: 10px 20px; /* x y values */
  rotate: 45deg;
  scale: 1.2; /* or 1.2 1.5 for x y */
  transform-origin: 12px 7px;
}

Key Difference: Individual properties don't cascade coordinate systems!

Transform-Origin Deep Dive

The Coordinate System Rule

  • transform-origin uses the same coordinate system as your SVG/element

  • For SVG lines: use the actual x1, y1, x2, y2 coordinate values

  • Not some separate CSS coordinate system

Examples

<!-- SVG with viewBox="0 0 24 24" -->
<line x1="4" y1="7" x2="20" y2="7" />   <!-- Top line -->
<line x1="4" y1="12" x2="20" y2="12" /> <!-- Middle line -->
<line x1="4" y1="17" x2="20" y2="17" /> <!-- Bottom line -->
.top-line {
  transform-origin: 12px 7px; /* SVG center-x, line's actual y */
}
.middle-line {
  transform-origin: 12px 12px; /* SVG center-x, line's actual y */
}
.bottom-line {
  transform-origin: 12px 17px; /* SVG center-x, line's actual y */
}

Result: All lines rotate around the visual center (12,12) of the SVG

Chained Transform Gotcha

/* ❌ Confusing -> coordinate system shifts */
.element {
  transform: translateY(5px) rotate(45deg);
  transform-origin: 12px 7px; /* Must account for the translate! */
}

/* ✅ Intuitive -> no coordinate cascading */
.element {
  translate: 0 5px;
  rotate: 45deg;
  transform-origin: 12px 12px; /* Works as expected */
}

Sequenced Animations

Using Transitions with Individual Properties

.element {
  transition-property: translate, rotate;
  transition-duration: 0.2s, 0.2s;
  transition-delay: 0s, 0.2s; /* translate first, then rotate */
}

.element.active {
  translate: 0 5px;
  rotate: 45deg;
  transition-delay: 0.2s, 0s; /* reverse: rotate first, then translate */
}

Using Keyframes (Often Cleaner)

@keyframes open-animation {
  40% {
    translate: 0 5px;
  } /* move first */
  100% {
    translate: 0 5px;
    rotate: 45deg;
  } /* then rotate */
}

@keyframes close-animation {
  0% {
    translate: 0 5px;
    rotate: 45deg;
  }
  60% {
    translate: 0 5px;
  } /* rotate back first */
  100% {
    translate: 0 0;
  } /* then move back */
}

CSS Attribute Selectors

State-Based Styling

/* Target elements by attribute values */
button[aria-pressed="true"] .icon {
  rotate: 180deg;
}

input[type="email"] {
  border: 2px solid blue;
}

div[data-state="loading"] {
  opacity: 0.5;
}

Common Patterns

[hidden] {
  display: none;
}
[disabled] {
  opacity: 0.5;
}
[aria-expanded="true"] .chevron {
  rotate: 180deg;
}

Common Patterns

Burger Menu Animation

.burger-line {
  transition-property: translate, rotate;
  transition-duration: 0.3s;
  transition-delay: 0.15s, 0s; /* for closing: rotate first, then translate */
}

.burger.open .top-line {
  translate: 0 5px;
  rotate: 45deg;
  transition-delay: 0s, 0.15s; /* for opening: translate first, then rotate */
  transform-origin: 12px 7px; /* where the line actually sits */
}

.burger.open .bottom-line {
  translate: 0 -5px;
  rotate: -45deg;
  transition-delay: 0s, 0.15s;
  transform-origin: 12px 17px; /* where the line actually sits */
}

Hover Effects

.card {
  translate: 0 0;
  scale: 1;
  transition: translate 0.2s, scale 0.2s;
}

.card:hover {
  translate: 0 -4px;
  scale: 1.02;
}

Pro Tips

  1. Individual properties are usually cleaner for complex animations

  2. Transform-origin coordinates match your SVG/element coordinates -> not CSS pixels

  3. Keyframes give you full control over sequenced animations

  4. Attribute selectors are powerful for state-based styling

  5. Always test both directions of your animations (open/close, hover/unhover)