选中前一个单选按钮的CSS选择器

时间:2016-11-14 20:02:40

标签: html css css3

我正在通过一些单选按钮构建一个小星级CSS评级,并使其正常工作。我有一个问题是能够在选择的收音机之前填写星星,所以如果选择星号3,星号1和2也将被填写。这是我到目前为止:



#review-form input,
#review-form textarea {
  background: none repeat scroll 0 0 #333333;
  border: 0 none;
  color: #fff;
  margin: 0;
  max-width: 100%;
  padding: 7px 4px;
}
#review-form .radio {
  display: inline-block;
}
#review-form input[type=radio] {
  display: none;
}
#review-form input[type=radio] + label {
  display: block;
}
#review-form input[type='radio'] + label:before {
  display: inline-block;
  font-family: FontAwesome;
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  padding-right: 8px;
  width: 23px;
}
#review-form input[type=radio] + label:before {
  content: "\f006";  /* Radio Unchecked */
}
#review-form input[type=radio]:checked + label:before {
  content: "\f005";  /* Radio Checked */
}

<link href="//netdna.bootstrapcdn.com/font-awesome/3.0/css/font-awesome.css" rel="stylesheet" />
<div class="form-group" id="review-form">
  <label for="rating">RATING</label>
  <span class="star-rating star-5">
                  <div class="radio">
                    <input type="radio" id="option1" name="star-radios" value="1">
                    <label for="option1"></label>
                  </div>
                  <div class="radio">
                    <input type="radio" id="option2" name="star-radios" value="2">
                    <label for="option2"></label>
                  </div>
                  <div class="radio">
                    <input type="radio" id="option3" name="star-radios" value="3">
                    <label for="option3"></label>
                  </div>
                  <div class="radio">
                    <input type="radio" id="option4" name="star-radios" value="4">
                    <label for="option4"></label>
                  </div>
                  <div class="radio">
                    <input type="radio" id="option5" name="star-radios" value="5">
                    <label for="option5"></label>
                  </div>

                </span>

</div>
&#13;
&#13;
&#13;

Codepen

我想知道是否有一个CSS选择器(或其他东西)可用于我可以更改选择单选按钮之前的星号。如果可以的话,尽量避免使用JS。

2 个答案:

答案 0 :(得分:4)

此解决方案仅使用CSS:

以相反的顺序(从5到1)处理无线电和标签(HTML),我们可以使用CSS General sibling combinator A ~ B。这样当选择收音机后,所有标签显示正确的星形图标(选择收音机4显示4,3,2,1的填充星形图标)。然后我们可以将每个元素重新定位到所需的顺序,即1 2 3 4 5:

  • 在每个元素中使用transform属性
  • 在容器中使用flex-direction: row-reverse;属性(我们还需要为此工作分配display: flex;justify-content: flex-end;);正如瑞奇在答案中所说的那样。

/* Using transform */
.use_transform #option1_label {
  transform: translateX(-80px)
}
.use_transform #option2_label {
  transform: translateX(-40px)
}
.use_transform #option4_label {
  transform: translateX(40px)
}
.use_transform #option5_label {
  transform: translateX(80px)
}

/* Using flex */
.use_flex.star-rating {
    display: flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
}

/* Select all next siblings */
#review-form input:checked~label.label_star:before {
  content: "\f005";
}

/**/
#rating {
  float: left;
  margin-right: 10px;
}
.label_star {
  float: left;
  width: 20px;
}

#review-form input,
#review-form textarea {
  background: none repeat scroll 0 0 #333333;
  border: 0 none;
  color: #fff;
  margin: 0;
  max-width: 100%;
  padding: 7px 4px;
}
#review-form .radio {
  display: inline-block;
}
#review-form input[type=radio] {
  display: none;
}
#review-form input[type=radio] + label {
  display: block;
}
#review-form input[type='radio'] + label:before {
  display: inline-block;
  font-family: FontAwesome;
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  //padding-right: 8px;
  width: 23px;
}
#review-form input[type=radio] + label:before {
  content: "\f006";
  /* Radio Unchecked */
}
#review-form input[type=radio]:checked + label:before {
  content: "\f005";
  /* Radio Checked */
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<div class="form-group" id="review-form">
  <label id="rating" for="rating">RATING</label>
  <span class="use_flex star-rating star-5">

  <input type="radio" id="option5" name="star-radios" value="5">
  <label class="label_star" id="option5_label" for="option5"></label>

  <input type="radio" id="option4" name="star-radios" value="4">
  <label class="label_star" id="option4_label" for="option4"></label>
  
  <input type="radio" id="option3" name="star-radios" value="3">
  <label class="label_star" id="option3_label" for="option3"></label>
  
  <input type="radio" id="option2" name="star-radios" value="2">
  <label class="label_star" id="option2_label" for="option2"></label>
  
  <input type="radio" id="option1" name="star-radios" value="1">
  <label class="label_star" id="option1_label" for="option1"></label>

</span>
</div>

