0

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?

1
  • 4
    Frankly, CSS is a blunt instrument here. Use an SVG or a clip-path. Much simpler all round. Commented Jul 12, 2024 at 14:43

3 Answers 3

5

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>

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Paulie_D. I thought of using a SVG, but I am not really good with SVG's. Appreciate it.
Here the CodePen with your solution (and my requirements): codepen.io/r-w-c/pen/PorqWJK
5

My heart shape works well with some adjustment. There is a little space at the top that is clickable but I don't think it's a big deal.

.heart {
  display: inline-block;
  width: 200px;
  aspect-ratio: 1;
  border-image: radial-gradient(var(--c,red) 69%, #0000 70%) 84.5%/50%;
  clip-path: polygon(-41% 0, 50% 91%, 141% 0);
  border-radius: 30%;
}

a:hover {
  --c: blue;
}
<a class="heart" href="#"></a>

A more complex clip-path can eliminate that space:

.heart {
  display: inline-block;
  width: 200px;
  aspect-ratio: 1;
  border-image: radial-gradient(var(--c,red) 69%, #0000 70%) 84.5%/50%;
  clip-path: polygon(-41% 0,40% 0,50% 8%,60% 0,141% 0,50% 91%);
  border-radius: 30%;
}

a:hover {
  --c: blue;
}
<a class="heart" href="#"></a>

Comments

1

If the background is going to be opaque, then you can change your implementation a bit by adding the correct aspect ratio. Somehow:

body {
  margin: 0;
  display: grid;
  place-items: center;
  min-height: 100dvh;
}

.heart {
    outline: solid 1px green; /* for testing */ 
    
  --bg-color: red;
  --width: 100px;
  --radius: calc(0.25 * var(--width));

  width: var(--width);
  aspect-ratio: 1.171;
  display: grid;
  grid-template-columns: 1fr 1fr;
  pointer-events: none;
  &:hover {
    --bg-color: blue;
  }
  &:before,
  &:after {
    content: '';
    background-color: var(--bg-color);
    border-radius: var(--radius) var(--radius) 0 0;
    transform-origin: var(--radius) var(--radius);
    transition: background-color 0.4s;
    pointer-events: auto;
  }
  &:before {
    rotate: -45deg;
  }
  &:after {
    rotate: 45deg;
  }
}
<a href="#" class="heart"></a>

1 Comment

Thanks. A lot of CSS stuff I don't know. Always nice to learn new things. Appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.