如何将 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>
我正在尝试构建星级评分功能,我惊讶地发现最麻烦的部分是弄清楚如何获得星形。在我看来,考虑到我已经构建的内容,最直接的方法是尝试使用 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>