如何使用CSS创建心形图案?

26
我在 SO 上的一个答案中发现了以下 CSS,想知道为什么它创建了所需的心形图案:

我在这里的一个答案中发现了以下 CSS,想知道为什么它创建了所需的心形图案:

#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>

请问有人可以解释一下吗?


心脏带脉搏动的动画: https://youtu.be/Jq4diUd10Zs - Mandeep Pasbola
2个回答

55

CSS3 Mon Amour - 四步恋爱

使用CSS3创建心形需要以下几个步骤:

  1. 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 */
    }
    
  2. 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:

    enter image description here

  3. 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:

    enter image description here

    Already starting to come together :).

  4. 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>:

    enter image description here

没有任何前缀的片段:

#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>


太棒了,真是一项令人着迷的工作!对于其他人,请不要忘记将第一个 #heart:before { 更改为 #heart:before, #heart:after {。尽管 Yotam 说过这个,但我太快了,在尝试代码时没有看到这个信息。 - Avatar
也许在第4步之后添加另一张图像,其中第二个部分是另一种颜色,以更好地显示层次结构?以更好地展示应用的“技巧” :) - Martijn
此外,这些属性不需要供应商前缀 :) 我已经从问题中删除了它们以简化。 - Martijn

19

更少代码的新想法(来自我的文章:https://verpex.com/blog/website-tips/css-shapes-the-heart

.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>

使用遮罩,我们可以将其应用于图像。

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">


旧答案

这里是另一个使用一个元素并依赖多个背景来实现心形的想法。您还可以通过仅更改宽度轻松调整大小:

.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>

CSS heart shape

您还可以使用 mask,并且可以有任何种类的着色:

.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>

CSS heart shape with gradient coloration


它是如何工作的?

整个形状是由4个渐变组合而成:2个用于创建顶部,另外2个用于底部。每个渐变占据1/4的大小,并放置在一个角落。

使用不同的颜色来清晰地标识拼图。

.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>


惊人的答案,您介意稍微解释一下第一个代码片段中如何实现该效果吗? - James
@James 这里有一个示例来理解 clip-path 的作用:https://jsfiddle.net/7xb50yrm/ .. 关于边框部分,我邀请您阅读这个答案以了解它的工作原理:https://dev59.com/erTna4cB1Zd3GeqPCe9k#56915094 - Temani Afif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接