—CSS Series · Post 11: Transitions, Transforms & CSS Variables

Transitions, Transforms & CSS Variables — CodeHerWay
CSS Series · Post 11

Transitions, Transforms
& CSS Variables

This post brings your sites to life. Smooth hover effects, subtle movement, and a reusable color system you can change in one place — these three tools are what separate static pages from polished products.

CSS Beginner Series: Post 11 ~13 min read

💬 "Why Does This Feel Cheap?"

The layout is correct. The colors are right. But when you hover over a button it snaps — no fade, no feel. The card jumps up without any softness. Everything technically works but nothing feels considered.

That snap is the absence of transitions. Transitions convert instant state changes into smooth animations, and they require a single line of CSS. This post covers the three properties that close the gap between "it works" and "it feels good."

🧱 Transitions

A transition tells CSS to animate from the old value to the new value when a property changes (on hover, on focus, on class change). Without a transition, the change is instant. With a transition, it's smooth.

hover both buttons — feel the difference
styles.css
CSS · transition
/* transition: property duration timing-function */ .button { background: rgba(255,105,180,0.15); color: #ff69b4; transition: all 0.3s ease; /* smooth ALL changing properties */ } .button:hover { background: #ff69b4; color: #fff; } /* Transition specific properties — better for performance */ .card { transition: transform 0.25s ease, box-shadow 0.25s ease; } /* Timing functions */ /* ease — slow start, fast middle, slow end (default) */ /* ease-in — slow start, fast end */ /* ease-out — fast start, slow end (feels most natural) */ /* linear — same speed throughout */ /* ease-in-out — slow start and end */
✦ transition: all vs Specific Properties

transition: all is convenient but animates everything — including properties like display and height that don't animate well. For production code, list specific properties: transition: transform 0.3s ease, opacity 0.3s ease. It's more intentional and performs better.

🧱 Transform — Move, Scale, Rotate

The transform property manipulates an element's position, size, and rotation without affecting layout. Other elements don't shift to accommodate it. It happens at the compositing layer — which makes it fast and smooth.

hover the cards

Card A

Lifts on hover

Card B

Smooth lift

styles.css
CSS · transform values
/* translateX / translateY — move horizontally / vertically */ .card:hover { transform: translateY(-6px); /* lift up 6px */ } /* scale — grow or shrink */ .icon:hover { transform: scale(1.1); /* 10% bigger */ } /* rotate */ .arrow:hover { transform: rotate(90deg); } /* Combine multiple transforms */ .button:hover { transform: translateY(-2px) scale(1.02); } /* Always add transition on the BASE state — not the :hover */ .button { transition: transform 0.2s ease; /* ← here, not on :hover */ }
ℹ️ Put transition on the Base, Not :hover

If you put transition only on :hover, the effect plays when entering the hover state but snaps back instantly when the cursor leaves. Always put transition on the base element — then it animates both in and out smoothly.

opacity — Fade In and Out

styles.css
CSS · opacity transition
/* Fade an overlay in on hover */ .card-overlay { opacity: 0; transition: opacity 0.3s ease; } .card:hover .card-overlay { opacity: 1; } /* Dim inactive items */ .nav-item { opacity: 0.6; transition: opacity 0.2s ease; } .nav-item:hover, .nav-item.active { opacity: 1; }

🧱 CSS Variables — A Reusable Design System

CSS custom properties (variables) let you define a value once and reuse it everywhere. Change it in one place and every element that references it updates instantly. This is how real design systems work — one source of truth for colors, spacing, and typography.

styles.css
CSS · Custom Properties
/* Define variables on :root — available everywhere */ :root { /* Colors */ --color-bg: #0a0a0f; --color-surface: #12121a; --color-text: #e0e0e8; --color-muted: #9595a8; --color-accent: #ff69b4; /* Transparent layers built from the accent */ --accent-glow: rgba(255, 105, 180, 0.15); --accent-border: rgba(255, 105, 180, 0.25); /* Spacing */ --space-sm: 8px; --space-md: 16px; --space-lg: 24px; --space-xl: 48px; /* Typography */ --font-body: 'Space Grotesk', sans-serif; --font-mono: 'Fira Code', monospace; --radius-card: 12px; } /* Use them with var() */ body { background: var(--color-bg); color: var(--color-text); font-family: var(--font-body); } .card { background: var(--color-surface); border: 1px solid var(--accent-border); border-radius: var(--radius-card); padding: var(--space-lg); transition: border-color 0.3s ease; } .card:hover { border-color: var(--color-accent); }
✦ Rebrand in One Edit

Want to change your accent from pink to purple? Change --color-accent on :root once. Every border, every hover state, every text that uses var(--color-accent) updates instantly — across the whole site. This is the professional reason to use variables, not just convenience.

🛠

Mini Build: Card with Hover Effects + Variable Theme

Build a card that lifts on hover with a smooth transition, using CSS variables for all colors. Then swap the entire theme by changing two variable values.

01

Define your design token variables on :root.

styles.css
CSS
:root { --bg: #0a0a0f; --surface: #12121a; --accent: #ff69b4; /* change this to rebrand */ --glow: rgba(255,105,180,0.12); --text: #e0e0e8; --muted: #9595a8; --radius: 12px; --transition: 0.3s ease; } * { margin: 0; padding: 0; box-sizing: border-box; } body { background: var(--bg); color: var(--text); font-family: sans-serif; padding: 40px 24px; }
02

Build the card with transitions tied to variables.

styles.css
CSS
.card { background: var(--surface); border: 1px solid rgba(255,255,255,0.07); border-radius: var(--radius); padding: 24px; max-width: 320px; transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition); } .card:hover { transform: translateY(-6px); box-shadow: 0 20px 48px rgba(0,0,0,0.5); border-color: var(--accent); background: var(--glow); } .card-tag { font-size: 0.75rem; color: var(--accent); text-transform: uppercase; letter-spacing: 1.5px; margin-bottom: 10px; display: block; }
03

Swap the theme in two lines. Change --accent to #69d2e7 and --glow to rgba(105,210,231,0.12). Your entire card — tag color, hover border, hover background — instantly switches. No hunting through 20 selectors.

💛 Your Sites Have a Pulse Now

The difference between a static page and a product that feels designed often comes down to two things: motion and consistency. Transitions add the motion. CSS variables enforce the consistency. Together they're the finish layer on everything you've built.

  • transition smooths state changes — put it on the base element, not :hover
  • transform: translateY() lifts elements. scale() grows them. rotate() turns them.
  • Transform doesn't affect layout — other elements don't move
  • opacity fades. Pair with transition for smooth reveal effects.
  • CSS variables (--name: value) defined on :root are available everywhere
  • Use var(--name) to reference. Change once, updates everywhere.

Next: Shadows, Depth & Advanced Selectors — box-shadow, ::before/::after, and attribute selectors. The finishing details that make a site feel properly crafted.

🧾 DevFession

For an embarrassingly long time I had transition on my :hover state. Not on the base. On the hover. Which meant hovering in was smooth but leaving was an instant snap, and I genuinely thought that was just how CSS transitions worked.

Someone finally pointed it out in a code review. "Why is your transition only on :hover?" I looked at it. I thought about it. I moved it to the base. Both directions became smooth. That code review note quietly improved every interactive element I've written since.

Base element. Not :hover. Every time.

Previous
Previous

—CSS Series · Post 09: Responsive Design

Next
Next

—CSS Series · Post 10: Specificity & The Cascade