Text that wraps tightly around shapes sells the layout before the copy even starts. With the shape-outside property you can bend paragraph flow around circles, triangles, and even image silhouettes. By the end of this article you will build a clean article layout where text wraps a circular badge, a triangular callout, and a photo silhouette, while keeping the code maintainable and readable.
Why shape-outside Matters
Browsers normally wrap around rectangular floats. That wastes space when your art or decoration is not a rectangle. shape-outside defines a non-rectangular contour for wrapping, which gives you magazine-style layouts with straightforward CSS. Unlike clip-path or masks, shape-outside does not cut or hide pixels; it only changes how inline content flows around a float. That split of concerns is powerful: clip-path controls visuals, shape-outside controls text wrap. When you combine both on the same element you get an accurate visual shape with precise wrapping that matches it.
Prerequisites
You do not need a framework. You just need comfort with modern layout basics and a bit of shape math. We will use float because shape-outside applies to floats.
- Basic HTML
- CSS custom properties
- CSS pseudo-elements (::before / ::after)
Step 1: The HTML Structure
The structure uses a single article container with three floated shape elements placed before paragraphs. The floats are decorative and marked as hidden from assistive tech. The rest is plain text content. This makes the reading order and semantics straightforward while giving you fine control over wrap points.
<!-- HTML -->
<article class="demo-article">
<figure class="shape shape-circle" aria-hidden="true"></figure>
<h1>Magazine-style Wrapping with CSS shape-outside</h1>
<p>The first section wraps around a circular badge. We will size the badge with a CSS variable and use the same value for both clip-path (visual) and shape-outside (wrap).</p>
<p>You will see how a tight wrap can improve scanability, reduce awkward line lengths, and create rhythm in a dense block of content. The float stays in the markup where the wrap should begin.</p>
<figure class="shape shape-polygon" aria-hidden="true"></figure>
<p>Next, text wraps a triangular callout pinned to the right. Using polygon() gives full control over the contour, which is perfect for arrows, speech bubbles, or angled treatments.</p>
<p>The polygon is purely decorative. The content reads in a natural order even if the shape is not rendered.</p>
<img class="shape shape-image" src="shape-photo.png" alt="" aria-hidden="true">
<p>Finally, a photo silhouette channels the flow using the image alpha as the wrap shape. The image remains visible while shape-outside: url(...) computes the contour for text to avoid.</p>
<p>This technique works for logos, portraits, and product cutouts, so long as the image has transparent regions that define an interesting silhouette.</p>
</article>
Step 2: The Basic CSS & Styling
We will set a comfortable reading width, define color variables, and create a shared .shape class that floats, sets a size, and applies a shape margin so text does not stick to the edge. Each specific shape will extend this base.
/* CSS */
:root {
--accent: #5f6af3;
--ink: #111;
--paper: #fff;
--muted: #6a6f7a;
--gap: 1.25rem;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html, body {
height: 100%;
}
body {
margin: 0;
color: var(--ink);
background: #f6f7fb;
font: 16px/1.6 system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
}
.demo-article {
max-width: 68ch;
margin: 4rem auto;
padding: 0 1rem;
background: var(--paper);
border-radius: 12px;
box-shadow: 0 6px 24px rgba(0,0,0,.07);
}
.demo-article h1 {
margin: 0 0 1rem;
font-size: 1.8rem;
line-height: 1.2;
letter-spacing: -0.01em;
}
.demo-article p {
margin: 0 0 1rem;
color: var(--ink);
}
.shape {
float: left; /* Required for shape-outside to affect wrapping */
width: 240px;
height: 240px;
margin: 0 var(--gap) var(--gap) 0;
shape-margin: 12px; /* Breathing room between text and shape */
background: var(--accent);
background-size: cover;
background-position: center;
}
Advanced Tip: Put all sizing values behind CSS variables. You can drive both clip-path and shape-outside from the same custom property to keep visuals and wrapping in sync during tweaks or theming.
Step 3: Building the Circular Wrap
We will create a circular badge that text wraps around. The element uses clip-path for the visible circle and shape-outside: circle() for the wrap boundary. Both reference the same radius variable so the outline and wrap match perfectly.
/* CSS */
.shape-circle {
--r: 110px; /* circle radius */
width: calc(var(--r) * 2);
height: calc(var(--r) * 2);
border-radius: 50%; /* visual fallback if clip-path is unsupported */
clip-path: circle(var(--r) at 50% 50%);
shape-outside: circle(var(--r));
background:
radial-gradient(circle at 30% 30%, rgba(255,255,255,.4), transparent 50%),
radial-gradient(circle at 70% 70%, rgba(0,0,0,.12), transparent 55%),
conic-gradient(from 210deg, #9aa6ff, #6f7aff, #5f6af3, #4b57e6, #6f7aff);
}
How This Works (Code Breakdown)
shape-outside only affects floats, so the .shape base class sets float: left. For the circle, we define a radius –r and compute width and height from it. This keeps the element square and makes the circle trivial to maintain.
clip-path: circle(var(–r) at 50% 50%) cuts the element to a perfect circle, while shape-outside: circle(var(–r)) sets the same circle as the wrapping curve. The browser now uses that circle to push inline text away. The radial and conic gradients are cosmetic; you could replace them with a photo or solid color.
If you want a primer on geometric circles in CSS, you can review how to make a circle with CSS. shape-outside builds on that knowledge by applying the circle to the layout flow.
Step 4: Building the Triangular Wrap
Triangles are a common accent for callouts and arrows. polygon() gives you point-by-point control, and you can clip and wrap with the same coordinates to keep edges sharp.
/* CSS */
.shape-polygon {
float: right; /* move the callout to the right side */
width: 240px;
height: 240px;
margin: 0 0 var(--gap) var(--gap);
background:
linear-gradient(135deg, #ffd166, #ef476f);
/* Right-pointing triangle: left edge vertical, apex at middle right */
clip-path: polygon(0 0, 100% 50%, 0 100%);
shape-outside: polygon(0 0, 100% 50%, 0 100%);
}
How This Works (Code Breakdown)
We flip the float to the right for variety and rebuild margins so text does not crash into the shape. The polygon uses three points: top-left, mid-right, and bottom-left. That creates a right-pointing triangle. clip-path uses the polygon to draw the visible area, and shape-outside uses the same points to compute the wrap.
Because polygon coordinates are percentages, the triangle scales with width and height, which makes responsive sizing straightforward. Matching clip-path and shape-outside avoids a mismatch where the text wraps one shape and the pixels show another.
If you want a deeper refresher on CSS triangles, this quick reference on how to make a triangle right with CSS shows the coordinate strategy and alternative border-based methods. For wrapping, polygon() is the most direct tool.
Step 5: Building the Image Silhouette Wrap
shape-outside also accepts an image URL. The browser samples the alpha channel and creates a contour based on opacity. With shape-image-threshold you control the cutoff level. This works best with transparent PNGs or SVGs with non-rectangular transparency.
/* CSS */
.shape-image {
float: left;
width: 260px;
height: 340px; /* Required so the image has a box to scale into */
margin: 0 var(--gap) var(--gap) 0;
object-fit: cover;
border-radius: 8px; /* purely visual */
background: none; /* img tag renders pixels; no gradient here */
/* The wrap shape comes from the same file as the displayed image */
shape-outside: url("shape-photo.png");
shape-image-threshold: 0.5; /* 0..1: higher = tighter wrap around opaque regions */
shape-margin: 14px; /* extra breathing room for a photo */
}
How This Works (Code Breakdown)
We set an explicit width and height because the wrapping shape needs a predictable reference box. The image file is used twice: it draws the pixels in the element and it defines the wrap via shape-outside: url(…). The browser scales the image into the box, samples alpha, and builds a path. shape-image-threshold governs where the cutoff happens. A value of 0.5 means pixels with at least 50% opacity count as inside the shape.
Transparent assets with clean edges yield the best results. Logos on transparent backgrounds or clipped portraits work well. For intricate silhouettes, a gentle shape-margin helps keep text from kissing tiny concavities.
Advanced Techniques: Animations & Hover Effects
You can synchronize visuals and wrapping with CSS variables. The trick: drive both clip-path and shape-outside with the same variables, then animate those variables or dependent properties. Some browsers will animate shape-outside smoothly for circle() and ellipse(); polygons may update per frame or snap between states. Width and height transitions always help the wrap keep up with the visual change.
/* CSS */
.demo-article {
--circle-r: 110px;
--tri-apex: 100%;
--anim-time: 600ms;
--curve: cubic-bezier(.2,.8,.2,1);
}
.shape-circle {
--r: var(--circle-r);
transition:
width var(--anim-time) var(--curve),
height var(--anim-time) var(--curve),
clip-path var(--anim-time) var(--curve);
}
.shape-polygon {
transition:
width var(--anim-time) var(--curve),
height var(--anim-time) var(--curve),
clip-path var(--anim-time) var(--curve);
}
/* Hover the article to grow the badge and pull the triangle's apex inward */
.demo-article:hover {
--circle-r: 140px;
--tri-apex: 85%;
}
.demo-article:hover .shape-circle {
/* width/height follow --r automatically */
/* shape-outside recomputes from the new radius */
}
.demo-article:hover .shape-polygon {
clip-path: polygon(0 0, var(--tri-apex) 50%, 0 100%);
shape-outside: polygon(0 0, var(--tri-apex) 50%, 0 100%);
}
/* Prefer reduced motion: keep layout stable */
@media (prefers-reduced-motion: reduce) {
.shape-circle,
.shape-polygon {
transition: none;
}
}
The hover state increases the circle radius and moves the triangle apex inward via a variable. clip-path transitions smoothly. shape-outside updates on the same frame in many cases, and width/height transitions help keep the wrap coherent even where shape-outside interpolation is limited. The prefers-reduced-motion query removes the animation for users who request less motion.
If organic outlines appeal to you, pair shape-outside with a blob-like clip-path. This guide on how to make a CSS blob organic shape explains strategies for soft, curvy polygons. You can reuse those coordinates for shape-outside to make text flow around the blob.
Accessibility & Performance
shape-outside adjusts line breaks, not reading order. The DOM order in the HTML section remains the order read by assistive tech and search engines. That separation keeps content usable on readers or when CSS fails. The shapes we used are decorative; they include aria-hidden=”true”. If the shape carries meaning, place the content meaning in text next to it or give the image a proper alt attribute that conveys the information.
Accessibility
For decorative figures, an empty alt on the img and aria-hidden=”true” keep redundancy out of screen readers. Keep sufficient contrast between text and any backgrounds around the shapes, because tight wraps bring text close to colored areas. When animations are present, honor the prefers-reduced-motion setting and keep the layout stable. On small screens, test how floats behave; you can disable the float and shape-outside at narrow widths to avoid narrow text columns.
Performance
Wrapping around a circle or ellipse is cheap. Complex polygons with dozens of points cost more because the layout engine must test line fragments against the shape on each reflow. Use the fewest vertices that produce a clean contour. The image-based shape-outside path adds image decoding and sampling; keep assets small and set explicit width and height to avoid layout shifts. Animating clip-path and shape-outside can trigger reflow as the wrap updates; reserve such effects for small elements and short durations. If you need smooth interpolation between polygon shapes, limit the number of points and keep the point ordering consistent.
Shipping Layouts with Edge and Character
You now have a clear recipe for flowing text around circles, triangles, and image silhouettes using shape-outside. The combination of float, clip-path, and a shared set of variables keeps visuals and wrapping aligned and maintainable. Take this pattern and build headers, pull quotes, and editorial features that read well and look intentional.