Glassmorphism✨ Premium

Squircle Image Masks

Four 90 px portraits masked as an n = 4 superellipse that, on hover, really tightens towards n = 5 over 0.6 s (two 64-point clip-path: polygon() interpolated by the browser), while a colored ring and the first name appear: a team shown without a caption under each face.

SVGClip-pathHover

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Glassmorphism has 47 effects, including 6 free. Explore the category →

3 usage examples

Team of a health center — “Our carers” page — Squircle Image Masks example 1

① Team of a health center — “Our carers” page

WhenThe patient looks for who will follow them: they hover the four faces — GP, nurse, physiotherapist, midwife — and the first name appears under each.
WhyThe soft shape and the appearing name make the team approachable without turning the page into a directory; the ring, in the profession's color, is read again in the legend at the bottom.
SettingsMasks enlarged to 104 px; first name in #0f172a at 12 px (the code's gray is meant for a dark background); portraits drawn in SVG with one gradient id per scene (msp-g1 to msp-g4); legend of the four ring colors.
Choosing your instructor — surf school — Squircle Image Masks example 2

② Choosing your instructor — surf school

WhenBefore booking a two-hour lesson, the customer hovers the instructors over a swell background: Maëlys, Tiago, Joseph, Inès.
WhyThe superelliptic mask unifies photos taken in very different conditions — beach, water, backlight —: same frame, same corner, whatever the photo's background.
Settings104 px masks, white first name with a drop shadow to read over the sea; portrait backgrounds in wetsuit colors; beginners / advanced split recalled at the bottom.
Authors of a short story collection — a publisher's page — Squircle Image Masks example 3

③ Authors of a short story collection — a publisher's page

WhenRelease page of a four-voice collection: readers hover the authors' portraits under the title.
WhyThe careful shape suits publishing, and the appearing name avoids a caption under each portrait; the tightening from n = 4 to n = 5 gives a discreet movement that stays sober on a book page.
Settings104 px masks on dark paper, full name in ivory serif at 13 px; portraits in muted tones (stone, slate, rust); ids edit-g1 to edit-g4.

How it works

Each .sq-mask (90 × 90 px) holds an image .sq-mask__img — in the sold code, a placeholder SVG portrait: gradient background, head and bust in 30% white —, a ring .sq-mask__ring and a first name .sq-mask__name. The image is cut by clip-path: var(--sqm-squircle), an n = 4 superellipse of 64 points in percentages. On hover it switches to var(--sqm-squircle-tight), n = 5, with transition: clip-path 0.6s cubic-bezier(0.34, 1.56, 0.64, 1): both polygons have 64 points in the same order, so the browser interpolates them. At the 45° point, the edge moves closer to the corner, from 7.2 to 5.8 px on each axis: the mask “tightens” towards a square. Measured during the transition, at 120 ms: 31.5% for a point going from 34.3% to 30.3%, in Chromium 151, Firefox 153 and WebKit 26.

