⬅ Back

CSS TRANSITIONS

Modern web pages should be both beautiful and convenient.

For example, when you hover over a button, it changes color to attract attention.

That effect can be made in different ways, but one of the simplest methods is CSS transitions.

A developer should not only know what a transition looks like.

It is also important to understand:

1. Quick Roadmap

This note is easier to understand if we move through it in this order:

  1. what a transition is
  2. the four transition properties
  3. how to build a basic transition
  4. real examples
  5. common mistakes and practical rules
  6. related transform effects often used with transitions

2. What a CSS Transition Is

CSS transitions allow us to animate a change in property values.

They let us:

A transition usually starts when an event happens, for example:

Main idea: a transition changes a property from one value to another over time.

3. Two-State Logic

A CSS transition always works between only two states:

  1. the initial value
  2. the final value

So a transition knows how to change:

Example:

The transition changes:

Diagram:

Initial state           Final state
[ blue button ]  --->   [ red button ]

Return:

Mouse leaves
[ red button ]   --->   [ blue button ]

Very important: CSS transitions are best for two-state animations only.

4. Important Limitation

Transitions are good when something changes between two states.

Examples:

But if an animation needs more than two states, then transitions are usually not enough.

In that case, we usually use CSS animation instead.

Simple comparison:

Transition = A <-> B
Animation  = A -> B -> C -> D ...

5. The Four Transition Properties

These four properties control a transition:

transition-property: <property>;
transition-duration: <time>;
transition-timing-function: <timing-function>;
transition-delay: <delay>;

Each property controls a different part of the animation.

6. transition-property

transition-property tells the browser which CSS property should animate.

Example:

transition-property: background-color;

Meaning: animate changes of background-color.

If the background color changes, do it smoothly.

If another property changes, it will not animate unless it is also included.

Example:

.button {
  transition-property: background-color;
}

Diagram:

Allowed to animate:
background-color

Not included:
width
height
opacity

Another example:

transition-property: background-color, transform;

Meaning: animate both:

7. transition-duration

If the transition duration is not specified, the property value changes instantly, without animation.

The transition-duration property sets the amount of time during which the transition should happen.

Syntax:

transition-duration: time;

Time units:

Seconds:

2s
0.5s

Milliseconds:

2000ms
500ms

Important idea: transition-duration controls how long the change takes.

Without it:

old value -> new value instantly

With it:

old value -> smooth change over time -> new value

Example:

.box {
  background-color: teal;
  transition-property: background-color;
  transition-duration: 1000ms;
}

.box:hover {
  background-color: orange;
}

What happens here:

Visual idea:

Without duration:

teal -> orange immediately

With 1000ms:

teal -> smooth color change -> orange

Comparing durations:

Very short duration:

transition-duration: 100ms;

This feels very fast.

Medium duration:

transition-duration: 300ms;

This is a common value for buttons and hover effects.

Long duration:

transition-duration: 2000ms;

This feels much slower and more noticeable.

Seconds vs milliseconds:

transition-duration: 1s;
transition-duration: 1000ms;

Also:

transition-duration: 0.5s;
transition-duration: 500ms;

Multiple durations:

If several properties have different transition times, the durations are listed with commas.

Example:

.box {
  transition-property: background-color, transform;
  transition-duration: 300ms, 600ms;
}

What this means:

The first duration matches the first property. The second duration matches the second property.

Example with two properties:

.box {
  background-color: teal;
  transform: scale(1);
  transition-property: background-color, transform;
  transition-duration: 300ms, 700ms;
}

.box:hover {
  background-color: orange;
  transform: scale(1.2);
}

What happens:

Why duration matters:

Common practical values:

These are very common for simple hover effects.

For larger visual effects, developers may use:

Short summary: transition-duration sets how long a transition lasts. If it is not set, the change happens instantly.

Mini cheat sheet:

100ms   -> very fast
300ms   -> common smooth UI transition
500ms   -> slower, more noticeable
1000ms  -> 1 second

Very short practical rule:

For buttons and hover effects,
300ms is a very common duration.

Simple example:

