如何将 svg 用于剪辑路径

How to use svg for clip path

我正在尝试构建星级评分功能,我惊讶地发现最麻烦的部分是弄清楚如何获得星形。在我看来,考虑到我已经构建的内容,最直接的方法是尝试使用 SVG 星形在显示评级的 div 元素上创建剪辑路径。我在一般意义上熟悉 clip-path,并将它用于更基本的形状,但我很难理解如何将它与 svg 一起使用以及为什么我当前的代码不起作用(svgs 不完全在我典型的操舵室)。

代码:

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>

你可以使用 clip-path: polygon(); 吗?

我认为 url(#id) 不完全支持或难以正确。

与边框无关:边框将应用于边界框

看到最后一颗星星

.star {
  width: 50px;
  height: 50px;
  background-color: pink;
  border: solid 1px gray;
  clip-path: polygon(54.5% 24.5%, 80.25% 24.27%, 60.73% 34.91%, 75% 52.25%, 44.5% 41.24%, 15% 52.75%, 30.00% 34.75%, 1.5% 25.25%, 31.77% 24.86%, 41.82% 9.01%);
 
}

.star-last {
  background-color: #f1e745;
  height: 50px;
  width: 50px;
  clip-path: polygon(54.5% 24.5%, 80.25% 24.27%, 60.73% 34.91%, 75% 52.25%, 44.5% 41.24%, 15% 52.75%, 30% 34.75%, -200.42% 25.25%, 31.77% 24.86%, 41.82% 9.01%);
  border: 1px solid black;
}
      
#rating {
  display: flex;
}
   
    <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-last"></div>
      </div>
    </div>

编辑:正如我所说,很难正确使用标准 SVG 路径,但是添加变换比例是您需要做的,正如所选答案中指出的那样,我现在学到了一些东西。以下是实现相同目的的其他方法,但选择的答案是最好的方法。

也许这是你的路径定义,正如我在我的其他回答中所说 url(#id) 似乎有点难以正确使用标准 SVG 路径。

我从 MDN 复制了一条心路并删除了矩形,你的代码有效。

编辑:如果您不能为星形路径计算出正确的定义语法,则可以使用 CSS 中的 polygon() 代码作为十进制代替 svg 中的路径。 从 svg 中删除 <path> 并替换为.

 <polygon points="0.545 0.245, 0.8025 0.2427, 0.6073 0.3491, 0.75 0.5225, 0.445 0.4124, 0.15 0.5275, 0.3000 0.3475, 0.15 0.2525, 0.3177 0.2486, 0.4182 0.0901" />

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">
         <path d="M0.5,1
                    C 0.5,1,0,0.7,0,0.3
                    A 0.25,0.25,1,1,1,0.5,0.3
                    A 0.25,0.25,1,1,1,1,0.3
                    C 1,0.7,0.5,1,0.5,1 Z" ></path>     
      </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>

关于从原始 SVG 尺寸计算 clipPath 的 0-1 范围,有一个很好的答案here

.star {
  width: 30px;
  height: 30px;
  clip-path: url(#star-clip);
  background: Gold;
}

#rating {
  display: flex;
}
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0">
  <defs>
    <clipPath id="star-clip" clipPathUnits="objectBoundingBox" transform="scale(0.025, 0.02439)">
      <path 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" />
    </clipPath>
  </defs>
</svg>

<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>