1

I'm currently building one of my my first projects in HTML/CSS so i'm a newbie. I want to fill a png in function of a percentage but I don't find anything talking about this. I tried using a double image but it's not clean and not working very well

It's a preview of what I did on figma

I want to make this in HTML CSS to integrate in a videogame

Zoral
  • 11
  • 1
  • Do you have an example of an attempt you're trying to troubleshoot a problem with? – Chris W. May 04 '22 at 20:32
  • @ChrisW. Nope, unfortunately i've deleted the code as it was not what I needed I have juste the background of the image on my webpage, I just need to add the fill [link](https://imgur.com/SvypVzl.png) – Zoral May 04 '22 at 20:41
  • I did something [like this](https://imgur.com/9Y3swwR.png) But i want to be linear [like this](https://i.stack.imgur.com/bfhWO.png) – Zoral May 04 '22 at 20:51

2 Answers2

0

I think this could be considered the quickest approach to the problem using just one img element and a css rule.

The picture is a png image I uploaded myself having a yellow background and a transparent hearth shape in the middle.

The filling is made by the background css attribute using linear-gradient to paint a given % of the picture height as blue. Since the shape inside the picture is transparent, the blue color comes out only there.

The demo includes a range slider to show how you can control that % dinamically via js.


EDIT:

I added the solution proposed by @FernandoBravoDiaz just to show how you could fill its hearth shaped with clip-path. Its solution is good enough to be the accepted one.

The solutions you proposed on comments use svg ... unfortunately I don't know how to make an hearth shape that way and it wasn't explored that far in the answer you cited.

I think you can use the @FernandoBravoDiaz solution and just add the linear-gradient strategy to fill it up with a solid color for a given %. I placed the hearth inside a relative positioned container.

document.addEventListener("DOMContentLoaded", ()=>{

  document.querySelector('#giveSupport').addEventListener('change', ()=>{
    sliderPercentage = window.event.target.value;
    
    document.querySelector('img.hearth').style.background = 
      `linear-gradient(to top, blue ${sliderPercentage}%, transparent 0)`;
      
    document.querySelector('.hearthvectorial').style.background = 
      `linear-gradient(to top, blue ${sliderPercentage}%, transparent 0)`;
  });
  
});
/*
---------------------------------------
 Original Solution - Using picture mask
---------------------------------------
*/

.hearth{
  width: 200px;
  /* here you are controlling the % */
  background: linear-gradient(to top, blue 49%, transparent 0);
}

/*
---------------------------------------
 Svg Solution - proposed by
---------------------------------------
*/

.backgroundpage{
  width: 100%;
  height: 200px;
  background: red;
  position: relative;
}

.hearthvectorial {  

  /*position absolute will be relative to the container having position:relative*/
  position: absolute;    
  top: 44px;
  left: 48px;  
  
  /*this is when display: block*/
  /*
  margin-left: 42px;
  margin-top: 42px;
  */
  
  /*size*/
    width: 24px;
    height: 24px;       
  
  /*hearth shape*/
    clip-path: path("M12 4.419c-2.826-5.695-11.999-4.064-11.999 3.27 0 7.27 9.903 10.938 11.999 15.311 2.096-4.373 12-8.041 12-15.311 0-7.327-9.17-8.972-12-3.27z");  
    transform: scale(5);
  
  /*background strategy to fill %*/
  background: linear-gradient(to top, blue 100%, transparent 0);
}
<img
  src="https://i.ibb.co/68RY3q8/UA.png"
  class="hearth" />
  
<input
  type="range"
  id="giveSupport"
  style="cursor:pointer;"
  min="0"
  max="100" />
  
  <hr>
  
  <h1>Solution proposed by @FernandoBravoDiaz</h1>
  
  <div class="backgroundpage">    
    <div class="hearthvectorial">
    </div>  
  </div>
Diego D
  • 6,156
  • 2
  • 17
  • 30
  • Yes, but i don't want the yellow part, because your yellow part must be transparent in my render as it will be displayed in a video game – Zoral May 04 '22 at 21:07
  • Okay but like i told you I cant have the yellow border, it must be totally transparent – Zoral May 04 '22 at 21:20
  • I made that edit adding the js while you pointed out I didn't correctly get the request. Yes you are right. I didn't notice that you needed the shape to be solid with a transparent background. In that case my approach to get the shape via image transparency mask is out of the game. And I'm afraid I'm out of clue right in this moment – Diego D May 04 '22 at 21:24
  • I'll be seriously following this question because I'll be curious to hear other answers. So far the only working approach I could think of is through css composition using box-shadow or intermittent different border-radius on each corner or anything like that to overcome the box model... and that's not how wish this was solved. I'd prefer the mask approach if someone will come up with anything like that – Diego D May 04 '22 at 21:30
  • Diego, [I just found this on another topic](https://stackoverflow.com/questions/32645053/is-it-possible-to-make-svg-circle-fill-color-from-bottom-to-top-based-on-percent) Could you tell me if it can be used for my problem and if yes how ? – Zoral May 04 '22 at 22:16
0

You could also use CSS crop on some divs instead of an image, that will make your code something like this:

A container, two hearth shaped divs and a button for triggering the fill

<!-- A wrapper for the hearths -->
<div class="container">
    <!-- A shape that serves as the placeholder -->
    <div class="hearth base"></div>
    <!-- The shape that is going to be filled -->
    <div class="hearth color"></div>
</div>
<button onclick="fillHearth()" >Fill Hearth</button>

The styles

.container {
  margin: 70px;
  display:flex;
  flex-wrap: wrap;
  gap: 10px 120px;
  position: relative;
}
.hearth {
  position: absolute;
  width: 24px;
  height: 24px;
  clip-path: path("M12 4.248c-3.148-5.402-12-3.825-12 2.944 0 4.661 5.571 9.427 12 15.808 6.43-6.381 12-11.147 12-15.808 0-6.792-8.875-8.306-12-2.944z");
  transform: scale(5);
}
.base {
  background: #cecece;
}
.color {
  background: transparent;
}

The script that fills the hearth in an interval of half a second

function fillHearth(argument) {
    let current = 0;
    console.log('Filling hearth');
    const interval = setInterval(() => {
        console.log('Current: ', current);
        document.querySelector('div.color').style.background = 
              `linear-gradient(to top, #FF5252 ${current}%, transparent 0)`;
        current += 10;
        if (current > 100) clearInterval(interval);
    }, 500);
}

The crop shape was taken from here

Fernando Bravo Diaz
  • 551
  • 1
  • 4
  • 11