# How to Start Entrance Animations from scale(0.95): CSS and React Implementation

> Learn to create subtle pop-in entrance animations starting from scale(0.95) and opacity 0 using CSS and React. Achieve a smooth transition with ease-out curves for a polished UI effect.

- Repository: [Emil Kowalski/skills](https://github.com/emilkowalski/skills)
- Tags: how-to-guide
- Published: 2026-08-04

---

**Start entrance animations from `scale(0.95)` (or any value between 0.9–0.97) combined with `opacity: 0`, then transition to `scale(1)` and `opacity: 1` using a 200ms strong ease-out curve to create a subtle pop-in effect.**

The `emilkowalski/skills` repository defines strict animation standards in [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) that explicitly discourage scaling from zero. Instead, the guidelines prescribe a slight scale-down approach for entrance animations that feels responsive without visual jarring.

## Why You Should Avoid scale(0) for Entrances

According to the source code in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 53-60, you should **never start entrance animations from `scale(0)`**. Scaling from zero creates a dramatic, distracting zoom effect that draws unnecessary attention to the animation itself rather than the content.

The standards define a **modest shrink-to-scale range of 0.9–0.97** as the starting point. This range provides just enough movement to signal "new element arriving" while maintaining subtlety. A value like `scale(0.95)` sits perfectly in the middle of this recommended range, offering a balanced "pop-in" feel.

## Core Animation Standards from STANDARDS.md

### The Scale and Opacity Combination

Always pair the initial scale reduction with `opacity: 0`. The standards require elements to fade in while scaling up, creating a cohesive entrance. In [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 53-60, the reference implementation sets both properties in the initial state class.

### Recommended Easing Curves

For the transition timing, use the **strong ease-out curve** defined in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 31-34:

```css
cubic-bezier(0.23, 1, 0.32, 1)

```

This curve provides a responsive feel with a quick start and gentle deceleration, making the animation feel snappy yet smooth.

### Duration Constraints

Keep entrance animations under 300ms. As specified in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 41-48, **200ms is the recommended sweet spot** for UI-level entrances. Longer durations feel sluggish, while shorter durations risk appearing abrupt.

## Implementing the scale(0.95) Entrance Pattern

### CSS Implementation with data-mounted

The preferred CSS approach uses a base `.enter` class for the hidden state and a `data-mounted` attribute to trigger the transition:

```css
/* Base style – initial hidden state */
.enter {
  transform: scale(0.95);
  opacity: 0;
}

/* Active state – triggered via data attribute */
.enter[data-mounted="true"] {
  transform: scale(1);
  opacity: 1;
  transition: transform 200ms cubic-bezier(0.23, 1, 0.32, 1),
              opacity 200ms cubic-bezier(0.23, 1, 0.32, 1);
}

```

This pattern allows JavaScript to control the timing precisely by toggling the `data-mounted` attribute when the element is ready to appear.

### React Component Pattern

As referenced in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 99-100, use a `useEffect` hook to trigger the animation after mount:

```jsx
import { useEffect, useState } from "react";

export default function EntranceCard({ children }) {
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    // Trigger entrance animation after component mounts
    setMounted(true);
  }, []);

  return (
    <div className="enter" data-mounted={mounted}>
      {children}
    </div>
  );
}

```

The `useState` and `useEffect` combination ensures the animation runs only after the DOM element exists, preventing flashes of unstyled content or premature transitions.

### Web Animations API Approach

For JavaScript-only implementations without CSS classes, use the WAAPI with the same parameters:

```javascript
const element = document.querySelector(".enter");

element.animate(
  [
    { transform: "scale(0.95)", opacity: 0 },
    { transform: "scale(1)", opacity: 1 }
  ],
  {
    duration: 200,
    easing: "cubic-bezier(0.23, 1, 0.32, 1)",
    fill: "forwards"
  }
);

```

This approach provides the same `scale(0.95)` starting point and 200ms duration while allowing dynamic control via JavaScript.

## Summary

- **Never use `scale(0)`** for entrance animations; start from `scale(0.9)` to `scale(0.97)` instead.
- **Combine scale with opacity**: Begin at `opacity: 0` and transition to `opacity: 1` simultaneously.
- **Use the strong ease-out curve**: `cubic-bezier(0.23, 1, 0.32, 1)` as defined in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md).
- **Keep duration at 200ms**: Under the 300ms maximum specified in the standards for UI entrances.
- **Toggle visibility via `data-mounted`**: The recommended pattern in `emilkowalski/skills` uses attribute selectors for clean state management.

## Frequently Asked Questions

### Why is scale(0.95) better than scale(0) for entrance animations?

Starting from `scale(0)` creates a jarring, dramatic zoom effect that distracts users from the content. The `emilkowalski/skills` standards explicitly prohibit this approach in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 53-60 because it violates principles of subtle, functional animation. Starting from `scale(0.95)` provides just enough motion to signal a new element without drawing attention to the animation mechanics.

### Can I use a different scale value like 0.9 or 0.97?

Yes. The standards specify a range of 0.9–0.97, so any value within this range is acceptable depending on your design context. Use `scale(0.9)` for a more pronounced entrance or `scale(0.97)` for an extremely subtle fade-in effect. The key is avoiding the extremes of 0 (too dramatic) or 1 (no animation).

### How do I handle entrance animations for server-side rendered React components?

Apply the `data-mounted` pattern client-side only. Initialize the `mounted` state as `false` and set it to `true` inside `useEffect` (as shown in [`STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/STANDARDS.md) lines 99-100). This ensures the server renders the initial `scale(0.95)` state while the client handles the transition to `scale(1)` after hydration, preventing layout shifts or animation flashes on initial page load.

### Where are the official animation standards documented?

The primary reference is [`skills/review-animations/STANDARDS.md`](https://github.com/emilkowalski/skills/blob/main/skills/review-animations/STANDARDS.md) in the `emilkowalski/skills` repository. This file contains the specific line references for scale ranges (lines 53-60), easing curves (lines 31-34), duration limits (lines 41-48), and React implementation patterns (lines 99-100). The [`SKILL.md`](https://github.com/emilkowalski/skills/blob/main/SKILL.md) file in the same directory provides additional context on how these standards are packaged for team use.