Why are my CSS star layers not aligning properly?

Viewed 356

I want the Yellow Stars to completely obscure the blue stars

Could anyone help complete this? Or at least point to the right direction?

This is my code:

.star-ratings-css {

  width: 100px;
}
.star-ratings-css-top {
      display: block;
     height: 22px;
    position: relative;
    overflow: hidden;
}
.star-ratings-css-bottom::before  {
color: #167ac6;
    content: "★★★★★";
    font-size: 22px;
    position: absolute;
}
.star-ratings-css-top::before  {
    color: #f4b414;
    content: "★★★★★";
    font-size: 22px;
    position: relative;
}
<div class="star-ratings-css">
  <div class="star-ratings-css-bottom"></div>
  <div class="star-ratings-css-top" style="width: 31%"></div>

</div>

It does not work as I would like. What I am doing wrong?

Yellow stars do not completely cover the blue stars.

enter image description here

6 Answers

Just remove overflow: hidden; and it will work like a charm. Below is an example for 4/5.

.star-ratings-css {
  width: 100px;
}
.star-ratings-css-top {
    display: block;
     height: 22px;
    position: relative;
}
.star-ratings-css-bottom::before  {
    color: #167ac6;
    content: "★★★★★";
    font-size: 22px;
    position: absolute;
}
.star-ratings-css-top::before  {
    color: #f4b414;
    content: "★★★★";
    font-size: 22px;
    position: relative;
}
<div class="star-ratings-css">
  <div class="star-ratings-css-bottom"></div>
  <div class="star-ratings-css-top" style="width: 31%"></div>
</div>

enter image description here

Try the "Inspect" feature of the Chrome browser to adjust CSS settings to what you want displayed.

The first two stars were made all yellow with the following changes.

enter image description here

  • Remove: "height: 22px;" from .start-ratings-css-top::before
  • Change: style="width: 31%" to style="width: 35%"

Another option to get just two (2) yellow stars is ...

  • Remove: "height: 22px;" from .start-reatings-css-top
  • Remove: style="width: 31%"
  • Change: content: "★★"; for .start-ratings-css-top::before

Star Rating Icons

The code in is overcomplicated and could be easily done with better tags than <div>s and can be interactive as well.

HTML

The two types of tags used in the following demo are:

<input id='ID' name='rad' type='radio'>

and

<label for='ID' class='star'>★</label>

There's an input and label for each star icon, the ID of the input is matched by the label [for] attribute. When an input/label pair is setup this way, they are associated so that when one is clicked the other is clicked as well. All inputs will be hidden and all labels will be styled.


CSS

Each input will be followed by the next label:

<label for='ID3' class='star'>★</label> // 1. User clicks

<input id='ID3' name='rad' type='radio'> // 2. Which puts this as: [name='rad']:checked

<label for='ID4' class='star'>★</label> /* 3. Any labels that occur from this point on
will be styled: ~ .star {color:navy}*/

<input id='ID4' name='rad' type='radio'>

<label for='ID5' class='star'>★</label>

So when this ruleset is in CSS:

 [name='rad']:checked ~ .star { `color: navy` }

it will style the stars in two states: default color: gold (on) or color: navy (off).


Demo

Click a star and any stars to the right of it will turn off. Click to the left or right end where there are no stars and all stars will be turned off.

[name=rad] {
  display: none
}

label {
  display: inline-block;
  outline: 0;
  font-size: 10vh;
  line-height: 1;
  color: gold;
  background: none;
  transition: 0.6s;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  cursor: pointer;
}

[name=rad]:checked~.star {
  color: navy;
  transition: 0.6s;
}

#s0:checked~.star {
  color: navy;
  transition: 0.6s;
}

[name=rad]+label.star:hover {
  color: cyan;
  transition: 0.4s;
}

[name=rad]+label.star:active {
  color: tomato;
  transition: 0.4s;
}
<label for='s0' class='void'>&nbsp;&nbsp;&nbsp;</label>
<input id='s0' name='rad' type='radio' value='0'>
<label for='s1' class='star'>&#9733;</label>
<input id='s1' name='rad' type='radio' value='1'>
<label for='s2' class='star'>&#9733;</label>
<input id='s2' name='rad' type='radio' value='2'>
<label for='s3' class='star'>&#9733;</label>
<input id='s3' name='rad' type='radio' value='3'>
<label for='s4' class='star'>&#9733;</label>
<input id='s4' name='rad' type='radio' value='4'>
<label for='s5' class='star'>&#9733;</label>
<input id='s5' name='rad' type='radio' value='5' checked>
<label for='s0' class='void'>&nbsp;&nbsp;&nbsp;</label>

You can use absolute position for :before and :after selectors.

.star-ratings-css {
  width: 100px;
}
.star-ratings-css-top {
      display: block;
     height: 22px;
    position: relative;
    overflow: hidden;
}
.star-ratings-css-bottom::before  {
color: #167ac6;
    content: "★★★★★";
    font-size: 22px;
    position:absolute;top:0;left:8px
}
.star-ratings-css-top::before  {
    color: #f4b414;
    content: "★★★★★";
    font-size: 22px;
    position:absolute;top:-8px;left:0
}
<div class="star-ratings-css">
  <div class="star-ratings-css-bottom"></div>
  <div class="star-ratings-css-top" style="width: 31%"></div>

</div>

You can simplify your code using one element

.star-ratings-css {
  display: inline-block;
  position: relative;
  font-size: 22px;
}

.star-ratings-css::before {
  color: #167ac6;
  content: "★★★★★";
}

.star-ratings-css::after {
  color: #f4b414;
  content: "★★★★★";
  position: absolute;
  top: 0;
  left: 0;
  width: var(--p, 100%);
  overflow: hidden;
  white-space:nowrap;
}
<div class="star-ratings-css" style="--p:20%;"></div>
<br>
<div class="star-ratings-css" style="--p:50%;"></div>
<br>
<div class="star-ratings-css"></div>

There are a couple of things wrong with your example:

  • The top element is 31% of 100px but the stars have a different width. If you set the width to 50% it will not display 2½ stars!

  • You're setting a height of 22px on top element and which is shorter than the actual height of bottom element (22px * line height = ~30px) which is the issue your'e talking about.

You could use display: inline-block to make the container stretch to contents i.e. the actual width of five stars. This will make percentage widths match the correct number (or fraction) of stars. And remove the height: 22px. The simplified code would look like this:

.star-ratings-css {
  display: inline-block;
  position: relative;
  font-size: 22px;
}

.star-ratings-inner {
  position: absolute;
  overflow: hidden;
}

.star-ratings-inner::after {
  color: #f4b414;
  content: "★★★★★";
}

.star-ratings-css::after {
  color: #167ac6;
  content: "★★★★★";
}
<div class="star-ratings-css">
  <div class="star-ratings-inner" style="width: 31%"></div>
</div>

Related