@cssints/squircle

Squircle corners for cssints, as one chain member of cssints/plugin scope(): native corner-shape: squircle where the targets have it (Chrome 139), and a CSS mask that cuts the same curve where one lacks it. No script.

import { bg, cn, hover } from "cssints" with { type: "cssints" };
import { squircle } from "@cssints/squircle" with { type: "cssints" };

export const icon = cn(squircle().radius("24px"), bg("tomato"));
export const card = cn(squircle(), hover(squircle().radius("2rem")));
@layer _.k {
  ._squircle-core {
    border-radius: var(--squircle-r);
    corner-shape: squircle;
    --squircle-r: 1rem;
  }
  /* only when a browserslist target lacks corner-shape (Firefox, Safari today) */
  @supports not (corner-shape: squircle) {
    ._squircle-core {
      --squircle-m: url("data:image/svg+xml,%3Csvg … viewBox='-1 -1 2 2' preserveAspectRatio='none'%3E%3Cpath d='M1 0C1 .92 .92 1 0 1…Z'/%3E%3C/svg%3E");
      border-radius: 0;
      mask:
        var(--squircle-m) 0 0 / min(2 * var(--squircle-r), 100%) min(2 * var(--squircle-r), 100%)
          no-repeat,
        var(--squircle-m) 100% 0 / … no-repeat,
        var(--squircle-m) 0 100% / … no-repeat,
        var(--squircle-m) 100% 100% / … no-repeat,
        linear-gradient(#000 0 0) 50% / 100% max(0px, 100% - 2 * var(--squircle-r)) no-repeat,
        linear-gradient(#000 0 0) 50% / max(0px, 100% - 2 * var(--squircle-r)) 100% no-repeat;
    }
  }
}
@layer _.a {
  ._c2r73i {
    --squircle-r: 24px;
  }
}
@layer _.b {
  ._1xgz4ts:hover {
    --squircle-r: 2rem;
  }
}

Browsers

Why a mask

Rules

Limits

cd packages/squircle && bun run test            # fixtures through the engine (output for both kinds of targets, conflicts, errors)
cd packages/squircle && bun run typecheck       # and the type test (test/types)
cd packages/squircle && bun run test:browsers   # Chrome, Firefox and WebKit through playwright-core

Credits

The curve is the superellipse of CSS Borders and Box Decorations Level 4 (corner-shape: squircle). The mask is drawn here; nothing is copied.