.button {
  background-color: blue;
  transition-property: background-color;
  transition-duration: 300ms;
}

.button:hover {
  background-color: red;
}

Meaning:

Final summary:

8. transition-timing-function

transition-timing-function controls the speed curve.

It decides how the movement or change behaves over time.

Example:

transition-timing-function: ease;

This does not change the total time.

It changes how the speed feels during that time.

Common values:

Quick meaning:

linear      -> same speed all the time
ease        -> smooth start and end
ease-in     -> slow start
ease-out    -> slow end
ease-in-out -> slow start and slow end

Visual idea:

linear

start ---- same speed ---- end

ease-in

start --slow--> ----faster---- end

ease-out

start ----fast---- -->slow-- end

ease-in-out

start --slow--> --fast-- -->slow-- end

9. transition-delay

transition-delay sets a waiting time before the transition begins.

Example:

transition-delay: 200ms;

Meaning:

Diagram:

hover starts -> wait 200ms -> animation begins

This can be useful, but too much delay may make the interface feel slow.

10. How to Create a Transition

To create a transition, we usually do two things.

Step 1. Define the initial state

Step 2. Define the final state

This is the basic structure.

11. Basic Example

This example shows a button with a smooth color transition.





What it means:


Here is the code for the button above.


<div>
  <div class="button-container">
    <button class="button-item">Hover me</button>
  </div>

  <style>
    .button-container {
      display: inline-block;
    }

    .button-container .button-item {
      background-color: #4caf50;
      color: white;
      border: none;
      padding: 14px 28px;
      font-size: 18px;
      border-radius: 8px;
      cursor: pointer;
      transition: background-color 250ms ease;
    }

    .button-container .button-item:hover,
    .button-container .button-item:focus,
    .button-container .button-item.active {
      background-color: #388e3c;
    }
  </style>

  <script>
    document.querySelectorAll(".button-container .button-item").forEach((button) => {
      button.addEventListener("touchstart", () => {
        button.classList.add("active");
      });

      button.addEventListener("touchend", () => {
        setTimeout(() => {
          button.classList.remove("active");
        }, 250);
      });
    });
  </script>

</div>

Why this works well:

The most important transition line is:

transition: background-color 250ms ease;

Meaning:

So the browser changes the button color smoothly instead of instantly.

Diagram:

normal state  -> green
hover/focus   -> darker green
transition    -> smooth color change in 250ms
touch         -> simulated with .active class

Mini cheat sheet:

:hover   -> mouse interaction
:focus   -> keyboard interaction
.active  -> custom class used here for touch
transition: background-color 250ms ease;

12. Why Transitions Feel Better

Instant changes can feel sharp or rough.

Transitions make interfaces feel:

Example:

Without transition:

Button:
blue -> red instantly

With transition:

Button:
blue -> smooth color change -> red

That small difference often makes the whole interface feel better.

13. Example With a Square

If the lesson says: "Hover over the square to start the transition", that usually means:

Example:


Here is the square





Here is the code for the square


<div>
  <div class="square-container">
    <div class="square-box"></div>
  </div>

  <style>
    .square-container {
      display: inline-block;
    }

    .square-container .square-box {
      width: 100px;
      height: 100px;
      background-color: steelblue;
      transition: background-color 300ms ease;
    }

    .square-container .square-box:hover,
    .square-container .square-box.active {
      background-color: orange;
    }
  </style>

  <script>
    document.querySelectorAll(".square-container .square-box").forEach((box) => {
      box.addEventListener("touchstart", () => {
        box.classList.add("active");
      });

      box.addEventListener("touchend", () => {
        setTimeout(() => {
          box.classList.remove("active");
        }, 300);
      });
    });
  </script>
</div>


Diagram:

Before hover:
[ blue square ]
After hover:
[ orange square ]

Between them:
[ blue ] -> smooth change -> [ orange ]

14. Example With Multiple Properties

A transition can animate more than one property.





What happens on hover:


Diagram:

Before hover:
[ teal box ]

During transition:
[ color changing ] + [ size increasing ]

After hover:
[ bigger orange box ]

This creates a stronger interactive effect.

Here is the code that I used



