diff --git a/public/freebies/css-selector-cheat-sheet.avif b/public/freebies/css-selector-cheat-sheet.avif new file mode 100644 index 0000000..4309f27 Binary files /dev/null and b/public/freebies/css-selector-cheat-sheet.avif differ diff --git a/src/blogComponents/cornerShape/CornerShapeExample.astro b/src/blogComponents/cornerShape/CornerShapeExample.astro new file mode 100644 index 0000000..f69294c --- /dev/null +++ b/src/blogComponents/cornerShape/CornerShapeExample.astro @@ -0,0 +1,149 @@ +--- +interface Props { + borderRadius: string + cornerShape: string + hoverCornerShape?: string + selector?: string + width?: string + height?: string +} + +const { + borderRadius, + cornerShape, + hoverCornerShape = cornerShape, + selector, + width = "160px", + height = "160px", +} = Astro.props +--- + +
+
+
+
!
+

+ Your browser doesn't support corner-shape yet +

+

+ This example requires browser support for the + corner-shape property. +

+
+
+ +
+
+
+ {selector && {selector}} +
+
+ + diff --git a/src/blogComponents/cornerShape/CornerShapePlayground.jsx b/src/blogComponents/cornerShape/CornerShapePlayground.jsx new file mode 100644 index 0000000..55a38b8 --- /dev/null +++ b/src/blogComponents/cornerShape/CornerShapePlayground.jsx @@ -0,0 +1,267 @@ +import { useState, useEffect, useRef } from "react" + +const SHAPES = [ + { id: "round", label: "round" }, + { id: "squircle", label: "squircle" }, + { id: "square", label: "square" }, + { id: "bevel", label: "bevel" }, + { id: "scoop", label: "scoop" }, + { id: "notch", label: "notch" }, + { id: "superellipse", label: "superellipse()" }, +] + +const WARNING_CSS = ` + .cs-playground-warning { + display: none; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.75rem; + } + @supports not (corner-shape: round) { + .cs-playground-warning { + display: flex; + } + } +` + +const styles = { + wrapper: { + position: "relative", + border: "1px solid var(--theme-divider)", + borderRadius: "0.5rem", + overflow: "hidden", + margin: "1.5rem 0", + }, + warning: { + position: "absolute", + inset: 0, + backgroundColor: "hsl(41, 100%, 90%)", + border: "2px solid var(--theme-yellow)", + zIndex: 10, + padding: "1.5rem", + textAlign: "center", + }, + warningIcon: { + fontSize: "1.25rem", + fontWeight: "900", + width: "2rem", + height: "2rem", + borderRadius: "50%", + backgroundColor: "hsl(41, 80%, 40%)", + color: "#fff", + display: "flex", + alignItems: "center", + justifyContent: "center", + flexShrink: 0, + }, + warningTitle: { + fontSize: "1.125rem", + fontWeight: "700", + color: "hsl(41, 80%, 20%)", + margin: 0, + }, + warningCode: { + backgroundColor: "hsl(41, 100%, 80%)", + padding: "0.1em 0.3em", + borderRadius: "0.2em", + fontSize: "0.9em", + fontFamily: "monospace", + }, + warningText: { + color: "hsl(41, 60%, 30%)", + margin: 0, + maxWidth: "45ch", + fontSize: "0.875rem", + }, + inner: { + padding: "1.5rem", + display: "flex", + gap: "2rem", + alignItems: "flex-start", + flexWrap: "wrap", + }, + controls: { + flex: "1 1 220px", + display: "flex", + flexDirection: "column", + gap: "1.25rem", + }, + preview: { + flex: "1 1 220px", + display: "flex", + flexDirection: "column", + alignItems: "center", + gap: "1rem", + }, + controlGroup: { + display: "flex", + flexDirection: "column", + gap: "0.5rem", + }, + controlLabel: { + fontWeight: "600", + fontSize: "0.875rem", + color: "var(--theme-text)", + }, + controlSubLabel: { + fontSize: "0.75rem", + color: "var(--theme-text-lighter)", + fontFamily: "monospace", + }, + shapeButtons: { + display: "flex", + flexWrap: "wrap", + gap: "0.5rem", + }, + slider: { + width: "100%", + accentColor: "var(--theme-accent)", + cursor: "pointer", + }, + previewBox: { + width: "160px", + height: "160px", + backgroundColor: "var(--theme-accent)", + }, + codeOutput: { + backgroundColor: "var(--theme-code-bg)", + color: "var(--theme-code-text)", + padding: "0.75rem 1rem", + borderRadius: "0.375rem", + fontFamily: "monospace", + fontSize: "0.8rem", + whiteSpace: "pre", + width: "100%", + overflowX: "auto", + boxSizing: "border-box", + }, + hint: { + fontSize: "0.75rem", + color: "var(--theme-text-lighter)", + fontStyle: "italic", + marginTop: "0.25rem", + }, +} + +function ShapeButton({ id, label, selected, onClick }) { + return ( + + ) +} + +export default function CornerShapePlayground() { + const [shape, setShape] = useState("round") + const [borderRadius, setBorderRadius] = useState(40) + const [superellipseN, setSuperellipseN] = useState(1.5) + const boxRef = useRef(null) + + const cornerShapeValue = + shape === "superellipse" ? `superellipse(${superellipseN})` : shape + + // Apply CSS properties directly to DOM since React doesn't know about corner-shape + useEffect(() => { + if (!boxRef.current) return + boxRef.current.style.setProperty("border-radius", `${borderRadius}px`) + boxRef.current.style.setProperty("corner-shape", cornerShapeValue) + }, [borderRadius, cornerShapeValue]) + + const cssCode = `border-radius: ${borderRadius}px;\ncorner-shape: ${cornerShapeValue};` + + return ( +
+ + diff --git a/src/data/freebies.ts b/src/data/freebies.ts index 6b5b676..cc86cb0 100644 --- a/src/data/freebies.ts +++ b/src/data/freebies.ts @@ -34,6 +34,15 @@ export const freebies: Record = { kitFormId: "9019792", kitFormUrlId: "a485fd2bc3", }, + "css-selector-cheat-sheet": { + title: "CSS Selector Cheat Sheet", + shortTitle: "CSS Cheat Sheet", + description: + "Learn every important CSS selector (from basic to advanced) with visual examples and explanations.", + image: "/freebies/css-selector-cheat-sheet.avif", + kitFormId: "1481102", + kitFormUrlId: "4062a025a6", + }, } export const DEFAULT_FREEBIE_ID = "web-dev-roadmap" diff --git a/src/pages/2026-04/corner-shape/index.mdx b/src/pages/2026-04/corner-shape/index.mdx new file mode 100644 index 0000000..fba2922 --- /dev/null +++ b/src/pages/2026-04/corner-shape/index.mdx @@ -0,0 +1,349 @@ +--- +layout: "@layouts/BlogPost.astro" +title: "I Love the New CSS corner-shape Property" +date: "2026-04-20" +description: "Learn how the new CSS corner-shape property lets you create angled, concave, and squircle corners for some truly unique designs." +tags: ["CSS"] +freebie: "css-selector-cheat-sheet" +--- + +import Tangent from "@blogComponents/lib/Tangent.astro" +import CornerShapeShowcase from "@blogComponents/cornerShape/CornerShapeShowcase.astro" +import CornerShapeExample from "@blogComponents/cornerShape/CornerShapeExample.astro" +import CornerShapePlayground from "@blogComponents/cornerShape/CornerShapePlayground" + +For years, `border-radius` has been the only tool we have for shaping corners in CSS. It is genuinely powerful (we can make pill buttons, circles, and all manner of rounded rectangles), but it only ever gives us one type of corner: a circular or elliptical arc. Every rounded corner on the web looks essentially the same. That changes with the new `corner-shape` CSS property, which lets you control the actual shape of a corner, not just its size. + +_If you prefer to learn visually, check out the video version of this article._ +`youtube: AhBL2MYlQj0` + +## Why `corner-shape` Matters + +The limitation of `border-radius` is subtle but real. No matter what radius you set, the curve you get is always a circular arc. Designers have long wanted: + +- **Angled corners**: straight lines meeting at a point, like a diamond or a cut-gem effect +- **Concave corners**: corners that curve _inward_, creating scooped-out shapes +- **Squircles**: the rounded-square hybrid used by iOS app icons, which is mathematically a superellipse, not a circle + +Before `corner-shape`, achieving any of these required `clip-path`, SVG masks, or complex border tricks, all of which are fragile and hard to combine with other CSS features like `box-shadow` or `border`. The `corner-shape` property solves this cleanly at the CSS level. + +## How `corner-shape` Works + +The `corner-shape` property works together with `border-radius`. Think of it this way: + +- **`border-radius`** defines _how far_ from the corner the curve extends (the size of the corner) +- **`corner-shape`** defines _what shape_ that corner takes (the type of curve) + +Without a `border-radius`, `corner-shape` has no visible effect because there is no corner area to reshape. The two properties are a team. + +```css +.element { + /* border-radius sets the corner size */ + border-radius: 1rem; + /* corner-shape sets the corner shape */ + corner-shape: round; +} +``` + +Here is a preview of some of the things you can do with `corner-shape`, each with the same `border-radius: 40%`: + + + +### Interactive Playground + + + +## `round` + +`round` is the default value and produces the same circular arc you already know from `border-radius`. You will never need to write it explicitly unless you are overriding another value, but it is important to know it exists. + +```css +.card { + border-radius: 1rem; + corner-shape: round; /* This is the default */ +} +``` + + + +## `bevel` + +`bevel` replaces the curved arc with straight lines from point to point. This is great for creating hexagonal or diamond shapes. + +```css +/* With a large border-radius, you get a diamond */ +.diamond { + width: 120px; + height: 120px; + border-radius: 50%; + corner-shape: bevel; +} + +/* With a smaller border-radius, you get a cut-corner effect */ +.cut-corner { + border-radius: 1.5rem; + corner-shape: bevel; +} +``` + +1 + +
+ + +
+ +## `scoop` + +`scoop` is the inverse of `round`. Instead of the corner curving outward like a rounded rectangle, it curves _inward_, creating a concave indentation at each corner. + +```css +.scooped-card { + border-radius: 1.5rem; + corner-shape: scoop; +} + +/* With a large radius, you get a pronounced pinched/star effect */ +.pinched { + border-radius: 40%; + corner-shape: scoop; +} +``` + +
+ + + +
+ +## The `square` Value + +`square` may seem counterintuitive since it completely removes the visual effect of `border-radius`, giving right-angle corners even when `border-radius` is set, but this value is useful for animation. Rather than animating `border-radius` from a value down to `0`, you can keep `border-radius` constant and transition `corner-shape` between values, which makes it easy to create smooth transitions between shape types. + +```css +.button { + border-radius: 0.5rem; + corner-shape: square; + transition: corner-shape 0.3s ease; +} + +.button:hover { + corner-shape: round; +} +``` + + + +## `notch` + +`notch` is the concave counterpart to `square`. While `square` gives right-angle corners, `notch` cuts a straight line _into_ the element, creating a sharp indentation at each corner. + +```css +.notched { + border-radius: 1.5rem; + corner-shape: notch; +} +``` + + + +## `squircle` + +`squircle` produces the rounded-square hybrid. The difference from `round` is subtle, but `squircle` has a more rectangular shape with a softer curve that is especially noticeable at larger `border-radius` values. + +```css +.squircle { + border-radius: 28%; + corner-shape: squircle; +} + +.round { + border-radius: 28%; + corner-shape: round; +} +``` + +Before `corner-shape`, getting a proper squircle required custom SVG or `clip-path` with complex coordinate math. Now it is one CSS property. + +
+ + + +
+ +## `superellipse()` + +The `superellipse()` function is the mathematical foundation that all `corner-shape` keyword values are built on. Each keyword is a shorthand for a specific `superellipse(n)` value: + +| Keyword | Equivalent | Shape | +| ---------- | ------------------------- | ------------------------- | +| `notch` | `superellipse(-infinity)` | Sharp concave right angle | +| `scoop` | `superellipse(-1)` | Concave arc | +| `bevel` | `superellipse(0)` | Straight diagonal line | +| `round` | `superellipse(1)` | Standard elliptical arc | +| `squircle` | `superellipse(2)` | Rounded square | +| `square` | `superellipse(infinity)` | Right-angle corners | + +The `n` parameter controls curvature: + +- **Negative values** produce concave (inward) shapes. The more negative, the sharper the notch. +- **`n = 0`** produces a straight bevel with no curvature. +- **`n = 1`** is a standard circular arc, matching the behavior of `border-radius` alone. +- **Larger positive values** produce shapes that look increasingly square. + +You use `superellipse()` when you want a shape that falls _between_ the named keywords: + +```css +/* Between bevel (n=0) and round (n=1) */ +/* A subtly curved bevel */ +.soft-bevel { + border-radius: 1.5rem; + corner-shape: superellipse(0.5); +} + +/* Between round (n=1) and squircle (n=2) */ +/* Squarer than round, rounder than squircle */ +.soft-squircle { + border-radius: 40%; + corner-shape: superellipse(1.5); +} + +/* Between bevel (n=0) and scoop (n=-1) */ +/* Gentle concave curve */ +.gentle-scoop { + border-radius: 1.5rem; + corner-shape: superellipse(-0.5); +} +``` + +
+ + +{" "} + + + + +
+ +## Controlling Individual Corners + +Just like `border-radius` has individual corner longhand properties (`border-top-left-radius`, etc.), `corner-shape` has its own set of longhands for per-corner control: + +- `corner-top-left-shape` +- `corner-top-right-shape` +- `corner-bottom-right-shape` +- `corner-bottom-left-shape` + +This lets you mix and match shapes on different corners for creative effects: + +```css +/* Speech bubble tail */ +.speech-bubble { + border-radius: 1rem; + corner-shape: round; + /* Make the bottom-right corner pointed for a speech tail */ + corner-bottom-right-shape: square; +} + +/* Mixed decorative element */ +.mixed-corners { + border-radius: 2rem; + corner-top-left-shape: round; + corner-top-right-shape: bevel; + corner-bottom-right-shape: scoop; + corner-bottom-left-shape: superellipse(4); +} +``` + +The `corner-shape` shorthand also accepts up to four values following the same clockwise pattern as `border-radius` (top-left, top-right, bottom-right, bottom-left): + +```css +/* Shorthand: top-left top-right bottom-right bottom-left */ +.mixed-shorthand { + border-radius: 2rem; + corner-shape: round bevel scoop superellipse(4); +} +``` + +
+ + +{" "} + + + +
+ +## Interactive Playground + +Try different values and see exactly what CSS is generated. Use the shape buttons to switch between `round`, `squircle`, `square`, `bevel`, `scoop`, `notch`, and `superellipse()`, and adjust the sliders to fine-tune the result: + + + +## Browser Support + +`corner-shape` currently only has [69% support](https://caniuse.com/mdn-css_properties_corner-shape) and is only available in Chromium-based browsers as of April 2026. + +Because `border-radius` degrades gracefully when `corner-shape` is not recognized, you can start using `corner-shape` today for progressive enhancement without any risk to unsupported browsers. The shape will simply fall back to a standard rounded corner. + +## Conclusion + +The `corner-shape` property is a small addition to CSS that unlocks a surprisingly large design space. For the first time, we can create angled, concave, squircle, and notched corners entirely in CSS without `clip-path`, without SVG, and without losing access to `box-shadow`, `border`, or `overflow`.