RRP
RRP

Reputation: 2853

CSS sprites and background positioning

I am currently working on implementing a star-rating widget. Which needs to make use of a sprite file, which looks as the following

Sprite with ratings

I have my html structured as following

HTML

 <span id="star-ratings" class="containers">
      <span id="ratings"></span>
 </span>

I have the following CSS, which is where i am unsure of in terms of displaying the stars

#star-ratings, #ratings{
    background:url(../images/star-sprite.png) 0 15.8px repeat-x;
    display: block;
    width: 78px;
    height: 14px;
}

To further explain my thought process, i am passing down a rating value which can range from 0-5 through my javascript and then calculating the final width size and applying it to the inner span.

Currently i am trying to display the initial start, which is the empty star. But instead i see all the stars on my page.

Upvotes: 0

Views: 496

Answers (2)

Romulo
Romulo

Reputation: 5104

Explanation

Let's use the image you provided in the example. The image have 80px width (actually its 79px but i'm rounding up), 14px height and 5 states: 0%, 25%, 50%, 75% and 100%.

To use the image as a sprite, we will create a base class called .star and assign the height of the image (14px) and the width of a single state, which would be 16px (80px / 5 states).

The default state will be the first one in the sprite (0%). Afterwards, we create an extra CSS for each aditional state: 25%, 50%, 75% and 100%.

Each class will have a different value for the background-position attribute, based on the state width.

Example

Here is an example using the image provided by the user as a sprite.

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <style>
    .rating {
      margin: 25px;
    }
    .rating label {
      font-weight: bold;
      display: block;
    }
    .star {
      display: inline-block;
      width: 16px;
      height: 14px;
      background-image: url('https://i.sstatic.net/ZSMMj.png');
      background-repeat: none;
    }
    .star-25 {
      background-position: -16px 0;
    }
    .star-50 {
      background-position: -32px 0;
    }
    .star-75 {
      background-position: -48px 0;
    }
    .star-100 {
      background-position: -64px 0;
    }
  </style>
</head>

<body>

  <div class="rating">
    <label>1/5 (20%)</label>
    <span class="star star-100"></span>
    <span class="star"></span>
    <span class="star"></span>
    <span class="star"></span>
    <span class="star"></span>
  </div>

  <div class="rating">
    <label>4/5 (80%)</label>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star"></span>
  </div>

  <div class="rating">
    <label>8/10 (80%)</label>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star star-100"></span>
    <span class="star"></span>
    <span class="star"></span>
  </div>

</body>

</html>

Additional example

Here is another example using only CSS (no images), for additional studies purposes. Based on Accessible star rating widget with pure CSS, provided by the user connexo in the comments.

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="UTF-8">

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>

  <style type="text/css">
    body {
      margin: 25px;
    }
    .center {
      padding: 10px 0;
    }
    input[type=number] {
      font-size: 22px;
      padding: 5px;
      width: 50px;
    }
    .star-rating {
      display: inline-block;
    }
    .star {
      font-size: 30px;
    }
    .star:before {
      content: '★';
      color: #ddd;
      text-shadow: 2px 2px #bbb;
    }
    .star-rating[data-value="1"] .star:nth-child(-n + 1):before,
    .star-rating[data-value="2"] .star:nth-child(-n + 2):before,
    .star-rating[data-value="3"] .star:nth-child(-n + 3):before,
    .star-rating[data-value="4"] .star:nth-child(-n + 4):before,
    .star-rating[data-value="5"] .star:nth-child(-n + 5):before,
    .star-rating[data-value="6"] .star:nth-child(-n + 6):before,
    .star-rating[data-value="7"] .star:nth-child(-n + 7):before,
    .star-rating[data-value="8"] .star:nth-child(-n + 8):before,
    .star-rating[data-value="9"] .star:nth-child(-n + 9):before,
    .star-rating[data-value="10"] .star:nth-child(-n + 10):before {
      color: #fff455;
      text-shadow: 2px 2px #c3bb41;
    }
  </style>

</head>

<body>

  <div class="center">

    <input type="number" value="0" min="0" max="3" class="star-control" data-target="#star-1">

    <div id="star-1" class="star-rating" data-value="0">
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
    </div>

  </div>

  <div class="center">

    <input type="number" value="0" min="0" max="5" class="star-control" data-target="#star-2">

    <div id="star-2" class="star-rating" data-value="0">
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
    </div>

  </div>

  <div class="center">

    <input type="number" value="0" min="0" max="10" class="star-control" data-target="#star-3">

    <div id="star-3" class="star-rating" data-value="0">
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
      <span class="star"></span>
    </div>

  </div>

  <script type="text/javascript">
    function onStarControlChange() {

      var $this = $(this),
        value = $this.val(),
        target = $this.data('target');

      $(target).attr('data-value', value);

    }

    $('.star-control').on('change', onStarControlChange);
  </script>

</body>

</html>

Upvotes: 2

m4n0
m4n0

Reputation: 32255

You have used the width for all the images combined while you need to define the width for that particular image. Modify the place of the internal images using background-position

#star-ratings,
#ratings {
  background: url(https://i.sstatic.net/ZSMMj.png) 0 0 repeat-x;
  display: block;
  width: 14px; /* Modified */
  height: 14px;
  background-position: 0px;
}

.ratings1 {
  background: url(https://i.sstatic.net/ZSMMj.png) 0 0 repeat-x;
  display: block;
  width: 14px; 
  height: 14px;
  background-position: -16px;
}
First rating
<span id="star-ratings" class="containers">
      <span id="ratings"></span>
</span>
Second rating
<span id="star-ratings" class="containers">
      <span class="ratings1"></span>
</span>

Upvotes: 2

Related Questions