Skip to content Skip to sidebar Skip to footer

Toggle Radio Input Using CSS Only

The following code use a script to toggle/uncheck a radio when clicked a second time on the same. My question is how do I do this using CSS only? Edit I need a cross browser solut

Solution 1:

You can't change the functionality of radio buttons using CSS. CSS is designed for visual changes only.

That said, you can simulate this behavior with a clever hack. For your example, I'd recommend using CSS to visually replace the label for the currently selected radio button with a dummy label attached to another radio button representing a "blank" or "empty" selection. That way, clicking the dummy label would select the "blank" option, effectively clearing your prior choice:

.container {
  display: flex;
  flex-wrap: wrap;
  max-width: 660px;
}
.container > label {
  flex: 1;
  flex-basis: 33.333%;
}
.container > div {
  flex: 1;
  flex-basis: 100%;
}
.container label img {
  display: block;
  margin: 0 auto;
}
.container input, .container input ~ div {
  display: none;
  padding: 10px;
}

.container #img1:checked ~ #img1txt,
.container #img2:checked ~ #img2txt,
.container #img3:checked ~ #img3txt {
  display: block;
}

.container label[for=noimg] {
  display: none;
}

.container #img1:checked ~ label[for=img1],
.container #img2:checked ~ label[for=img2],
.container #img3:checked ~ label[for=img3] {
  display: none;
}

.container #img1:checked ~ label[for=img1] + label[for=noimg],
.container #img2:checked ~ label[for=img2] + label[for=noimg],
.container #img3:checked ~ label[for=img3] + label[for=noimg] {
  display: block;
}
<div id="img-select" class="container">
  <input id="noimg" type="radio" name="img-descr">
  <input id="img1" type="radio" name="img-descr">
  <input id="img2" type="radio" name="img-descr">
  <input id="img3" type="radio" name="img-descr">

  <label for="img1">
    <img src="http://lorempixel.com/200/200/food/1/" alt="">
  </label>
  <label for="noimg">
    <img src="http://lorempixel.com/200/200/food/1/" alt="">
  </label>
  <label for="img2">
    <img src="http://lorempixel.com/200/200/food/6/" alt="">
  </label>
  <label for="noimg">
    <img src="http://lorempixel.com/200/200/food/6/" alt="">
  </label>
  <label for="img3">
    <img src="http://lorempixel.com/200/200/food/8/" alt="">
  </label>
  <label for="noimg">
    <img src="http://lorempixel.com/200/200/food/8/" alt="">
  </label>

  <div id="img1txt">
    <div>Recipe nr 1</div>
  </div>
  <div id="img2txt">
    <div>Recipe nr 2</div>
  </div>
  <div id="img3txt">
    <div>Recipe nr 3</div>
  </div>
</div>

(View in JSFiddle)


Solution 2:

If the effect does not need to be persistent, you can achieve something similar playing with :focus instead of using radio buttons.

To make an element focusable, set the tabindex attribute to an integer. Use a negative one if you don't want the element to be reached via sequential focus navigation (pressing the "tab" key).

.container {
  display: flex;
  flex-wrap: wrap;
  max-width: 660px;
}
.container > .img {
  flex: 1;
  position: relative;
}
.container > .img > .unselect {
  display: none;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
}
.container > .txt {
  display: none;
  order: 1;
  flex-basis: 100%;
}
.container > .img:focus > .unselect,
.container > .img:focus + .txt {
  display: block;
}
<div id="img-select" class="container">
  <div class="img" tabindex="0">
    <img src="http://lorempixel.com/200/200/food/1/" alt="">
    <span class="unselect" tabindex="-1"></span>
  </div>
  <div class="txt">Recipe nr 1</div>
  <div class="img" tabindex="0">
    <img src="http://lorempixel.com/200/200/food/6/" alt="">
    <span class="unselect" tabindex="-1"></span>
  </div>
  <div class="txt">Recipe nr 2</div>
  <div class="img" tabindex="0">
    <img src="http://lorempixel.com/200/200/food/8/" alt="">
    <span class="unselect" tabindex="-1"></span>
  </div>
  <div class="txt">Recipe nr 3</div>
