Star rating system hover
Asked Answered
A

3

6

Currently I'm making a rating system for a webshop. Basically how I want it to work:

If visitor never rated before:

  • Visitor hovers over a star
  • The previous and current stars will be yellow, the next stars gray (done with class)
  • If the visitor leaves the hover, reset all stars to the old state
  • If the visitor clicks on a star, save it, calculate the next star values and update the array.

I'm using font awesome so I'm not using any images. The problem now is that if I hover over a star, it works, but if I want to move from star to star it glitches (because there's a little gap between the stars and it means it'll reset the stars first).

jsfiddle: https://jsfiddle.net/uappvz3y/

JS:

var current_star_statusses = [];

star_elements = $('.fa-star');

star_elements.each(function(i, elem)
{
    current_star_statusses.push($(elem).hasClass('yellow'));
});

star_elements.mouseenter(changeRatingStars);
star_elements.mouseleave(resetRatingStars);

/**
 * Changes the rating star colors when hovering over it.
 */
function changeRatingStars()
{
    // Current star hovered
    var star = $(this);

    // Removes all colors first from all stars
    $('.fa-star').removeClass('gray').removeClass('yellow');

    // Makes the current hovered star yellow
    star.addClass('yellow');

    // Makes the previous stars yellow and the next stars gray
    star.parent().prevAll().children('.fa-star').addClass('yellow');
    star.parent().nextAll().children('.fa-star').addClass('gray');
}

/**
 * Resets the rating star colors when not hovered anymore.
 */
function resetRatingStars()
{
    star_elements.each(function(i, elem)
    {
        $(elem).removeClass('yellow').removeClass('gray').addClass(current_star_statusses[i] ? 'yellow' : 'gray');
    });
}

HTML:

<ul class="list-inline rating-list">
    <li><i class="fa fa-star yellow"></i></li>
    <li><i class="fa fa-star yellow"></i></li>
    <li><i class="fa fa-star yellow"></i></li>
    <li><i class="fa fa-star yellow"></i></li>
    <li><i class="fa fa-star gray"></i></li>
</ul>

CSS:

.fa-star:before {
    content: "\f005";
}

.rating-list li i.yellow {
    color: #FFD700;
}

.rating-list li i.gray {
    color: #bbb;
}

.list-inline>li {
    display: inline-block;
    padding-right: 5px;
    padding-left: 5px;
}

.rating-list li {
    padding: 0px;
}
.fa {
    display: inline-block;
    font: normal normal normal 14px/1 FontAwesome;
    font-size: inherit;
    text-rendering: auto;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    transform: translate(0, 0);
}

I know there are a lot of libraries that makes it easier but I'd like to keep it my own code if I can.

Authority answered 24/2, 2017 at 8:52 Comment(0)
B
3

I changed these 4 lines of code.

star_elements = $('.fa-star').parent();

star_elements.find(".fa-star").each(function(i, elem) {
  current_star_statusses.push($(elem).hasClass('yellow'));
});

star_elements.find(".fa-star").mouseenter(changeRatingStars);
star_elements.find(".fa-star").mouseleave(resetRatingStars);

So now the star_element is the li.

Also if you pref jsfiddle, here is a link

var current_star_statusses = [];

star_elements = $('.fa-star').parent();

star_elements.find(".fa-star").each(function(i, elem) {
  current_star_statusses.push($(elem).hasClass('yellow'));
});

star_elements.find(".fa-star").mouseenter(changeRatingStars);
star_elements.find(".fa-star").mouseleave(resetRatingStars);

/**
 * Changes the rating star colors when hovering over it.
 */
function changeRatingStars() {
  // Current star hovered
  var star = $(this);

  // Removes all colors first from all stars
  $('.fa-star').removeClass('gray').removeClass('yellow');

  // Makes the current hovered star yellow
  star.addClass('yellow');

  // Makes the previous stars yellow and the next stars gray
  star.parent().prevAll().children('.fa-star').addClass('yellow');
  star.parent().nextAll().children('.fa-star').addClass('gray');
}

/**
 * Resets the rating star colors when not hovered anymore.
 */
function resetRatingStars() {
  star_elements.each(function(i, elem) {
    $(elem).removeClass('yellow').removeClass('gray').addClass(current_star_statusses[i] ? 'yellow' : 'gray');
  });
}
.fa-star:before {
  content: "\f005";
}

.rating-list li i.yellow {
  color: #FFD700;
}

.rating-list li i.gray {
  color: #bbb;
}

.list-inline>li {
  display: inline-block;
  padding-right: 5px;
  padding-left: 5px;
}

.rating-list li {
  padding: 0px;
}