At the same time, over 0.5 s: the block grows 10% (scale(1.1), with a bounce), the ring — 4 px around the image, 2 px border, border-radius: 28% — goes from opacity 0 and scale(0.9) to 1, in the color of its position (violet, pink, cyan, green by :nth-child); the first name (9.6 px, weight 600, #a1a1aa) appears 18 px below the portrait over 0.3 s. The ring is not clipped: it is a sibling of the image, it stays whole around the mask. No JavaScript.

The two masks, --sqm-squircle and --sqm-squircle-tight, are CSS variables with the same structure, with no SVG <clipPath>: that is what lets the hover “tightening” exist. Two url(#…) pointing to missing SVGs would leave square portraits, and even when present they would not interpolate into each other. The placeholder portraits' gradients carry prefixed ids, sqm-grad-1 to 4, so they never clash with a generic id on your page.

Accessibility

  • The first name only appears on hover: with the keyboard it never shows — the .sq-mask blocks are divs with no tabindex (measured: Tab never stops on them). It stays in the DOM at opacity: 0, so screen readers read it. If the portraits lead to a profile, make .sq-mask a link and add .sq-mask:focus-visible .sq-mask__name { opacity: 1 } plus the same rule for the ring, which then serves as the focus indicator (it is not clipped).
  • Images: replace the demo SVGs with <img class="sq-mask__img" src="…" alt="Dr Hélène Marchal, GP"> — object-fit: cover is already in the CSS and clip-path applies to the image. The code's SVGs have no role or title: if they stay decorative, add aria-hidden="true".
  • First-name contrast: #a1a1aa at 9.6 px is 7.7:1 on the dark #0a0a0f background, but 2.6:1 on a white page — and the size is small. On a light background, set .sq-mask__name to #334155 and 12 px. The ring, the only carrier of color, must not be the only way to read a profession: double it with a word. No prefers-reduced-motion: the 10% grow stays active under the preference (measured).

Browser compatibility

CSS only: clip-path: polygon() on an <svg> (or <img>) element, a clip-path transition between two 64-point polygons, custom properties, transform, opacity. Zero JavaScript, no external image. Mask and tightening measured in Chromium 151, Firefox 153 and WebKit 26.

Chrome 55+✓ Full
Firefox 54+✓ Full
Safari 13.1+✓ Full
Edge 79+✓ Full
Mobile iOS 13.4+✓ Full (a tap reveals the name)
Android Chrome 55+✓ Full (a tap reveals the name)

Without clip-path (Firefox before 54, Safari before 13.1 without prefix), the portraits are square; the ring, the grow and the first name still work.

The code

HTML structure to paste into your page (the CSS + JS come with Premium):

index.html — structure
<div class="demo-preview">
  <div class="sq-masks-wrap">
    <div class="sq-mask">
      <svg class="sq-mask__img" viewBox="0 0 90 90">…</svg>
      <span class="sq-mask__ring"></span>
      <span class="sq-mask__name">…</span>
    </div>
    <div class="sq-mask">…</div>
    <div class="sq-mask">…</div>
    <div class="sq-mask">…</div>
  </div>
</div>
Unlock the full code — $9.90/mo incl. tax

The full HTML + CSS + JS of Squircle Image Masks, ready to paste — plus all 840 effects. Or $299 once, lifetime access.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Start and hover shapes (CSS — --sqm-squircle, --sqm-squircle-tight) n = 4, then n = 5 on hover For a more visible tightening, replace the start shape with an n = 3 superellipse (rounder): recompute its 64 points keeping the same order. A polygon with a different point count would break the animation.
Image (HTML — .sq-mask__img) demo SVG portrait, sqm-grad-N gradient Replace the <svg> with an <img> of the same class, with an alt. If you keep SVGs and paste the effect twice, rename the ids of the second copy.
Size (CSS — width / height of .sq-mask) 90 × 90 px The mask is in percentages: it follows. Move .sq-mask__name further down (bottom: -22px) as the size grows.
Ring (CSS — .sq-mask__ring) 4 px around, 2 px border, border-radius: 28% Colors by :nth-child(1) to (4). For a superelliptic ring, replace the border with a background and clip-path on two layers.
Durations (CSS — transition) mask 0.6 s, grow and ring 0.5 s, name 0.3 s Keep the mask longer than the rest: it is the least visible change, it should finish last.

FAQ

It is discreet, on purpose: from n = 4 to n = 5, the edge moves 1.4 px closer to the corner on each axis at 90 px, 1.6 px at 104 px. What shows first is the 10% grow and the ring; the tightening shape goes along with the movement. It only exists because both shapes are 64-point polygon()s: two url(#…) pointing to SVG <clipPath>s would not interpolate.
Yes: <img class="sq-mask__img" src="portrait.jpg" alt="…"> instead of the <svg>. width: 100%, height: 100% and object-fit: cover are already in the CSS: the photo fills the square, then the mask cuts it. Use centered faces, since the top corners are removed.
Because clip-path is set on the image only; the ring is a sibling element, placed 4 px around, with a 28% border-radius. If it were cut by the same shape, its border, which overflows the mask, would be cut off.