<div>
  <div class="box-container">
    <div class="box-item"></div>
  </div>

  <style>
    .box-container {
      display: inline-block;
    }

    .box-container .box-item {
      width: 100px;
      height: 100px;
      background-color: teal;
      transition-property: background-color, transform;
      transition-duration: 400ms;
    }

    .box-container .box-item:hover,
    .box-container .box-item.active {
      background-color: orange;
      transform: scale(1.2);
    }
  </style>

  <script>
    document.querySelectorAll(".box-container .box-item").forEach((box) => {
      box.addEventListener("touchstart", () => {
        box.classList.add("active");
      });

      box.addEventListener("touchend", () => {
        setTimeout(() => {
          box.classList.remove("active");
        }, 400);
      });
    });
  </script>
</div>

15. Very Important Rule

Transition settings are usually written in the initial state, not inside :hover.

Correct:

.button {
  transition-property: background-color;
  transition-duration: 300ms;
}

Then:

.button:hover {
  background-color: red;
}

Not usually like this:

.button:hover {
  transition-property: background-color;
}

Why?

Because the browser needs to know in advance how to animate the change.

Simple rule:

Normal state = transition rules
Hover state  = changed values

16. Example With Delay





What happens:

Timeline:

0ms       200ms              700ms
|----wait----|----animate----|

This can be useful for more elegant UI effects.


Here is the code:


<div>
  <div class="card-container">
    <div class="card-box"></div>
  </div>

  <style>
    .card-container {
      display: inline-block;
    }

    .card-container .card-box {
      width: 120px;
      height: 120px;
      background-color: steelblue;
      transition-property: opacity;
      transition-duration: 500ms;
      transition-delay: 200ms;
    }

    .card-container .card-box:hover,
    .card-container .card-box.active {
      opacity: 0.5;
    }
  </style>

  <script>
    document.querySelectorAll(".card-container .card-box").forEach((card) => {
      let removeTimer;

      card.addEventListener("touchstart", () => {
        clearTimeout(removeTimer);
        card.classList.add("active");
      });

      card.addEventListener("touchend", () => {
        removeTimer = setTimeout(() => {
          card.classList.remove("active");
        }, 700);
      });
    });
  </script>
</div>

17. Shorthand Property

Instead of writing four separate properties, we often use the shorthand:

transition: property duration timing-function delay;

Example:

transition: background-color 300ms ease 0ms;

This is the same as:

transition-property: background-color;
transition-duration: 300ms;
transition-timing-function: ease;
transition-delay: 0ms;

This shorter form is very common in real projects.

18. Very Common Button Example

.button {
  background-color: #4caf50;
  transition: background-color 250ms ease;
}

.button:hover {
  background-color: #388e3c;
}

What happens:

Diagram:

Normal:
[ green button ]

Hover:
[ dark green button ]

Transition:
[ green ] -> smooth darkening -> [ dark green ]

19. Simple Full Example





HTML:

<button class="btn">Hover me</button>

CSS:

.btn {
  background-color: royalblue;
  color: white;
  padding: 12px 20px;
  border: none;
  transition: background-color 300ms ease;
}

.btn:hover {
  background-color: tomato;
}

What happens:

20. Another Practical Example



Image


Opacity example:

.image {
  opacity: 1;
  transition: opacity 300ms ease;
}

.image:hover {
  opacity: 0.7;
}

Meaning:

Diagram:

opacity: 1   ->   smooth fade   ->   opacity: 0.7

21. Short Summary of the Four Transition Properties

transition-property

transition-duration

transition-timing-function

transition-delay

Mini cheat sheet:

transition-property        -> what changes
transition-duration        -> how long it takes
transition-timing-function -> speed curve
transition-delay           -> when it starts

22. Very Short Practical Rule

Put transition settings on the normal state,
and put the changed values on :hover.

This is one of the most important rules.

23. Common Mistakes

Mistake 1: putting transition rules only inside :hover.

Problem: the browser may not animate the way you expect.

Mistake 2: forgetting transition-duration.

Problem: without duration, the change happens instantly.

Mistake 3: trying to use transitions for animations with many states.