.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transform: translate(0, 0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<ul class="list-inline rating-list">
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star gray"></i></li>
</ul>
Bishopric answered 24/2, 2017 at 8:56 Comment(2)
Thanks, this is exactly what I need! Will accept the answer as soon as I can. Cheers!Authority
I'm happy to help, have a nice dayRatify
O
8

You can make stars rating using pure CSS. Float stars to right, and apply hover effect for li that has padding.

.rating-list li {
  float: right;
  color: #ddd;
  padding: 10px 5px;
}

.rating-list li:hover,
.rating-list li:hover ~ li {
  color: #ffd700;
}

.rating-list {
  display: inline-block;
  list-style: none;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>

<ul class="list-inline rating-list">
  <li><i class="fa fa-star" title="Rate 5"></i></li>
  <li><i class="fa fa-star" title="Rate 4"></i></li>
  <li><i class="fa fa-star" title="Rate 3"></i></li>
  <li><i class="fa fa-star" title="Rate 2"></i></li>
  <li><i class="fa fa-star" title="Rate 1"></i></li>
</ul>
Otherworldly answered 24/2, 2017 at 9:0 Comment(1)
CSS + radiobuttons pretty much makes this functional without any JS, too: jsfiddle.net/leaverou/CGP87Gradualism
B
3

I changed these 4 lines of code.

star_elements = $('.fa-star').parent();

star_elements.find(".fa-star").each(function(i, elem) {
  current_star_statusses.push($(elem).hasClass('yellow'));
});

star_elements.find(".fa-star").mouseenter(changeRatingStars);
star_elements.find(".fa-star").mouseleave(resetRatingStars);

So now the star_element is the li.

Also if you pref jsfiddle, here is a link

var current_star_statusses = [];

star_elements = $('.fa-star').parent();

star_elements.find(".fa-star").each(function(i, elem) {
  current_star_statusses.push($(elem).hasClass('yellow'));
});

star_elements.find(".fa-star").mouseenter(changeRatingStars);
star_elements.find(".fa-star").mouseleave(resetRatingStars);

/**
 * Changes the rating star colors when hovering over it.
 */
function changeRatingStars() {
  // Current star hovered
  var star = $(this);

  // Removes all colors first from all stars
  $('.fa-star').removeClass('gray').removeClass('yellow');

  // Makes the current hovered star yellow
  star.addClass('yellow');

  // Makes the previous stars yellow and the next stars gray
  star.parent().prevAll().children('.fa-star').addClass('yellow');
  star.parent().nextAll().children('.fa-star').addClass('gray');
}

/**
 * Resets the rating star colors when not hovered anymore.
 */
function resetRatingStars() {
  star_elements.each(function(i, elem) {
    $(elem).removeClass('yellow').removeClass('gray').addClass(current_star_statusses[i] ? 'yellow' : 'gray');
  });
}
.fa-star:before {
  content: "\f005";
}

.rating-list li i.yellow {
  color: #FFD700;
}

.rating-list li i.gray {
  color: #bbb;
}

.list-inline>li {
  display: inline-block;
  padding-right: 5px;
  padding-left: 5px;
}

.rating-list li {
  padding: 0px;
}

.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transform: translate(0, 0);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<ul class="list-inline rating-list">
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star gray"></i></li>
</ul>
Bishopric answered 24/2, 2017 at 8:56 Comment(2)
Thanks, this is exactly what I need! Will accept the answer as soon as I can. Cheers!Authority
I'm happy to help, have a nice dayRatify
L
3

There is a much simpler solution: use paddings on the .fa elements instead, and use float: left for the list items, which means that there will be no spacing between each star.

These few rules are sufficient to achieve the effect you intend to do:

.list-inline {
  list-style: none;
  padding: 0;
  margin: 0;
  overflow: hidden;
}
.list-inline > li {
  float: left;
}
.rating-list li {
  padding: 0px;
}
.rating-list li .fa {
  padding-right: 5px;
}

Here is a proof-of-concept example, leaving your JS code unchanged:

$(function() {

    var current_star_statusses = [];

    star_elements = $('.fa-star');

    star_elements.each(function(i, elem) {
      current_star_statusses.push($(elem).hasClass('yellow'));
    });

    star_elements.mouseenter(changeRatingStars);
    star_elements.mouseleave(resetRatingStars);

    /**
     * Changes the rating star colors when hovering over it.
     */
    function changeRatingStars() {
      // Current star hovered
      var star = $(this);

      // Removes all colors first from all stars
      $('.fa-star').removeClass('gray').removeClass('yellow');

      // Makes the current hovered star yellow
      star.addClass('yellow');

      // Makes the previous stars yellow and the next stars gray
      star.parent().prevAll().children('.fa-star').addClass('yellow');
      star.parent().nextAll().children('.fa-star').addClass('gray');
    }

    /**
     * Resets the rating star colors when not hovered anymore.
     */
    function resetRatingStars() {
      star_elements.each(function(i, elem) {
        $(elem).removeClass('yellow').removeClass('gray').addClass(current_star_statusses[i] ? 'yellow' : 'gray');
      });
    }
 });
.fa-star:before {
  content: "\f005";
}

.rating-list li i.yellow {
  color: #FFD700;
}

.rating-list li i.gray {
  color: #bbb;
}

.list-inline {
  list-style: none;
  padding: 0;
  margin: 0;
  overflow: hidden;
}
.list-inline>li {
  float: left;
}

.rating-list li {
  padding: 0px;
}
.rating-list li .fa {
  padding-right: 5px;
}

.fa {
  display: inline-block;
  font: normal normal normal 14px/1 FontAwesome;
  font-size: inherit;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  transform: translate(0, 0);
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list-inline rating-list">
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star yellow"></i></li>
  <li><i class="fa fa-star gray"></i></li>
</ul>
Liebig answered 24/2, 2017 at 9:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.