I'm attempting to build a kind of progress bar, similar to what Chris Coyier does here: https://css-tricks.com/css3-progress-bars/, except that I want to apply a SVG clipping path to the surrounding div element.
For example, I want to apply a SVG clipping path to .rating-stars
:
<div class="rating-stars">
<span class="rating"></span>
</div>
You can see what I have so far here: http://codepen.io/rleichty/pen/GrWmRR
It doesn't work in Safari for some reason, and I'm also not sure how to resize the SVG clipping path (if that's even possible).
Does anyone know how I might accomplish this, or perhaps have a better solution?
The path() value allows us to use an SVG path to clip a specific area. For now, the browser support is inconsistent. To make it work across different browsers, we need to use an inline SVG, and then use the url() as a value for clip-path . In CSS, we need to append the path using url() value.
Support for clip-path in SVG is supported in all browsers with basic SVG support. 1 Partial support refers to only supporting the url() syntax. 2 Partial support refers to supporting shapes and the url(#foo) syntax for inline SVG, but not shapes in external SVGs.
The <top> , <right> , <bottom> , and <left> values may be either a <length> or auto . If any side's value is auto , the element is clipped to that side's inside border edge. The element does not clip (default). This is different from rect(auto, auto, auto, auto) , which clips to the element's inside border edges.
Figured it out. Here's the final code here: http://codepen.io/rleichty/pen/zNZajM
HTML:
<div class='rating-container'>
<div class='rating-stars'>
<span class='rating'></span>
</div>
</div>
<svg width='0' height='0'>
<defs>
<clipPath id='svgStars' clipPathUnits = 'objectBoundingBox'>
<polygon points=".80 .073 .738 .118 .762 .19 .70 .145 .638 .19 .662 .118 .60 .073 .538 .118 .562 .19 .50 .145 .438 .19 .462 .118 .40 .073 .338 .118 .362 .19 .30 .145 .238 .19 .262 .118 .20 .073 .138 .118 .162 .19 .10 .145 .038 .19 .062 .118 0 .073 .076 .073 .10 0 .124 .073 .276 .073 .30 0 .324 .073 .476 .073 .50 0 .524 .073 .676 .073 .70 0 .724 .073 .876 .073 .90 0 .924 .073 1 .073 .938 .118 .962 .19 .90 .145 .838 .19 .862 .118 "/>
</clipPath>
</defs>
</svg>
CSS:
$ratingHeight: 100px;
.rating-container {
position: relative;
width: calc((100 / 19) * #{$ratingHeight});
height: $ratingHeight;
}
.rating-stars {
position: absolute;
width: 100%;
height: 0%;
padding-bottom: 100%;
background: lightgray;
-webkit-clip-path: url(#svgStars);
clip-path: url(#svgStars);
-webkit-clip-path: polygon(80% 7.3%, 73.8% 11.8%, 76.2% 19%, 70% 14.5%, 63.8% 19%, 66.2% 11.8%, 60% 7.3%, 53.8% 11.8%, 56.2% 19%, 50% 14.5%, 43.8% 19%, 46.2% 11.8%, 40% 7.3%, 33.8% 11.8%, 36.2% 19%, 30% 14.5%, 23.8% 19%, 26.2% 11.8%, 20% 7.3%, 13.8% 11.8%, 16.2% 19%, 10% 14.5%, 3.8% 19%, 6.2% 11.8%, 0 7.3%, 7.6% 7.3%, 10% 0, 12.4% 7.3%, 27.6% 7.3%, 30% 0, 32.4% 7.3%, 47.6% 7.3%, 50% 0, 52.4% 7.3%, 67.6% 7.3%, 70% 0, 72.4% 7.3%, 87.6% 7.3%, 90% 0, 92.4% 7.3%, 100% 7.3%, 93.8% 11.8%, 96.2% 19%, 90% 14.5%, 83.8% 19%, 86.2% 11.8%);
clip-path: polygon(80% 7.3%, 73.8% 11.8%, 76.2% 19%, 70% 14.5%, 63.8% 19%, 66.2% 11.8%, 60% 7.3%, 53.8% 11.8%, 56.2% 19%, 50% 14.5%, 43.8% 19%, 46.2% 11.8%, 40% 7.3%, 33.8% 11.8%, 36.2% 19%, 30% 14.5%, 23.8% 19%, 26.2% 11.8%, 20% 7.3%, 13.8% 11.8%, 16.2% 19%, 10% 14.5%, 3.8% 19%, 6.2% 11.8%, 0 7.3%, 7.6% 7.3%, 10% 0, 12.4% 7.3%, 27.6% 7.3%, 30% 0, 32.4% 7.3%, 47.6% 7.3%, 50% 0, 52.4% 7.3%, 67.6% 7.3%, 70% 0, 72.4% 7.3%, 87.6% 7.3%, 90% 0, 92.4% 7.3%, 100% 7.3%, 93.8% 11.8%, 96.2% 19%, 90% 14.5%, 83.8% 19%, 86.2% 11.8%);
}
.rating {
position: absolute;
display: block;
width: 50%;
height: 100%;
background-color: orange;
}
You can adjust the height of the stars by adjusting this SCSS variable $ratingHeight: 100px;
You don't need to use the variable, but it makes it simpler to adjust only one value (you could also flip it around so that the width is prioritized).
I found a lot of help here https://sarasoueidan.com/blog/css-svg-clipping/ as she notes:
One important thing to note here is that when you use the
objectBoundingBox
value, the coordinates specified for the contents of the<clipPath>
must be in the range [0, 1]—the coordinate system becomes a unit system, and the coordinates of the shapes inside aclipPath
have to be fractions in that range.
So I had to adjust the SVG coordinates to fractions.
In order to keep the aspect ratio of a percentage based clipping path, I found help out here How do I keep the aspect ratio of a percentage based clipping path? and simply used the padding-bottom
trick.
Now all you need to do is use jQuery to dynamically set the width of the .rating
element to represent a star rating. In my case, I'll be pulling data from Goodreads.
Personally I like this method as opposed to having separate star images for every single rating. It's simpler and more lightweight, as well as being vector based and responsive.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With