答案 1 :(得分:4)

CSS方法:

仅使用CSS,您可以使用flexbox。

  • 使用flex-direction: row-reverse;

      

    row-reverse:与行相同,但主开头和主端点都被置换。

  • 使用general sibling selector.

      

    〜组合器分离两个选择器并匹配第二个选择器   元素只有在第一个元素之前,并且两者共享一个共同元素   父节点。

#review-form .star-rating {
  display: inline-flex;
  flex-direction: row-reverse;
}

#review-form input[type=radio] + .label_star::before {
  content: "\f006";
  /* Radio Unchecked */
}

#review-form input[type=radio]:checked ~ .label_star::before {
  content: "\f005";
    /* Radio Checked */
}

#review-form .star-rating {
  display: inline-flex;
  flex-direction: row-reverse;
}
#review-form input,
#review-form textarea {
  background: none repeat scroll 0 0 #333333;
  border: 0 none;
  color: #fff;
  margin: 0;
  max-width: 100%;
  padding: 7px 4px;
}
#review-form .radio {
  display: inline-block;
}
#review-form input[type=radio] {
  display: none;
}
#review-form input[type=radio] + label {
  display: block;
}
#review-form input[type='radio'] + .label_star:before {
  display: inline-block;
  font-family: FontAwesome;
  font-style: normal;
  font-weight: normal;
  line-height: 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  //padding-right: 8px;
  width: 23px;
}
#review-form input[type=radio] + .label_star::before {
  content: "\f006";
  /* Radio Unchecked */
}
#review-form input[type=radio]:checked ~ .label_star::before {
  content: "\f005";
  /* Radio Checked */
}
<link href="//netdna.bootstrapcdn.com/font-awesome/3.0/css/font-awesome.css" rel="stylesheet" />
<div class="form-group" id="review-form">
  <label id="rating" for="rating">RATING</label>
  <span class="star-rating star-5">
  <input type="radio" id="option5" name="star-radios" value="5">
  <label class="label_star" id="option5_label" for="option5"></label>
  <input type="radio" id="option4" name="star-radios" value="4">
  <label class="label_star" id="option4_label" for="option4"></label>
  <input type="radio" id="option3" name="star-radios" value="3">
  <label class="label_star" id="option3_label" for="option3"></label>
  <input type="radio" id="option2" name="star-radios" value="2">
  <label class="label_star" id="option2_label" for="option2"></label>
  <input type="radio" id="option1" name="star-radios" value="1">
  <label class="label_star" id="option1_label" for="option1"></label>
</span>
</div>

Revised Codepen

JS方法:

正如评论中所说的那样,我在一段时间后创建了一个小评级组件,可能有所帮助。一些调整是为了满足要求,它使用JS。

该组件使用以下内容:

  • SVG图标
  • SVG Spritesheet
  • HTML5
  • 的Javascript
  • 的jQuery
  • CSS3

简单评级组件

  

jQuery依赖(不复杂,可以删除)。

