CSS Heart Generator
A heart as a single clipped element. Deepen the dip at the top, smooth the curves, and copy a rule you can drop on a button or a like icon.
About the CSS heart
A heart is two circles and a point, and there are two long-standing ways to build one in CSS. The old way stacks three boxes: a square rotated 45 degrees with two rounded lobes positioned on its top and left edges. It is compact, but it is three elements pretending to be one, and it cannot hold content or take a single background across the whole shape.
The other way is to clip the outline out of one element. That is what this generator does, and it means the heart behaves like any other box: one background, one gradient, one hover state, one thing in the DOM.
The code
The rule is long, because the lobes are curves and
clip-path: polygon() only draws straight edges. Here is the
shape of it, with the middle of each lobe cut for readability:
.shape {
aspect-ratio: 1 / 1;
clip-path: polygon(
50% 100%, 41.51% 92.9%, 34.01% 86.15%, 27.43% 79.76%, /* ... */
0.13% 33.12%, 0% 30%, 0.63% 23.32%, 2.48% 16.98%, 5.45% 11.3%,
9.41% 6.55%, 14.15% 2.97%, 19.44% 0.75%, 25% 0%, 30.56% 0.75%,
/* ... */ 94.55% 11.3%, 97.52% 16.98%, 99.37% 23.32%, 100% 30%,
99.87% 33.12%, /* ... */ 58.49% 92.9%, 50% 100%
);
width: 240px;
background: #0d6efd;
}
It starts at the point of the heart, 50% 100%, climbs the
left side to the shoulder at 0% 30%, arcs over the left lobe,
dips to the notch in the middle at 50% 30%, arcs over the right
lobe and comes back down. The Top dip setting moves that notch up and down;
the Roundness setting decides how many segments each arc gets. Copy the real
rule from the tool - the version above is trimmed to be readable, not to be
pasted.
Two settings, quite different hearts
- Top dip - how deep the valley between the lobes goes. A shallow dip gives a soft, rounded heart; a deep one gives the sharp, stylised heart used in playing cards.
- Roundness - segments per arc. Low values are visibly faceted, which can be the look you want; high values are smooth and cost a longer rule. Around 14 is indistinguishable from a real curve at normal sizes.
Where a CSS heart earns its keep
Like buttons and favourite toggles, where the shape needs to change color on click without swapping an image. Rating widgets. Valentine and wishlist graphics that should scale to any size without going soft. And empty states, where a big flat heart in a muted color says "nothing saved yet" better than a sentence does. If the heart is a genuine icon in a toolbar, an SVG is still the more conventional choice - and the generator exports one.
Frequently asked questions
Why is the heart's clip-path so long?
Because it is all curve. polygon() can only join points
with straight lines, so each lobe is drawn as a run of short segments -
the price of a shape that stays responsive. If the length bothers you,
lower the Roundness setting, or export as SVG where two arcs do the same
job in a fraction of the characters.
Can I animate a heart when it is liked?
Yes, and the reliable way is not to animate the shape. Put the
clip-path on the element and animate transform: scale() and
background-color instead - both are cheap, both are smooth,
and the outline stays exactly right throughout. Animating between two
different clip-path polygons only works if they have the same number of
points.
Should I use a heart made of three divs instead?
Only if you need a real border around it, which clipping
cannot give you - though the Border control gets close, stacking the
outline and the fill as two layers on one element. For everything else
the single clipped element is easier: one background, one transition, one
element to position, and it takes a gradient or a photo across the whole
heart rather than three separately coloured pieces.
Can the heart hold a photo?
Yes. Put the clip-path directly on an <img> with
object-fit: cover, or on a container with a
background-image. Keep the 1 : 1 aspect ratio so the heart
is not stretched, and remember the corners of the photo are what get cut
away - centre the subject.