Problem: transitions are meant for two states only.

Mistake 4: using too long a duration.

Problem: the interface may feel slow or heavy.

Mistake 5: using delay everywhere.

Problem: too much waiting can make the page feel unresponsive.

24. Visual Summary

Without transition:

State A ----> State B instantly

With transition:

State A -> -> -> smooth change -> -> -> State B

Transition logic:

Initial value <----> Final value

Shorthand pattern:

transition: what how-long speed-curve delay;

25. Final Summary

CSS transitions let us smoothly animate property changes between two states.

Important things to remember:

Super short memory line:

transition = smooth change from one state to another

RELATED TRANSFORMATIONS

Transitions are often used together with CSS transformations.

That is why this second part keeps the transform notes and demos in one place.

26. What a Transformation Is

A CSS transformation changes the visual shape or position of an element.

It can:

Main idea: transform changes how an element is displayed, not how the page layout is built.

27. Why Transformations Are Useful

Transformations are often used for interactive effects.

They are especially useful together with CSS transitions.

28. Important Idea About Layout

A transformation usually does not move other elements around it in the normal document flow.

It changes how the element is painted on the screen.

Layout position = where the browser keeps the element
Transform       = how the element is visually shown

29. The Main Property

The main property is:

transform: none;

When we want to apply a transformation, we replace none with one or more transform functions.

30. The Main Transform Functions

transform: translate(...);
transform: scale(...);
transform: rotate(...);
transform: skew(...);

These functions can also be combined in one line.

31. translate() and Axis Shortcuts

translate() moves an element visually along the X and Y axes.

transform: translate(20px, 10px);
Before: [box]
After:      [box]

Axis-specific functions:

transform: translateX(30px);
transform: translateY(15px);

32. scale() and One-Axis Scale

scale() changes the visual size of an element.

transform: scale(1.2);
scale(1)   -> [ box ]
scale(1.2) -> [  bigger box  ]

We can scale only one axis if needed:

transform: scaleX(1.5);
transform: scaleY(0.7);

This can stretch or compress the element horizontally or vertically.

33. rotate(), skew(), and transform-origin

rotate() turns an element around its transform origin.

transform: rotate(45deg);
transform: rotate(-45deg);

skew() slants an element.

transform: skew(20deg, 10deg);

This effect is less common in everyday UI, but it can be useful in decorative designs.

transform-origin sets the point around which a transformation happens.

transform-origin: center;
transform-origin: top left;

This is especially important for rotation and scale.

34. Multiple Transform Functions and Order

We can combine several transform functions in one property.

transform: translateY(-10px) scale(1.05) rotate(2deg);

The order of transform functions is important.

transform: translateX(50px) rotate(45deg);
transform: rotate(45deg) translateX(50px);
same functions + different order = possibly different result

35. Visual Summary of Common Functions

translate() = move
scale()     = resize visually
rotate()    = turn
skew()      = tilt

36. Simple Real UI Examples

Simple hover example:

HTML:

<button class="btn">Hover me</button>

CSS:

.btn {
  transition: transform 300ms ease;
}

.btn:hover {
  transform: scale(1.1);
}

Card lift example:

.card {
  transition: transform 250ms ease, box-shadow 250ms ease;
}

.card:hover {
  transform: translateY(-8px);
}

Rotation example:

.icon:hover {
  transform: rotate(180deg);
}

37. Practical Rule With Transforms

Transformations often look best when combined with transitions.

.item {
  transition: transform 300ms ease;
}

.item:hover {
  transform: scale(1.05);
}
transform changes the visual state
transition makes that change smooth

38. Common Mistakes With Transforms

Mistake 1: expecting transform to change normal page layout.

Problem: nearby elements usually keep their original positions.

Mistake 2: forgetting that order matters in multiple transforms.

Problem: the final visual result may be different from what you expected.

Mistake 3: overusing extreme values.

Problem: too much rotation, scale, or skew can make the UI feel messy.

Mistake 4: using transformation without transition for hover effects.

Problem: the change may feel too sudden.

39. Duration Demo

Here the same hover effect uses three different durations, so you can compare how fast and slow transitions feel.

