Mark van Herpen
Mark van Herpen

Reputation: 347

CSS for checked radio button with multiple labels

I'm having css issues with a second label on a radio button, when this radio button is checked. I already found out that a second (and a third) label is possible using 'for' in the label-tag. It's not possible to group everything in a single label-tag.

How can I change the background for the second label when a radio button is checked?

My (simplified) code is below, for the first label it works, second label it doesn't.

.radioclass:checked + label {
  background-color: cyan;
}
<div class="row">
  <div class="col-sm-4">
    <input class="radioclass" id="id_radiobtn1" type="radio" name="radiobtn1" value="1">
    <label for="id_radiobtn1">first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1">second label</label>
  </div>
</div>

Upvotes: 3

Views: 2991

Answers (4)

David Thomas
David Thomas

Reputation: 253308

Using just CSS this is possible, although it does require a rearrangement of your HTML, effectively moving the radio <input> ahead of the elements in which the <label> elements are contained; this removes the (impossible in CSS) requirement of traversing to the parent of the <input> in order to style the non-sibling <label> elements.

/* selects the element with the id of 'id_radiobtn1' when it is
   checked, uses the general sibling combinator (~) to select
   all sibling <div> elements with the class of 'col-sm-4'
   and then finds the descendant <label> elements within
   that/those <div> elements whose 'for' attribute-value is
   equal to 'id_radiobtn1': */
#id_radiobtn1:checked ~ div.col-sm-4 label[for=id_radiobtn1] {
  background-color: cyan;
}
<div class="row">
  <input class="radioclass" id="id_radiobtn1" type="radio" name="radiobtn1" value="1" />
  <div class="col-sm-4">
    <label for="id_radiobtn1">first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1">second label</label>
  </div>
</div>

Now, if you must have a visible radio <input> besides the first of the <label> elements, you can use a pseudo-element to effectively pretend, while also hiding the real radio <input>:

*,
 ::before,
 ::after {
 /* to include border and padding in the calculated
    dimensions (width/height) of the elements: */
  box-sizing: border-box;
}

.row>input[type=radio] {
  /* hiding the radio <input> elements: */
  display: none;
}

/* selecting the <input> elements whose type is
   equal to 'radio', which is checked and then
   finding all (subsequent) sibling elements
   (using the '~' combinator) which <div>
   elements with a class of 'col-sm-4', and
   traversing to the <label> elements within: */
input[type=radio]:checked~div.col-sm-4 label {
  background-color: cyan;
}

label {
  /* in order to ensure that the descendant
     pseudo-elements are positioned relative
     to their parent element: */
  position: relative;
  /* making room for the pseudo-elements: */
  margin-left: 2em;
}

input[type=radio]+.col-sm-4 label::before {
  /* the content property is required, even
     if only an empty string, to have the
     pseudo-element show up: */
  content: '';
  display: inline-block;
  /* positioning absolutely, in relation to
     the closest ancestor with a non 'static'
     position, in this case the parent
     <label> element: */
  position: absolute;
  /* moving it outside of the <label> element's
     left border, to avoid the background-color: */
  left: -2em;
  /* purely aesthetic: */
  width: 0.8em;
  height: 0.8em;
  /* arbitrary positioning, adjust to taste: */
  top: 50%;
  transform: translateY(-40%);
  /* making the pseudo-element circular in shape: */
  border-radius: 50%;
  /* colouring the faux 'border': */
  box-shadow: 0 0 0 2px #ccc;
}

/* adjusting the colours of the faux radio: */
input[type=radio]:checked+.col-sm-4 label::before {
  box-shadow: 0 0 0 2px #000, inset 0 0 0 3px #fff;
  background-color: limegreen;
}
<div class="row">
  <input class="radioclass" id="id_radiobtn1" type="radio" name="group1" value="1" />
  <div class="col-sm-4">
    <label for="id_radiobtn1">row one first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1">row one second label</label>
  </div>
</div>
<div class="row">
  <input class="radioclass" id="id_radiobtn2" type="radio" name="group1" value="2" />
  <div class="col-sm-4">
    <label for="id_radiobtn2">row two first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn2">row two second label</label>
  </div>
</div>

Upvotes: 2

Ehsan
Ehsan

Reputation: 12951

You can't do it with pure css, because backward in css is impossible.You can help of Jquery:

Note: I insert lab2 class to label.

$(document).ready(function(){
    $('input[type=radio]').on('change',function(){
        if($('.radioclass').is(':checked'))
            $('.lab2').addClass('sel');
        else
            $('.lab2').removeClass('sel');
    })
})

$(document).ready(function(){
    $('input[type=radio]').on('change',function(){
        if($('.radioclass').is(':checked'))
            $('.lab2').addClass('sel');
        else
            $('.lab2').removeClass('sel');
    })
})
#id_radiobtn1:checked + label {
    background-color: green;
}

.sel {
    background-color: red;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="row">
  <div class="col-sm-4">
    <input class="radioclass" id="id_radiobtn1" type="radio" name="radiobtn1" value="1">
    <label for="id_radiobtn1">first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1" class="lab2">second label</label>
  </div>
</div>

Upvotes: 0

Richard Parnaby-King
Richard Parnaby-King

Reputation: 14862

The + selector in css means "immediate sibling", i.e. the very next element after the input must be a label. This will only select the immediate sibling.

An alternative is ~ which means "any sibling" and targets any label after the input.

In both of these cases, the elements (input and label) are on the same dom level. There is no way to traverse up the dom, grab the sibling and then the label - which is what you are trying to do with the html supplied.

If you are able to change the html, then either place the input outside the two divs or place both labels inside the same div (after the input).

.radioclass:checked ~ div label {
  background-color: cyan;
}
<div class="row">
  <input class="radioclass" id="id_radiobtn1" type="radio" name="radiobtn1" value="1">
  <div class="col-sm-4">
    <label for="id_radiobtn1">first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1">second label</label>
  </div>
</div>

.radioclass:checked ~ label {
  background-color: cyan;
}
<div class="row">
  <div class="col-sm-4">
    <input class="radioclass" id="id_radiobtn1" type="radio" name="radiobtn1" value="1">
    <label for="id_radiobtn1">first label</label>
    <label for="id_radiobtn1">second label</label>
  </div>
</div>

If you cannot alter the html, then JS is the only other approach (I've changed the input to a checkbox for demonstration purposes):

$('input').on('change', function(){
  var func = 'removeClass';
  if($(this).is(':checked')) {
    func = 'addClass';
  }
  
  $('label[for="'+$(this).attr('id')+'"]')[func]('checked');
});
label.checked {
  background-color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="row">
  <div class="col-sm-4">
    <input class="radioclass" id="id_radiobtn1" type="checkbox" name="radiobtn1" value="1">
    <label for="id_radiobtn1">first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1">second label</label>
  </div>
</div>

Upvotes: 2

Ayaz Ali Shah
Ayaz Ali Shah

Reputation: 3531

You can do with Jquery on change event.

$(document).ready(function() {
$('#id_radiobtn1').on('change',function(){
$( "label:contains('second')" ).css( "background-color", "red" );
});
});
.radioclass:checked + label {
  background-color: cyan;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
  <div class="col-sm-4">
    <input class="radioclass" id="id_radiobtn1" type="radio" name="radiobtn1" value="1">
    <label for="id_radiobtn1">first label</label>
  </div>
  <div class="col-sm-4">
    <label for="id_radiobtn1">second label</label>
  </div>

Upvotes: 0

Related Questions