Reputation: 611
I've found the following CSS in one of the answers here on SO and I was wondering why does it create the desired heart shape:
#heart {
position: relative;
width: 100px;
height: 90px;
}
#heart:before, #heart:after {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 50px;
height: 80px;
background: red;
border-radius: 50px 50px 0 0;
transform: rotate(-45deg);
transform-origin: 0 100%;
}
#heart:after {
left: 0;
transform: rotate(45deg);
transform-origin :100% 100%;
}
<div id="heart"></div>
Please can someone explain?
Upvotes: 30
Views: 66966
Reputation: 272899
A new idea with less of code from my website: https://css-tip.com/image-heart-shape/
.heart {
display: inline-block;
width: 200px;
aspect-ratio: 1;
border-image: radial-gradient(red 69%, #0000 70%) 84.5%/50%;
clip-path: polygon(-41% 0, 50% 91%, 141% 0);
}
<div class="heart"></div>
<div class="heart" style="width:100px"></div>
<div class="heart" style="width:50px"></div>
Using mask, we can apply it to an image:
img {
width: 200px;
aspect-ratio: 1;
object-fit: cover;
--_m: radial-gradient(#000 69%,#0000 70%) 84.5%/50%;
-webkit-mask-box-image: var(--_m);
mask-border: var(--_m);
clip-path: polygon(-41% 0,50% 91%, 141% 0);
}
/* fallback until better support for mask-border */
@supports not (-webkit-mask-box-image: var(--_m)) {
img {
--_m:
radial-gradient(at 70% 31%,var(--c) 29%,#0000 30%),
radial-gradient(at 30% 31%,var(--c) 29%,#0000 30%),
linear-gradient(#000 0 0) bottom/100% 50% no-repeat;
-webkit-mask: var(--_m);
mask: var(--_m);
}
}
body {
margin: 0;
min-height: 100vh;
display: grid;
grid-auto-flow: column;
place-content: center;
gap: 30px;
background: pink;
filter: drop-shadow(0 0 10px #ff3e60)
}
<img src="https://picsum.photos/id/1027/300/300" alt="the face of a beautiful girl">
<img src="https://picsum.photos/id/64/300/300" alt="another beautiful girl">
Old answer
Here is another idea using one element and relying on multiple backgrounds to achieve the heart shape. You can also easily adjust the size by only changing the width:
.heart {
width:200px;
background:
radial-gradient(circle at 60% 65%, red 64%, transparent 65%) top left,
radial-gradient(circle at 40% 65%, red 64%, transparent 65%) top right,
linear-gradient(to bottom left, red 43%,transparent 43%) bottom left ,
linear-gradient(to bottom right,red 43%,transparent 43%) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
display:inline-block;
}
.heart::before {
content:"";
display:block;
padding-top:100%;
}
<div class="heart">
</div>
<div class="heart" style="width:100px">
</div>
<div class="heart" style="width:60px">
</div>
<div class="heart" style="width:30px">
</div>
You can also use mask
and you can have any kind of coloration:
.heart {
width:200px;
display:inline-block;
-webkit-mask:
radial-gradient(circle at 60% 65%, red 64%, transparent 65%) top left,
radial-gradient(circle at 40% 65%, red 64%, transparent 65%) top right,
linear-gradient(to bottom left, red 43%,transparent 43%) bottom left ,
linear-gradient(to bottom right,red 43%,transparent 43%) bottom right;
-webkit-mask-size:50% 50%;
-webkit-mask-repeat:no-repeat;
mask:
radial-gradient(circle at 60% 65%, red 64%, transparent 65%) top left,
radial-gradient(circle at 40% 65%, red 64%, transparent 65%) top right,
linear-gradient(to bottom left, red 43%,transparent 43%) bottom left ,
linear-gradient(to bottom right,red 43%,transparent 43%) bottom right;
mask-size:50% 50%;
mask-repeat:no-repeat;
background:linear-gradient(red,blue);
}
.heart::before {
content:"";
display:block;
padding-top:100%;
}
<div class="heart">
</div>
<div class="heart" style="width:100px;background:linear-gradient(45deg,grey 50%,purple 0)">
</div>
<div class="heart" style="width:60px;background:radial-gradient(red,yellow,red)">
</div>
<div class="heart" style="width:30px;background:blue">
</div>
The whole shape is combined using 4 gradients: 2 gradients to create the top part and 2 for the bottom parts. each gradient is taking 1/4 of size and placed at a corner.
Use a different color for each gradient to clearly identify the puzzle
.heart {
width:200px;
background:
radial-gradient(circle at 60% 65%, red 64%, grey 65%) top left,
radial-gradient(circle at 40% 65%, blue 64%, black 65%) top right,
linear-gradient(to bottom left, green 43%,black 43%) bottom left ,
linear-gradient(to bottom right,purple 43%,grey 43%) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
display:inline-block;
border:5px solid yellow;
}
.heart::before {
content:"";
display:block;
padding-top:100%;
}
<div class="heart">
</div>
Upvotes: 22
Reputation: 15356
There are a few steps for creating heart shape using CSS3:
Create a block-level element such as a <div>
in your DOM and assign it with id="heart"
and apply CSS:
#heart {
position:relative;
width:100px;
height:90px;
margin-top:10px; /* leave some space above */
}
Now using pseudo-element #heart:before
we create a red box with one rounded edge like this:
#heart:before {
position: absolute;
content: "";
left: 50px;
top: 0;
width: 52px;
height: 80px;
background: red; /* assign a nice red color */
border-radius: 50px 50px 0 0; /* make the top edge round */
}
Your heart should now look like this:
Let us assign a little rotation to that by adding:
#heart:before {
-webkit-transform: rotate(-45deg); /* 45 degrees rotation counter clockwise */
-moz-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
-webkit-transform-origin: 0 100%; /* Rotate it around the bottom-left corner */
-moz-transform-origin: 0 100%;
-ms-transform-origin: 0 100%;
-o-transform-origin: 0 100%;
transform-origin: 0 100%;
}
And we now get:
Already starting to come together :).
Now for the right part we basically need the same shape only rotated
45 degrees clockwise instead of counter clockwise. To avoid code duplication we attach the css
of #heart:before
also to #heart:after
, and then apply the change
in position and in angle:
#heart:after {
left: 0; /* placing the right part properly */
-webkit-transform: rotate(45deg); /* rotating 45 degrees clockwise */
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transform-origin: 100% 100%; /* rotation is around bottom-right corner this time */
-moz-transform-origin: 100% 100%;
-ms-transform-origin: 100% 100%;
-o-transform-origin: 100% 100%;
transform-origin :100% 100%;
}
And voilà! a complete heart shaped <div>
:
Snippet without any prefix:
#heart {
position: relative;
width: 100px;
height: 90px;
margin-top: 10px;
}
#heart::before, #heart::after {
content: "";
position: absolute;
top: 0;
width: 52px;
height: 80px;
border-radius: 50px 50px 0 0;
background: red;
}
#heart::before {
left: 50px;
transform: rotate(-45deg);
transform-origin: 0 100%;
}
#heart::after {
left: 0;
transform: rotate(45deg);
transform-origin: 100% 100%;
}
<div id="heart"></div>
Upvotes: 54