1

I want to make a heart shape which can be resized by usersr to any width and height and have a border of 1 px.

  1. I tried a heart made in pure CSS: https://stackoverflow.com/a/17386187/1404447

  2. I tried using a font, like this: https://www.w3schools.com/charsets/tryit.asp?deci=9829&ent=hearts

  3. and also tried an SVG picture: https://css-tricks.com/hearts-in-html-and-css/#inline-svg

However here are my problems:

  1. It cannot be freely and easily scaled to lets say 500x200 px. It's hard to add a border around it

  2. It cannot be stretched to other proportions and cannot be enlarged to fit into for eg. 500x400 box

  3. It's almost perfect but the border (stroke) stretches with the size. I want the border to be always 1px wide, no matter the scale

I also tried making another copy of the shape as a shadow (filled with black color and slightly offset, with lower z-index) but it isn't perfect (the border is not the same width everywhere):

enter image description here

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Tom
  • 2,962
  • 3
  • 39
  • 69

3 Answers3

2

Probably my heart will do a better job even if still not perfect

.heart {
  width:200px;
  height:200px;
  background:
   radial-gradient(90% 90% at 60% 65%, transparent calc(64% - 1px), black 64%, transparent calc(64% + 1px)) top left,
   radial-gradient(90% 90% at 40% 65%, transparent calc(64% - 1px), black 64%, transparent calc(64% + 1px)) top right,
   linear-gradient(to bottom left,     transparent calc(43% - 1px), black 43%, transparent calc(43% + 1px)) bottom left ,
   linear-gradient(to bottom right,    transparent calc(43% - 1px), black 43%, transparent calc(43% + 1px)) bottom right;
  background-size:50% 50%;
  background-repeat:no-repeat;
  border:2px solid red;
  overflow:hidden;
  resize:both;
}
<div class="heart">
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
1

For SVG, if you want to keep the border (stroke-width) the same relative size,
then recalculate that stroke-width on resize

path.setAttribute("stroke-width", startWidth / divWidth());

(better calculation required)

Wrapped in a W3C Web Component (supported in all modern browsers) with shadowDOM,
encapsulated CSS is simple, and multiple <my-hearts> tags can be used

<style>
  my-heart { --heartwidth: 80px  }
</style>

<my-heart></my-heart>
<my-heart style="--heartwidth:100px"></my-heart>
<my-heart style="--heartwidth:150px"></my-heart>
<my-heart></my-heart>

<script>
  customElements.define("my-heart", class extends HTMLElement {
    constructor() {
      super() // super sets and returns this scope
        .attachShadow({mode:"open"}) // sets and return this.shadowRoot
        .innerHTML = // no need for a Template
        `<style>:host{display: inline-block}
          div {
            width:var(--heartwidth,100px); height:var(--heartwidth,100px);
            resize:both; overflow:auto;
          }
          svg{  
            width:100%; height:100%; background:#ddd; vertical-align:top;
          }
          </style><div><svg preserveAspectRatio="none" viewBox="0 0 34 34">
    <path fill='lightcoral' stroke='red' stroke-width='1' d='m25 2c-3 0-6 3-8 6c-1-3-4-6-8-6c-4 0-8 4-8 8c0 9 10 12 16 21c6-9 16-12 16-21c0-4-4-8-8-8z'/>
    </svg></div>`; // end innerHTML
      let div = this.shadowRoot.querySelector("div");
      let path = this.shadowRoot.querySelector("path");
      let divWidth = () => ~~getComputedStyle(div).width.replace("px", "");
      let startWidth = divWidth();
      div.onmousemove =e=> path.setAttribute("stroke-width", startWidth / divWidth());
    }
  });
</script>
Danny '365CSI' Engelman
  • 16,526
  • 2
  • 32
  • 49
1

The below example is based on a simple web component that is based on iconocss. The drawback of the example is that it uses CSS scale() to achieve the effect you want, so Javascript would be needed dynamically change the scale portion.

html,
body {
  height: 100%;
  width: 100%;
}

:host {
  display: block;
}

pd-indicator:not(:defined) {
  display: none;
}

pd-indicator,
pd-indicator:defined {
  display: block;
  position: absolute;
  top: 20%;
  left: 30%;
  padding: .75rem;
}
pd-indicator:first-child {
  transform: scale(5);
}
pd-indicator:last-child {
  transform: scale(8);
}
<script type="module" src="https://unpkg.com/pd-indicator@1.1.7/pd-indicator.js"></script>
<div class="parent">
  <pd-indicator type="icon-heart" color="000099" active-color="990000"></pd-indicator>
  <pd-indicator type="icon-heart" color="000099" active-color="990000"></pd-indicator>
</div>