I'm trying to build a star rating feature, and am surprised to find that the part that's giving me the most trouble is figuring out how to get the star shape. It seems to me that the most straightforward approach, given what I have built already, is to try and use an SVG star shape to create a clip path on the div elements that show the rating. I'm familiar with clip-path in a general sense, and have used it for more basic shapes, but am struggling a lot to understand how to use it with an svg and why my current code is not working (svgs are not exactly in my typical wheelhouse).
The code:
const stars = document.getElementsByClassName('star');
function fillStars(starClasses, placeRating) {
const wholeFill = Math.floor(placeRating);
const decimalFill = placeRating % 1;
const yellowFill = decimalFill.toFixed(2).toString().replace('0.', '');
for (let i = 0; i < wholeFill; i++) {
starClasses[i].style.backgroundColor = '#fbff01';
}
if (placeRating - wholeFill !== 0) {
starClasses[starClasses.length - 1].style.background = `linear-gradient(90deg, #fbff01 ${yellowFill}%, #FFFFFF 0%)`;
}
}
fillStars(stars, 4.3);
.star {
width: 30px;
height: 30px;
border: solid 1px gray;
clip-path: url(#star-clip);
}
#rating {
display: flex;
}
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
<defs>
<clipPath id="star-clip" clipPathUnits="objectBoundingBox">
<rect fill="#fff" id="canvas_background" height="40" width="41" y="-1" x="-1"/>
<rect fill="url(#gridpattern)" stroke-width="0" y="0" x="0" height="100%" width="100%"/>
<path id="svg_1" d="m3.885,14.64105l11.84103,0l3.65897,-12.22295l3.65897,12.22295l11.84103,0l-9.57958,7.55411l3.65916,12.22295l-9.57958,-7.55431l-9.57958,7.55431l3.65916,-12.22295l-9.57958,-7.55411z" stroke-width="1.5" stroke="#000" fill="#fff"/>
</clipPath>
</defs>
</svg>
<div id="header">
<div id="rating">
<div id="star-1" class="star"></div>
<div id="star-2" class="star"></div>
<div id="star-3" class="star"></div>
<div id="star-4" class="star"></div>
<div id="star-5" class="star"></div>
</div>
</div>