Transferring variables from CSS or HTML to inline SVG

I want to create a unique SVG star rating component using a single SVG.

The shape consists of 5 stars filled with a horizontal gradient. Take a look at the following code snippet:

<svg width="68" height="11" viewBox="0 0 68 11">
  <linearGradient id="grad">
        <stop offset="70%" stop-color="tomato"/>
        <stop offset="70%" stop-color="grey"/>
   </linearGradient>
  <g fill="url(#grad)">
    <path d="M6 8.84L9.708 11l-.984-4.07L12 4.192l-4.314-.354L6 0 4.314 3.838 0 4.192 3.276 6.93 2.292 11zM20 8.84L23.708 11l-.984-4.07L26 4.192l-4.314-.354L20 0l-1.686 3.838L14 4.192l3.276 2.738-.984 4.07zM34 8.84L37.708 11l-.984-4.07L40 4.192l-4.314-.354L34 0l-1.686 3.838L28 4.192l3.276 2.738-.984 4.07zM48 8.84L51.708 11l-.984-4.07L54 4.192l-4.314-.354L48 0l-1.686 3.838L42 4.192l3.276 2.738-.984 4.07zM62 8.84L65.708 11l-.984-4.07L68 4.192l-4.314-.354L62 0l-1.686 3.838L56 4.192l3.276 2.738-.984 4.07z"/>
  </g>
</svg>

The star rating can be in decimals, not just full or half stars, such as 3.35.

