Text✨ Premium

Letter Rotate In

Each letter flips 90° on the Y axis to reveal itself face-on — a 3D cascade powered by CSS alone.

JSCSS3D

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Text has 56 effects, including 4 free. Explore the category →

3 usage examples

Portfolio — Hero title for a creative studio — Letter Rotate In example 1

① Portfolio — Hero title for a creative studio

WhenOn initial page load of a portfolio or showcase site: the main headline reveals letter by letter before the rest of the content.
WhyThe 3D rotation entrance makes a memorable first impression and positions the brand as polished. The animation stops once played, without distracting navigation.
Settingsfont-size 4.5rem on .demo-text, step 0.08 s (standard cascade), perspective 500px — a 5 to 7-letter title reveals in under a second.
Online magazine — Article title on scroll — Letter Rotate In example 2

② Online magazine — Article title on scroll

WhenWhen an article or feature title enters the viewport after scrolling, triggered via an IntersectionObserver.
WhyThe letter-by-letter cascade draws the eye to the headline without interfering with the article body below. The short duration does not cause reading fatigue.
Settingsstep reduced to 0.05 s for a faster cascade, font-size 3rem, letter-spacing -0.03em for editorial density.
Video game — Title screen and main menu — Letter Rotate In example 3

③ Video game — Title screen and main menu

WhenAt game launch, before the first click: the game's name assembles letter by letter on the title screen, setting the cinematic mood before any interaction.
WhyThe 3D rotation effect is expected — even desired — for immersion. A large font size (5–8rem) amplifies the perspective depth and makes each tile spectacular without ever hindering usability.
Settingsfont-size 5rem, step 0.10 s for a theatrical cascade, perspective 400px for enhanced distortion, letter-spacing 0.05em to spread the tiles.

How it works

The effect relies on a @keyframes rotateInLetter that animates each letter from rotateY(90deg) opacity:0 to rotateY(0deg) opacity:1. Letters start edge-on — invisible from the front, like a tile seen from the side — and rotate toward the viewer. animation-fill-mode: forwards holds the final state: no JS manages opacity afterwards.

The perspective: 500px on the .text-rotate-in container establishes a shared 3D vanishing point for all letters. Lowering this value (200px) exaggerates the perspective distortion; raising it (1000px) makes the rotation nearly flat and more subtle.

The cascade is achieved via an increasing animation-delay injected as inline style on each <span> (step × index). The splitText(el, text, step) function rebuilds these spans on the fly for the Replay button — but the initial animation can be served entirely as static pre-generated HTML with no runtime JS needed.

Accessibility

  • prefers-reduced-motion absent: no @media (prefers-reduced-motion: reduce) rule in the CSS — letters always animate. Recommended fix: .text-rotate-in span { animation: none; opacity: 1; transform: none; } inside that media query.
  • Text lives in native <span> elements without aria-hidden — screen readers read the letters as the full word. Content remains accessible without extra markup.
  • The Replay button is a native <button>, keyboard-reachable (Tab + Enter/Space).
  • Text contrast in the demo: white on #0a0a0f, ratio ≈ 21:1 — exceeds WCAG AAA (≥ 7:1).
  • Fallback without animation support: letters stay at opacity:0 (initial state). Guard with @supports not (animation-name: none) { .text-rotate-in span { opacity: 1; transform: none; } }.

Browser compatibility

Requires CSS 3D transforms (rotateY) and animation-fill-mode: forwards — supported since Chrome 36, Firefox 16, Safari 9, Edge 12. Zero external dependencies.

Chrome 36+✓ Full
Firefox 16+✓ Full
Safari 9+✓ Full
Edge 12+✓ Full
Mobile iOS✓ Full
Android Chrome✓ Full

Without CSS 3D transform support, letters remain at <code>opacity:0</code> (the animation's initial state). Guard with <code>@supports not (transform: rotateY(0)) { .text-rotate-in span { opacity:1; transform:none; } }</code>.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="demo-preview">
  <span class="demo-text text-rotate-in" id="rotateInText">
    <!-- one <span> per letter with animation-delay = step × index -->
    <span style="animation-delay: 0s">W</span>
    <span style="animation-delay: 0.08s">O</span>
    <span style="animation-delay: 0.16s">R</span>
    <span style="animation-delay: 0.24s">D</span>
  </span>
  <button class="replay-btn" onclick="replayRotateIn()">Replay</button>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
perspective on .text-rotate-in 500px 3D depth: 200px = sharp, expressive flip; 1000px = near-flat rotation. Lower to dramatize the effect.
animation-duration in .text-rotate-in span .5s Per-letter animation duration. .3s = snappy reveal, 1s = dramatic slow entry.
animation-timing-function in .text-rotate-in span ease Easing curve. ease-out = gradual landing, cubic-bezier(0.34,1.56,0.64,1) = slight spring on arrival.
rotateY(90deg) in .text-rotate-in span 90deg Starting angle. rotateY(-90deg) = flip from the other side, rotateX(90deg) = vertical rotation (falling tile effect).
step in splitText(el, text, step) 0.08 Delay gap in seconds between each letter. 0.04 = fast cascade, 0.15 = theatrical slow cascade.
font-size on .demo-text 2.5rem Text size. The effect reads best at 4–8rem where the 3D depth is clearly perceptible.
letter-spacing on .demo-text -.02em Letter spacing. Positive values (0.1em) spread the tiles for a more pronounced visual offset.

FAQ

No, the animation is 100% CSS — @keyframes, 3D transform, and animation. JS is only used for the Replay button. The <span> list with animation-delay can be generated server-side or statically, with no runtime JS needed.
Start all letters with animation-play-state: paused, then switch to running via a class added by an IntersectionObserver. Example: el.classList.add('lri-visible') combined with .lri-visible .text-rotate-in span { animation-play-state: running; }.
Not natively. Add a @keyframes rotateOutLetter (from rotateY(0deg), opacity:1 to rotateY(-90deg), opacity:0) and apply it via an exit class. Chaining entrance and exit creates a reusable typographic ticker.