This is pure HTML and CSS for selecting the stars.
I do get what the js code does but I fail to understand how the stars are selected when I click on a star and al the stars below that one get selected
.rating {
float: left;
}
/* :not(:checked) is a filter, so that browsers that don’t support :checked don’t
follow these rules. Every browser that supports :checked also supports :not(), so
it doesn’t make the test unnecessarily selective */
.rating:not(:checked)>input {
position: absolute;
top: -9999px;
clip: rect(0, 0, 0, 0);
}
.rating:not(:checked)>label {
float: right;
width: 1em;
padding: 0 .1em;
overflow: hidden;
white-space: nowrap;
cursor: pointer;
font-size: 200%;
line-height: 1.2;
color: #ddd;
text-shadow: 1px 1px #bbb, 2px 2px #666, .1em .1em .2em rgba(0, 0, 0, .5);
}
.rating:not(:checked)>label:before {
content: '★ ';
}
.rating>input:checked~label {
color: #f70;
text-shadow: 1px 1px #c60, 2px 2px #940, .1em .1em .2em rgba(0, 0, 0, .5);
}
.rating:not(:checked)>label:hover,
.rating:not(:checked)>label:hover~label {
color: gold;
text-shadow: 1px 1px goldenrod, 2px 2px #B57340, .1em .1em .2em rgba(0, 0, 0, .5);
}
.rating>input:checked label:hover,
.rating>input:checked label:hover~label,
.rating>input:checked~label:hover,
.rating>input:checked~label:hover~label,
.rating>label:hover~input:checked~label {
color: #ea0;
text-shadow: 1px 1px goldenrod, 2px 2px #B57340, .1em .1em .2em rgba(0, 0, 0, .5);
}
.rating>label:active {
position: relative;
top: 2px;
left: 2px;
}
/* end of Lea's code */
/*
* Clearfix from html5 boilerplate
*/
.clearfix:before,
.clearfix:after {
content: " ";
/* 1 */
display: table;
/* 2 */
}
.clearfix:after {
clear: both;
}
/*
* For IE 6/7 only
* Include this rule to trigger hasLayout and contain floats.
*/
.clearfix {
*zoom: 1;
}
/* my stuff */
#status,
button {
margin: 20px 0;
}
<div id="status"></div>
<form id="ratingForm">
<fieldset >
<legend>Please rate:</legend>
<input type="radio" id="star5" name="rating" value="5" /><label for="star5" title="Rocks!">5 stars</label>
<input type="radio" id="star4" name="rating" value="4" /><label for="star4" title="Pretty good">4 stars</label>
<input type="radio" id="star3" name="rating" value="3" /><label for="star3" title="Meh">3 stars</label>
<input type="radio" id="star2" name="rating" value="2" /><label for="star2" title="Kinda bad">2 stars</label>
<input type="radio" id="star1" name="rating" value="1" /><label for="star1" title="Sucks big time">1 star</label>
</fieldset>
<div ></div>
<button >Submit</button>
</form>
CodePudding user response:
There is a few things going on. I have simplified it with more modern CSS.
- The items in the fieldset are reversed. This is important because CSS has a selector for elements that come after a certain selector but not before. The tilde,
~
, is used to select every sibling that comes after an element. - The checked radio button
:checked
is used to determine which is the target element, after which all elements should get a certain style applied.
These things combined allow colouring everything after the checked input. Since the list is reversed, it appears to the user as if everything before checked input was coloured. Additionally, the checked input itself is also coloured.
.rating>input:checked::before,
.rating>input:checked~input::before
In this example, the pseudo-element before
is used to get the star via content: '⭐'
. The colouring is done by removing the colour in the default state through a CSS filter: filter: grayscale(100%) contrast(200%);
and unsetting the filter when the checked, and sibling after checked, condition applies.
.rating {
display: flex;
flex-direction: row-reverse;
width: 320px;
padding-bottom: 1rem;
}
.rating>input {
flex: 1 1 0%;
display: grid;
place-content: center;
}
.rating>input::before {
content: '⭐';
filter: grayscale(100%) contrast(200%);
font-size: 200%;
}
.rating>input:checked::before,
.rating>input:checked~input::before {
filter: unset;
}
<fieldset >
<legend>Please rate:</legend>
<input type="radio" id="star5" name="rating" value="5" />
<input type="radio" id="star4" name="rating" value="4" />
<input type="radio" id="star3" name="rating" value="3" checked />
<input type="radio" id="star2" name="rating" value="2" />
<input type="radio" id="star1" name="rating" value="1" />
</fieldset>
Using these techniques, you could easily expand this with the hover
state, as in your example.
Another thing that was used in your example is the
which is similar to ~
but it only applies to the first silibing instead of all sibling. It appears to be redundant.