Search code examples
htmlcsscss-shapes

Create a (clickable) heart shape using CSS only


Creating a heart shape is not a problem. A few examples can be found here: How to create a heart shape using CSS?

The problem with these solutions is if you want the heart shape to be clickable, the whole HTML element is clickable (a DIV tag or an IMG tag) and not only the heart shape.

I found a solution to create a clickable heart here: https://codepen.io/bailey_jones/pen/jONaONK

Code snippet:

    
    #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%;
    }
<a id="heart" href="#"></a>

Here position: absolute is used. I want to use position: relative and the size of the heart to be relative to the parent container and I want it to be centered in the parent container. which should not be difficult, but my heart shape is malformed.

Code snippet:

body {
  width: 90vw;
  height: 90vh;
}

body,
#container {
  display: flex;
  align-items: center;
  justify-content: center;
}

#container {
  width: 400px;
  height: 400px;
  background: yellow;
}

#heart {
  position: relative;
  --width: 100%; /* was 100px, is 400px */
  --height: 90%; /* was 90px, is 360px */
  --x: calc(.5 * var(--width)); /* was 50px, is 200px */
  --y: calc(8/9 * var(--height)); /* was 80px, is 320px */
  width: var(--width); /* was 100px, is 400px */
  height: var(--height); /* was 90px, is 360px */
  border: 1px dotted blue;
}
#heart:before,
#heart:after {
  position: absolute;
  content: "";
  left: var(--x);
  top: calc(var(--height) - var(--y)); /* Does this make sense? */
  width: var(--x);
  height: var(--y);
  background: red;
  border-radius: var(--x) var(--x) 0 0;
  transform: rotate(-45deg);
  transform-origin: 0 100%;
}
#heart:after {
  left: 0;
  transform: rotate(45deg);
  transform-origin: 100% 100%;
}
<div id="container">

<a id="heart" href="#"></a>

</div>

The worst of all, now not only the heart shape is clickable. Why and how to fix this?


Solution

  • Use an SVG which contains the link you want.

    svg {
      transform:rotate(-135deg);
      stroke: red;
      stroke-width:0;
      height: 50vh;
      margin: 1.5rem;
    }
    
    path {
    fill: red;
    transition: fill 1s ease;
    }
    
    path:hover {
    fill: blue;
    }
    <svg
    xmlns="http://www.w3.org/2000/svg" viewbox="0 0 300 300 " >
      <a href="#">
      <path
        d="M0 200 v-200 h200 
        a100,100 90 0,1 0,200
        a100,100 90 0,1 -200,0
        z" />
      </a>
    </svg>