A transition is triggered when hovering over a container

500ms
1500ms
3000ms


Here is the code

<section>
  <div class="transition-demo-wrapper">
    <h1>A transition is triggered when hovering over a container</h1>

    <div class="flex-container" id="transitionBox">
      <div class="circle">500ms</div>
      <div class="circle">1500ms</div>
      <div class="circle">3000ms</div>
    </div>
  </div>
</section>

<style>
  .transition-demo-wrapper {
    font-family: Arial, sans-serif;
    padding: 30px 20px;
    box-sizing: border-box;
  }

  .transition-demo-wrapper h1 {
    text-align: center;
    font-size: 28px;
    margin-bottom: 30px;
    color: #222;
  }

  .transition-demo-wrapper .flex-container {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 20px;
    flex-wrap: wrap;
    padding: 30px;
    min-height: 220px;
    border: 2px dashed #ccc;
    border-radius: 16px;
    background: #f5f7fa;
    transition: background-color 0.3s ease, border-color 0.3s ease;
    cursor: pointer;
  }

  .transition-demo-wrapper .circle {
    width: 120px;
    height: 120px;
    border-radius: 50%;
    background: #4a90e2;
    color: #fff;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 18px;
    font-weight: bold;
    box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
    transition-property: transform, background-color;
    transition-timing-function: ease;
  }

  .transition-demo-wrapper .circle:nth-child(1) {
    transition-duration: 500ms;
  }

  .transition-demo-wrapper .circle:nth-child(2) {
    transition-duration: 1500ms;
  }

  .transition-demo-wrapper .circle:nth-child(3) {
    transition-duration: 3000ms;
  }

  .transition-demo-wrapper .flex-container:hover .circle,
  .transition-demo-wrapper .flex-container.active .circle {
    transform: translateY(-25px) scale(1.08);
    background: #ff7a59;
  }

  .transition-demo-wrapper .flex-container:hover,
  .transition-demo-wrapper .flex-container.active {
    background: #eef6ff;
    border-color: #4a90e2;
  }
</style>

<script>
  const transitionBox = document.getElementById("transitionBox");

  if (transitionBox) {
    transitionBox.addEventListener("click", function () {
      transitionBox.classList.toggle("active");
    });
  }
</script>

40. Timing Function Demo

This example compares how different timing functions change the motion, even when the duration is the same.


A transition is triggered when hovering over a container


Here is the code

<div class="transition-timing-demo-wrapper">
  <h1>A transition is triggered when hovering over a container</h1>

  <div class="container" id="timingDemoBox">
    <div class="circle"></div>
    <div class="circle"></div>
    <div class="circle"></div>
    <div class="circle"></div>
    <div class="circle"></div>
    <div class="circle"></div>
  </div>
</div>

<style>
  .transition-timing-demo-wrapper {
    font-family: sans-serif;
    text-align: center;
    padding: 20px;
    box-sizing: border-box;
  }

  .transition-timing-demo-wrapper .container {
    border: 2px dashed #2a2a2a;
    border-radius: 4px;
    padding: 10px;
    overflow: hidden;
    --move-distance: 300px;
  }

  .transition-timing-demo-wrapper .circle {
    width: 50px;
    height: 50px;
    border-radius: 10%;
    transform: translateX(0);
    transition-property: transform;
    transition-duration: 2000ms;
  }

  .transition-timing-demo-wrapper .container:hover .circle,
  .transition-timing-demo-wrapper .container.active .circle {
    transform: translateX(var(--move-distance));
  }
</style>

41. Delay Demo

Here is example.




Here is the code

<div class="transition-delay-demo-wrapper">
  <div class="box" id="delayDemoBox"></div>
</div>

<style>
  .transition-delay-demo-wrapper .box {
    transition-property: background-color, transform;
    transition-duration: 500ms;
    transition-timing-function: ease-in-out;
    transition-delay: 500ms;
  }

  .transition-delay-demo-wrapper .box:hover,
  .transition-delay-demo-wrapper .box.active {
    background-color: teal;
    transform: rotate(180deg);
  }
</style>
⬅ Back