</div>

Solution 3:

Bounty Challenge Accepted (without the extra noimg)

.container {
    display: flex;
    flex-wrap: wrap;
    max-width: 660px;
    overflow: hidden;
    position: relative;
}
.container img {
    user-select: none;
    pointer-events: none;
}
.container > label {
    flex: 1;
    flex-basis: 33.333%;
    z-index: 1;
}
.container > div {
    flex: 1;
    flex-basis: 100%;
}
.container label img { margin: 0 auto }
.container input,
.container input ~ div {
    display: none;
    padding: 10px;
}
.container label[for=none] {
    position: absolute;
    bottom: 0;
    top: 0;
    left: 0;
    right: 0;
    z-index: 0;
}
.container #img1:checked ~ label[for=img1],
.container #img2:checked ~ label[for=img2],
.container #img3:checked ~ label[for=img3] {
    pointer-events: none;
    z-index: -1;
}
.container #img1:checked ~ #img1txt,
.container #img2:checked ~ #img2txt,
.container #img3:checked ~ #img3txt { display: block }
<div id="img-select" class="container">
  <input id="img1" type="radio" name="img-descr">
  <input id="img2" type="radio" name="img-descr">
  <input id="img3" type="radio" name="img-descr">

  <!-- Experimental -->
  <input id="none" type="radio" name="img-descr" checked>
  <label for="none"></label>

  <label for="img1">
    <img src="http://dummyimage.com/200/333" alt="">
  </label>
  <label for="img2">
    <img src="http://dummyimage.com/200/666" alt="">
  </label>
  <label for="img3">
    <img src="http://dummyimage.com/200/999" alt="">
  </label>

  <div id="img1txt">
    <div>Recipe nr 1</div>
  </div>
  <div id="img2txt">
    <div>Recipe nr 2</div>
  </div>
  <div id="img3txt">
    <div>Recipe nr 3</div>
  </div>
</div>

EDIT: By definition radio buttons shouldn't be toggleable (I forgot that this was an additional requirement in this task = to broke the rules). @Ajedi32 answer is probably the best, but it can be optimized (repeated images)? Bounty still in game...

EDIT 2: Now it's fully functional solution. (doing this trick https://stackoverflow.com/a/7392038/2601031)

EDIT 3: Multi-layer layout + Repaired selection.


Solution 4:

The answer is you can't unselect or uncheck a radio button in CSS only, as the radio button only becomes unchecked once you click on a different radio button. As only one radio button can be active at once, this will uncheck the previously checked radio button.

input:checked + label {
    color: green;
}

input:not(:checked) + label {
    color: red;
}

So you'll have to stick with using the JS function you posted.

Here are a couple of nice articles with further explanation :

CSS Click Events

How To Generate CSS Click Events


Solution 5:

The trick is using :target. I added two empty <a> tags in each block, and set them to cover the block completely in order to perform the click event. The first link is for the real :target event, and second link is just for undo it, with a bit help of z-index to make it happen.

jsFiddle

ul {
  padding: 0;
  margin: 0;
}
li {
  display: inline-block;
  vertical-align: top;
  position: relative;
}
a {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
div {
  display: none;
}
.target{
  z-index: 1;
}
.target:target {
  z-index: -1;
}
.target:target ~ div{
  display: block;
}
<ul>
  <li>
    <a href="#link-1" id="link-1" class="target"></a>
    <a href="#"></a>
    <img src="//dummyimage.com/150/333">
    <div>a</div>
  </li>
  <li>
    <a href="#link-2" id="link-2" class="target"></a>
    <a href="#"></a>
    <img src="//dummyimage.com/150/666">
    <div>b</div>
  </li>
  <li>
    <a href="#link-3" id="link-3" class="target"></a>
    <a href="#"></a>
    <img src="//dummyimage.com/150/999">
    <div>c</div>
  </li>
</ul>

Post a Comment for "Toggle Radio Input Using CSS Only"