Loaders✨ Premium

Morphing Shape

50 × 50 px, gradient #6366f1 → #d946ef, four shapes looping over 2 s: circle, square, two opposite diagonal leaves — each state turns a quarter turn. Pure CSS, zero JavaScript.

CSSTransform

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. Loaders has 29 effects, including 4 free. Explore the category →

3 usage examples

Creative tool loading screen — the shape doubles as an animated logo — Morphing Shape example 1

① Creative tool loading screen — the shape doubles as an animated logo

WhenFull-screen splash of a visual editor or image generator, between the click on the app icon and the workspace opening (1–4 s while fonts, layers and modules load): the 50 px shape sits alone at the centre of the dark background, beside the wordmark, with no progress bar.
WhyThis loader is not a spinning ring: its four states — circle, square, two diagonal leaves — are crisp geometric primitives that read like the construction of a logotype, and each quarter turn lands the square flush with the wordmark's baseline. At 50 px with its original indigo → fuchsia gradient it holds the place of an animated logo. And since it is pure CSS it renders from the HTML shell, before the editor's JavaScript bundle — exactly what the screen is waiting for — has even arrived.
SettingsOriginal code untouched: width: 50px; height: 50px, linear-gradient(135deg, #6366f1, #d946ef), animation: 2s ease-in-out infinite — the ease-in-out holds each shape briefly, letting it read as a settled logo. The container carries role="status" aria-live="polite"; the wordmark follows at 20 px inside display: flex; align-items: center.
AI generation zone — waiting for the first response — Morphing Shape example 2

② AI generation zone — waiting for the first response

WhenAn assistant or text-generator interface: after the prompt is sent, before the first token appears, the loader centers itself in the response area.
WhyThe four discrete shape states (circle, square, two diagonals) suggest successive processing phases — more expressive than a plain spinner. The indigo-to-violet palette matches the branding of many AI products.
Settingsanimation-timing-function: linear for a steady, mechanical pace; opacity: 0.8 to fade it once text starts streaming; size unchanged at 50 × 50 px.
File upload — loader centered in the drop zone — Morphing Shape example 3

③ File upload — loader centered in the drop zone

WhenA drag-and-drop area (image, PDF, video): during the server transfer, the loader replaces the drop icon inside the dashed rectangle.
Why50 × 50 px is proportionate for a drop zone of 200 × 120 px or larger. The morphing shapes signal active processing without a progress bar when the duration is unpredictable.
Settingswidth: 48px; height: 48px; animation-duration: 2.5s for a calm pace suited to a transfer that may last several seconds.

How it works

A single div.loader-morph of 50 × 50 px, painted by linear-gradient(135deg, #6366f1, #d946ef) (indigo to rose-violet), receives the animation morphLoader set to 2s ease-in-out infinite. No JavaScript, no extra element, no pseudo-element.

The @keyframes morphLoader defines four states: circle at 0 %/100 % (border-radius: 50%, rotate(0deg)); square at 25 % (border-radius: 0, rotate(90deg)); diagonal leaf A at 50 % (border-radius: 50% 0 — CSS shorthand for TL and BR rounded at 50%, TR and BL sharp —, rotate(180deg)); diagonal leaf B at 75 % (border-radius: 0 50% — TR and BL rounded at 50%, TL and BR sharp —, rotate(270deg)). Each shape state lands at an exact quarter-turn: the square at 90° sits flush with the axes, with no unwanted tilt. The ease-in-out timing holds each shape briefly before the next deformation.

Accessibility

  • prefers-reduced-motion not handled: the animation runs continuously regardless of the user's preference. Add to your CSS: @media (prefers-reduced-motion: reduce) { .loader-morph { animation: none; border-radius: 50%; } } — the element stays visible as a static colored disc.
  • Loading indicator role not declared: the code contains neither role="status", nor aria-busy, nor aria-live, nor an accessible label. Wrap the div in a container with role="status" aria-live="polite" aria-label="Loading" (or set aria-busy="true" on the element it covers) so screen readers announce when loading starts and ends.
  • Contrast: #6366f1 on dark background #0a0a0f measures 4.4:1 and #d946ef measures 3.7:1 — both above the 3:1 threshold for graphical components (WCAG 1.4.11). On a light background both drop below 3:1; adapt the gradient or add a dark background to the container.
  • Non-focusable element: the div is not interactive and does not receive keyboard focus. No label is needed on it; the container carrying role="status" holds the accessible name.

Browser compatibility

Requires unprefixed @keyframes, percentage border-radius, transform: rotate() and linear-gradient. Zero dependencies.

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

Without animation support (old browsers), the element is a fixed 50 × 50 px square with the indigo-violet gradient. Without linear-gradient (IE 8 and below), the element has no visible background.

The code

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

index.html — structure
<div class="loader-morph"></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
Size (CSS — width and height) 50px Both values must stay equal to keep a square. At 20–24 px it fits inside a 44 px button; at 80 px it works as a large page-level indicator.
Gradient colors (CSS — linear-gradient(135deg, #6366f1, #d946ef)) #6366f1 → #d946ef Replace either or both hex values. A translucent white gradient works on a dark button; a flat color (#6366f1, #6366f1) removes the gradient entirely.
Duration (CSS — animation-duration on .loader-morph) 2s 1 s = snappy pace for short waits (< 500 ms); 3 s = calm rhythm for longer generation.
Timing (CSS — animation-timing-function on .loader-morph) ease-in-out ease-in-out holds each shape briefly. linear gives a continuous, uniform motion — more mechanical.
Square shape (CSS — border-radius: 0 at 25 %) 0 (sharp corners) Replace with 4px for a slightly rounded square — a perceptible intermediate between the full circle and the strict square.
Intermediate shapes (CSS — 50% 0 at 50 %, 0 50% at 75 %) TL+BR rounded, then TR+BL rounded Replace 50% 0 with 50% 10% to soften the sharp corners of the diagonal leaves. 30% 0 gives shallower, less pronounced leaves.
prefers-reduced-motion (CSS — to add) absent from the code Add @media (prefers-reduced-motion: reduce) { .loader-morph { animation: none; border-radius: 50%; } } to freeze the indicator on systems that request it.

FAQ

fx-0134 animates border-radius on a variable-size interactive card — no rotation, click to expand, JavaScript required. fx-0431 is a 50 × 50 px loading indicator driven entirely by a CSS animation that coordinates border-radius and rotate() simultaneously, with no JavaScript and no interaction. Context (card vs. loader), scale and mechanics are all different.
The keyframes are built that way: each 25% mark of the cycle adds 90°, totalling 360° per loop. The square therefore always appears axis-aligned, with no unwanted tilt. If you offset — for example rotate(45deg) at 25 % — the square becomes a diamond and the diagonal leaves appear skewed.
The code contains no rule for this media query. Add to your CSS: @media (prefers-reduced-motion: reduce) { .loader-morph { animation: none; border-radius: 50%; } }. The element stays visible as a fixed colored disc — presence confirmed without motion.