Note: I created a working version and put it in to a public gist, which also demonstrates the rating text updating when a value is selected.
Here's a demo of this working in Visualforce:
We can get this to work, but you have to get a bit more creative, because the framework adds extra markup to our code. There's a few hurdles you have here.
First, the CSS used is actually LESS, which means it's meant to be pre-processed (which CodePen does for you). You have to expand the &:hover i and &:checked i elements.
.star-rating input:hover + i,
.star-rating input:checked + i{
opacity:1;
}
This takes us to our next problem. You see, non apex:selectOption
and apex:selectOptions
elements end up being all coalesced together. When you look at the source code, you end up with something like this:
<form id="j_id0:j_id6" name="j_id0:j_id6" method="post" action="/apex/fivestars" enctype="application/x-www-form-urlencoded">
<input type="hidden" name="j_id0:j_id6" value="j_id0:j_id6">
<i></i>
<i></i>
<i></i>
<i></i>
<i></i><fieldset style="border: none;"><table role="presentation">
<tbody><tr>
<td>
<input type="radio" name="j_id0:j_id6:j_id7" id="j_id0:j_id6:j_id7:0" value="1"><label for="j_id0:j_id6:j_id7:0"></label></td>
<td>
<input type="radio" name="j_id0:j_id6:j_id7" id="j_id0:j_id6:j_id7:1" value="2"><label for="j_id0:j_id6:j_id7:1"></label></td>
<td>
<input type="radio" name="j_id0:j_id6:j_id7" id="j_id0:j_id6:j_id7:2" value="3"><label for="j_id0:j_id6:j_id7:2"></label></td>
<td>
<input type="radio" name="j_id0:j_id6:j_id7" id="j_id0:j_id6:j_id7:3" value="4"><label for="j_id0:j_id6:j_id7:3"></label></td>
<td>
<input type="radio" name="j_id0:j_id6:j_id7" id="j_id0:j_id6:j_id7:4" value="5"><label for="j_id0:j_id6:j_id7:4"></label></td>
</tr>
</tbody></table></fieldset><div id="j_id0:j_id6:j_id18"></div>
</form>
As you can see, the <i>
elements end up getting put next to each other, and the remainder is inside a table. The CSS just won't work as is.
However, as you can see, we now have something to work with; we can actually just make the stars using the labels.
Now, this is where things get really messy. We need to start positioning everything and doing all sorts of extra CSS fuss.
So, after we tinker around with the CSS, selecting the fieldset, td elements, and labels, we end up with the following CSS. I also had to tinker with the z-index and width values to get everything working correctly, because the elements are nested differently.
.star-rating fieldset {
font-size:0;
white-space:nowrap;
display:inline-block;
width:250px;
height:50px;
overflow:hidden;
position:relative;
background:
url('data:image/svg+xml;utf-8,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve"><polygon fill="#DDDDDD" points="10,0 13.09,6.583 20,7.639 15,12.764 16.18,20 10,16.583 3.82,20 5,12.764 0,7.639 6.91,6.583 "/></svg>');
background-size: contain;
}
.star-rating input {
-moz-appearance:none;
-webkit-appearance:none;
opacity: 0;
display:inline-block;
width: 100%;
height: 100%;
margin:0;
padding:0;
z-index: 2;
position: relative;
}
.star-rating input:hover + label,
.star-rating input:checked + label {
opacity:1;
}
.star-rating label {
opacity: 0;
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 20%;
z-index: 4;
background:
url('data:image/svg+xml;utf-8,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve"><polygon fill="#FFDF88" points="10,0 13.09,6.583 20,7.639 15,12.764 16.18,20 10,16.583 3.82,20 5,12.764 0,7.639 6.91,6.583 "/></svg>');
background-size: contain;
}
.star-rating td ~ td label {
width: 40%;
z-index: 3;
}
.star-rating td ~ td ~ td label {
width: 60%;
z-index: 2;
}
.star-rating td ~ td ~ td ~ td label {
z-index: 1;
width: 80%;
}
.star-rating td ~ td ~ td ~ td ~ td label {
z-index: 0;
width: 100%;
}
And, finally, we can display our page:
<apex:outputPanel styleClass="star-rating">
<apex:form >
<apex:selectRadio layout="lineDirection">
<apex:selectOption itemValue="1"></apex:selectOption>
<apex:selectOption itemValue="2"></apex:selectOption>
<apex:selectOption itemValue="3"></apex:selectOption>
<apex:selectOption itemValue="4"></apex:selectOption>
<apex:selectOption itemValue="5"></apex:selectOption>
</apex:selectRadio>
</apex:form>
</apex:outputPanel>
You can't do that with Static Resources but you can achieve dynamic CSS binding with a Visualforce page as external CSS file.
Visualforce page (apex:page
) has a content type (contentType
) property where you can specify the content type of the file. That means you can render a Visualforce page in different MIME types like JavaScript HTML and CSS etc.
To do that you have to use text/css
as contentType of the Visualforce page as below.
Visualforce as external CSS file
<apex:page controller="CssController" contentType="text/css" cache="false" expires="0">
.classgreen{
color:{!testColor}
}
</apex:page>
Visualforce Page where the above file is referenced as CSS file
<apex:page>
<apex:stylesheet value="{!URLFOR($Page.csspage)}" />
<h1 class="classgreen">Congratulations</h1>
This is your new Page
<!-- End Default Content REMOVE THIS -->
</apex:page>
Best Answer
There is no 'proper' way to do this, but typically the resources will end up in a static resource so that's a good way to go, although it can be rather painful to constantly zip up files and upload them. Resource bundles in MavensMate can make this setup far easier to deal with: you can edit a file and upload with a zip with a couple of keystrokes. I highly recommend this approach as it means you'll be using your intended file structure etc. within the zip file, something you'll need to consider when you're using bundled images/Javascript as well.
An alternative, and handy option, during development is to use a cloud storage service like Dropbox. Put your CSS in the public folder, get a public link and then use that inside of your page to include the CSS. That way you can just hit save on the file, wait a couple of seconds and then refresh your Visualforce page to see the result. In my experience it takes no more than two to three seconds for Dropbox to sync small files like that. See the link: Productivity Tip : Quicker Javascript and CSS development using Dropbox