//Summary: Star Rating Component, get and/or set a rating displaying icons.
(function() {
// Assign variables for jQuery Objects and classes as string.
  var $rating = $(".rating"),
    sRatingClass = "rated",
    sIcon = "icon-star-full",
    $icon = $("." + sIcon);

// Iterate over jQuery Rating objects.
  $.each($rating, function() {
  // Get the rating if set, you can set this with a REST service and get the current rating.
    var iRating = $(this).data("rating");
    // Filter the icons with a :nth-child pseudo-class and add the 'active' class.
    $(this).find("."+ sIcon + ":nth-child(-n+" + iRating + ")").addClass(sRatingClass);
  });

// Add click event listener to jQuery Icon Objects.
  $icon.on("click", function() {
  // Get the index of the icon being clicked.
    var iIconIndex = $(this).index() + 1,
    // Select the parent of the icon being clicked.
      $iconParent = $(this).parent();
      // Remove the 'active' class to all the icons before setting the new ones.
    $iconParent.find("." + sIcon).removeClass(sRatingClass);
    // Add the 'active' class to the icon clicked and its previous siblings.
    $iconParent.find("." + sIcon + ":nth-child(-n+" + iIconIndex + ")").addClass(sRatingClass);
    // Set the rating to the parent, this can be sent to the backend with a REST service.
    $iconParent.attr("data-rating", iIconIndex);
  });

})();
.svg-spritesheet { /* Hide the SVG Spritesheet to prevent some browsers to render an empty white space. */
  display: none;
}
.icon { /* Default icon properties, using the currentColor variable to be able to change the icon's color with the CSS color property. */
  display: inline-block;
  width: 1em;
  height: 1em;
  stroke-width: 0;
  stroke: currentColor;
  fill: currentColor;
  cursor: pointer;
}
.icon-star-full { /* The icon's fill color */
  color: #C1C2C4;
}
.icon-star-full.rated { /* The icon's 'active' fill color */
  color: #F6DB08;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<section class="rating" data-rating="4">
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
</section>

<section class="rating" data-rating="0">
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
</section>



<svg class="svg-spritesheet">
  <symbol id="icon-star-full" viewBox="0 0 32 32">
    <title>star-full</title>
    <path d="M32 12.408l-11.056-1.607-4.944-10.018-4.944 10.018-11.056 1.607 8 7.798-1.889 11.011 9.889-5.199 9.889 5.199-1.889-11.011 8-7.798z"></path>
  </symbol>
</svg>

jsFiddle

使用IcoMoon免费星形图标。

游乐场:

你可以投入一些动画来进行一些视觉改善,就像AnimateCss一样。

$.fn.extend({
    animateCss: function (animationName) {
        var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
        this.addClass('animated ' + animationName).one(animationEnd, function() {
            $(this).removeClass('animated ' + animationName);
        });
    }
});

//Summary: Star Rating Component, get and/or set a rating displaying icons.
(function() {
  // Assign variables for jQuery Objects and classes as string.
  var $rating = $(".rating"),
    sRatingClass = "rated",
    sIcon = "icon-star-full",
    $icon = $("." + sIcon);

  // Iterate over jQuery Rating objects.
  $.each($rating, function() {
    // Get the rating if set, you can set this with a REST service and get the current rating.
    var iRating = $(this).data("rating");
    // Filter the icons with a :nth-child pseudo-class and add the 'active' class.
    $(this).find("." + sIcon + ":nth-child(-n+" + iRating + ")").addClass(sRatingClass);
  });

  // Add click event listener to jQuery Icon Objects.
  $icon.on("click", function() {
  	// Animate icon
    $(this).animateCss("bounceIn");
    // Get the index of the icon being clicked.
    var iIconIndex = $(this).index() + 1,
      // Select the parent of the icon being clicked.
      $iconParent = $(this).parent();
    // Remove the 'active' class to all the icons before setting the new ones.
    $iconParent.find("." + sIcon).removeClass(sRatingClass);
    // Add the 'active' class to the icon clicked and its previous siblings.
    $iconParent.find("." + sIcon + ":nth-child(-n+" + iIconIndex + ")").addClass(sRatingClass);
    // Set the rating to the parent, this can be sent to the backend with a REST service.
    $iconParent.attr("data-rating", iIconIndex);
  });

})();
.svg-spritesheet { /* Hide the SVG Spritesheet to prevent some browsers to render an empty white space. */
  display: none;
}
.icon { /* Default icon properties, using the currentColor variable to be able to change the icon's color with the CSS color property. */
  display: inline-block;
  width: 1em;
  height: 1em;
  stroke-width: 0;
  stroke: currentColor;
  fill: currentColor;
  cursor: pointer;
}
.icon-star-full { /* The icon's fill color */
  color: #C1C2C4;
  font-size: 3em;
}
.icon-star-full.rated { /* The icon's 'active' fill color */
  color: #F6DB08;
}

.animated {
    -webkit-animation-duration: 1s;
    animation-duration: 1s;
    -webkit-animation-fill-mode: both;
    animation-fill-mode: both
}
.animated.bounceIn {
    -webkit-animation-duration: .75s;
    animation-duration: .75s
}
@keyframes bounceIn {
    0%,100%,20%,40%,60%,80% {
        -webkit-animation-timing-function: cubic-bezier(0.215,.61,.355,1);
        animation-timing-function: cubic-bezier(0.215,.61,.355,1)
    }

    0% {
        opacity: 0;
        -webkit-transform: scale3d(.3,.3,.3);
        transform: scale3d(.3,.3,.3)
    }

    20% {
        -webkit-transform: scale3d(1.1,1.1,1.1);
        transform: scale3d(1.1,1.1,1.1)
    }

    40% {
        -webkit-transform: scale3d(.9,.9,.9);
        transform: scale3d(.9,.9,.9)
    }

    60% {
        opacity: 1;
        -webkit-transform: scale3d(1.03,1.03,1.03);
        transform: scale3d(1.03,1.03,1.03)
    }

    80% {
        -webkit-transform: scale3d(.97,.97,.97);
        transform: scale3d(.97,.97,.97)
    }

    100% {
        opacity: 1;
        -webkit-transform: scale3d(1,1,1);
        transform: scale3d(1,1,1)
    }
}

.bounceIn {
    -webkit-animation-name: bounceIn;
    animation-name: bounceIn
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<section class="rating" data-rating="4">
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
</section>

<section class="rating" data-rating="0">
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
  <svg class="icon icon-star-full">
    <use xlink:href="#icon-star-full"></use>
  </svg>
</section>



<svg class="svg-spritesheet">
  <symbol id="icon-star-full" viewBox="0 0 32 32">
    <title>star-full</title>
    <path d="M32 12.408l-11.056-1.607-4.944-10.018-4.944 10.018-11.056 1.607 8 7.798-1.889 11.011 9.889-5.199 9.889 5.199-1.889-11.011 8-7.798z"></path>
  </symbol>
</svg>