My main challenge is how to define offset="70%" dynamically.

  • Is there a way to pass a percentage to SVG? (e.g., using currentColor to pass color from CSS)
  • Is it possible to apply a linear gradient without referencing it by url(#id)? I want to avoid generating unique IDs for each rating on the page.
  • Or maybe there's a way to fill a certain percentage of horizontal space just through CSS?

Answer №1

You have the option of using your SVG as a background, giving you full control over the size:

.rating {
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="68" height="11" viewBox="0 0 68 11"><path fill="grey" d="M6 8.84L9.708 11l-.984-4.07L12 4.192l-4.314-.354L6 0 4.314 3.838 0 4.192 3.276 6.93 2.292 11zM20 8.84L23.708 11l-.984-4.07L26 4.192l-4.314-.354L20 0l-1.686 3.838L14 4.192l3.276 2.738-.984 4.07zM34 8.84L37.708 11l-.984-4.07L40 4.192l-4.314-.354L34 0l-1.686 3.838L28 4.192l3.276 2.738-.984 4.07zM48 8.84L51.708 11l-.984-4.07L54 4.192l-4.314-.354L48 0l-1.686 3.838L42 4.192l3.276 2.738-.984 4.07zM62 8.84L65.708 11l-.984-4.07L68 4.192l-4.314-.354L62 0l-1.686 3.838L56 4.192l3.276 2.738-.984 4.07z"/></svg>');
  width: 68px;
  height: 11px;
}

.rating:before {
  content: "";
  display: block;
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="68" height="11" viewBox="0 0 68 11"><path fill="tomato" d="M6 8.84L9.708 11l-.984-4.07L12 4.192l-4.314-.354L6 0 4.314 3.838 0 4.192 3.276 6.93 2.292 11zM20 8.84L23.708 11l-.984-4.07L26 4.192l-4.314-.354L20 0l-1.686 3.838L14 4.192l3.276 2.738-.984 4.07zM34 8.84L37.708 11l-.984-4.07L40 4.192l-4.314-.354L34 0l-1.686 3.838L28 4.192l3.276 2.738-.984 4.07zM48 8.84L51.708 11l-.984-4.07L54 4.192l-4.314-.354L48 0l-1.686 3.838L42 4.192l3.276 2.738-.984 4.07zM62 8.84L65.708 11l-.984-4.07L68 4.192l-4.314-.354L62 0l-1.686 3.838L56 4.192l3.276 2.738-.984 4.07z"/></svg>');
  height: 100%;
  width: var(--p, 50%);
}
<div class="rating"></div>
<div class="rating" style="--p:20%"></div>
<div class="rating" style="--p:80%"></div>
<div class="rating" style="--p:100%"></div>

To ensure broader compatibility, you may opt to replace CSS variables with standard CSS:

.rating {
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="68" height="11" viewBox="0 0 68 11"><path fill="grey" d="M6 8.84L9.708 11l-.984-4.07L12 4.192l-4.314-.354L6 0 4.314 3.838 0 4.192 3.276 6.93 2.292 11zM20 8.84L23.708 11l-.984-4.07L26 4.192l-4.314-.354L20 0l-1.686 3.838L14 4.192l3.276 2.738-.984 4.07zM34 8.84L37.708 11l-.984-4.07L40 4.192l-4.314-.354L34 0l-1.686 3.838L28 4.192l3.276 2.738-.984 4.07zM48 8.84L51.708 11l-.984-4.07L54 4.192l-4.314-.354L48 0l-1.686 3.838L42 4.192l3.276 2.738-.984 4.07zM62 8.84L65.708 11l-.984-4.07L68 4.192l-4.314-.354L62 0l-1.686 3.838L56 4.192l3.276 2.738-.984 4.07z"/></svg>');
  width: 68px;
  height: 11px;
}

.rating > div {
  background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="68" height="11" viewBox="0 0 68 11"><path fill="tomato" d="M6 8.84L9.708 11l-.984-4.07L12 4.192l-4.314-.354L6 0 4.314 3.838 0 4.192 3.276 6.93 2.292 11zM20 8.84L23.708 11l-.984-4.07L26 4.192l-4.314-.354L20 0l-1.686 3.838L14 4.192l3.276 2.738-.984 4.07zM34 8.84L37.708 11l-.984-4.07L40 4.192l-4.314-.354L34 0l-1.686 3.838L28 4.192l3.276 2.738-.984 4.07zM48 8.84L51.708 11l-.984-4.07L54 4.192l-4.314-.354L48 0l-1.686 3.838L42 4.192l3.276 2.738-.984 4.07zM62 8.84L65.708 11l-.984-4.07L68 4.192l-4.314-.354L62 0l-1.686 3.838L56 4.192l3.276 2.738-.984 4.07z"/></svg>');
  height: 100%;
  width:50%;
}
<div class="rating"></div>
<div class="rating" ><div style="width:20%"></div></div>
<div class="rating" ><div style="width:80%"></div></div>
<div class="rating" ><div style="width:100%"></div></div>

Answer №2

To achieve this effect, you can utilize SVG clipping.

.rating {
  position: relative;
  height: 11px;
  width: 68px;
  background: grey;
  clip-path: url(#myClip);
}

.fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  background: tomato;
}
<svg width="68" height="11" viewBox="0 0 68 11">
  <defs>
    <clipPath id="myClip">
      <path d="M6 8.84L9.708 11l-.984-4.07L12 4.192l-4.314-.354L6 0 4.314 3.838 0 4.192 3.276 6.93 2.292 11zM20 8.84L23.708 11l-.984-4.07L26 4.192l-4.314-.354L20 0l-1.686 3.838L14 4.192l3.276 2.738-.984 4.07zM34 8.84L37.708 11l-.984-4.07L40 4.192l-4.314-.354L34 0l-1.686 3.838L28 4.192l3.276 2.738-.984 4.07zM48 8.84L51.708 11l-.984-4.07L54 4.192l-4.314-.354L48 0l-1.686 3.838L42 4.192l3.276 2.738-.984 4.07zM62 8.84L65.708 11l-.984-4.07L68 4.192l-4.314-.354L62 0l-1.686 3.838L56 4.192l3.276 2.738-.984 4.07z"/>
    </clipPath>
  </defs>
</svg>

<div class="rating">
  <div class="fill" style="width: 55%;"></div>
</div>
<div class="rating">
  <div class="fill" style="width: 80%;"></div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Having trouble with CSS Locator identifying an element in your Protractor Test?

In the Protractor test snippet below, I am attempting to calculate the quantity of div elements using the CSS locator: let list = element.all(by.css('div[class="ag-header-cell ag-header-cell-sortable"]')); expect(list.count()).toBe(11); ...

Is it possible to incorporate a 960 grid system into a div container?

Can I contain an entire 960 grid within a div on my webpage? I am looking to create a page wider than 960px, and considering placing sidebars outside of the 960 grid while having it manage the central column. ...

Filtering, cleaning, and confirming the validity of data input allowed for HTML tags

While there is a lot of information available on sanitizing, filtering, and validating forms for simple inputs like email addresses, phone numbers, and addresses, the security of your application ultimately relies on its weakest link. What if your form inc ...

What is the process for including body text in a Bootstrap tooltip?

I am attempting to enhance a Bootstrap tooltip by adding body text, as it typically only includes a basic title. After reviewing the Bootstrap 5 documentation, it seems that the simplest approach is to utilize the template option: template Base HTML used ...

Creating a multi-column ordered list that spans multiple pages is a great way to organize and

My goal is to showcase a numbered list in a three-column format, following the guidelines presented in this particular query. However, I am looking to maintain the continuity of the list across different pages by ensuring that the subsequent item on the ...

The art of positioning in menu - absolute versus relative

Struggling with positioning absolute divs is a common challenge for many of us. In my case, it's horizontal sub-menus with the following CSS: ul.children{ display:none; position:absolute; } ul.children li{ position:relative; height:60px; float:none; ...

Material-UI icons refusing to show up on the display

I've been working on creating a sidebar component and importing various icons to enhance the UI, but for some reason they are not displaying on the screen. I even tried other suggested solutions without success. <SidebarOption Icon = {InsertComment ...

Transferring information to the controller and refreshing the interface (Single-page design)

I'm stuck on a personal project and could really use some help. If anyone has any feedback, it would be greatly appreciated. Thanks in advance. In my index.php file, I have a div with the id main-container. Inside this container, there are two separa ...

methods for adjusting the transparency of the background image while keeping the foreground image visible

I am using Twitter Bootstrap to create a carousel on my website. Currently, I have set the foreground image as the current image and the background image as the next one. However, I want to adjust the opacity of just the background image. Can someone pleas ...

Safari IOS experiencing issue with element disappearing unexpectedly when input is focused

I am facing a situation similar to the one discussed in the question (iOS 8.3 fixed HTML element disappears on input focus), but my problem differs slightly. My chatbox iframe is embedded within a scrollable parent, and when the iframe is activated, it exp ...

What is the best way to create space between my cards within responsive bootstrap rows on smaller devices?

As a beginner, I welcome even the simplest advice. In this section, there is a generous amount of padding defined in bootstrap as padding-right and padding-left. When I reduce the display size, one card moves below and there is no spacing between the two ...

Creating CSS wrappers around div elements of varying sizes

I am looking for a way to "wrap" different divs of varying sizes, similar to how Microsoft Word wraps text around an image. I have a simplified structure outlined below: <div id = "div1"></div> <div id = "div2"></div> <div id = ...

What is the best way to modify the color of a button within an AngularJS function by utilizing the same button?

Currently, I have a function assigned to the ng-click event on a button in order to filter a list. My goal is to change the color of the button once it has been clicked and the filtered list is displayed. I am looking for a way to achieve this within the ...

The height of each list item should expand based on the size of the div contained within it

The HTML markup I am working with looks like this: <ul data-role="listview" data-inset="true" class="stuff site-content lists"> <li> <div class="nearby"> 20 </div> <h1> name</h1> </li> ...

Troubleshooting Problem with Website Responsiveness on iPhones Using Bootstrap 5

I am currently experiencing a challenge involving the responsiveness of a website I am developing, particularly when it comes to iPhones. The site utilizes Bootstrap 5 and displays correctly on Android devices and in Chrome Dev Tools. However, upon testing ...

Tips for utilizing a dropdown menu in Angular

<div> <label> Categories </label> <select> <option *ngFor = "let category of categories" [value] = "category" (click) = "onCategorySelected( category.name )"> ...

Activate the popup for sharing or bookmarking by clicking on a regular link

I am currently utilizing a Share/Bookmark script: <div class="singles-right"> <a href="#" class="bookmark"></a> <script type="text/javascript" src="http://static.addinto.com/ai/ai2_bkmk.js"></script> <a href="#" clas ...

Adjust the minimum height and width when resizing the window

Apologies in advance if this has already been addressed, but I have tried solutions from other sources without success. My Objective: I aim to set the minimum height and width of a div based on the current dimensions of the document. This should trigger ...

Creating consistent height list groups within a Bootstrap 4 card deck

How can I create a card-desk using Bootstrap 4 that contains internal list-groups or card-blocks with the same horizontal height without setting a fixed height for each section? I have tried using d-flex flex-column and list-groups, but it didn't wor ...

When the flex-grow property is set to 1, the height of the div extends beyond the space that

Here is an example of some HTML code: .container { height: 100%; width: 100%; display: flex; flex-direction: column; padding: 10px; background-color: aqua; } .box { width: 100%; height: 100%; flex-grow: 1; background-color: cadetb ...