Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toggle radio input using CSS only

Tags:

html

css

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?

(function(lastimg) {
  document.querySelector("#img-select").addEventListener('click', function(e){
    if (e.target.tagName.toLowerCase() == 'input') {
      if (lastimg == e.target) {
        e.target.checked = false;
        lastimg = null;
      } else {
        lastimg = e.target;
      }      
    }
  });
}());
.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,
.container #img4:checked ~ #img4txt {
  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">

  <label for="img1">
    <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="img3">
    <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>

Edit

I need a cross browser solution, working on the major browsers, and without script, just CSS.

To clarify, I want it to work as a normal radio input, but if clicked twice, or repeatedly, on the same, it should toggle itself as a checkbox input does.

Also markup change are allowed, as long as the layout structure is kept the same, and I would also prefer if it can break line, as a page can have more than 3 recipes.

Edit 2

The main focus of the question is how to make a radio input togglable, though since a couple of answers show other ways to toggle a state with pure CSS, any such tricks is welcome.

like image 570
Asons Avatar asked Mar 22 '16 18:03

Asons


People also ask

How do I select a radio button in CSS?

For a radio button, you can use the input[type="radio"]:checked + label selector, which matches a label that immediately follows a checked input of type radio.

How do you style an input type radio?

In your code you need to add <label for="r2"><span></span>Radio Button 2</label> after creating radio and using my css code you can do this. @DipeshParmar using input[type="radio"] { display:none; } will take out keyboard access from the radio buttons.

How do you style radio buttons as buttons?

Unfortunately you can't style radio buttons directly in any browser. The way to do it is to use <label> elements with properly set for attributes, then hide the radio button itself using visibility: hidden rather than display: none . You can then position the labels wherever you want and they will act as radio buttons.

How do I change the radio button shape in HTML?

Go to the Style tab and scroll to the bottom of the survey preview. Click the HTML/CSS Editor link. Copy and paste the below CSS code in the field on the Custom CSS tab. Under Layout > Layout Options tab, make sure the option to Use Default Browser Icons for Radio Buttons and Checkboxes is unchecked.


2 Answers

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)

like image 110
Ajedi32 Avatar answered Oct 08 '22 00:10

Ajedi32


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>
like image 33
Oriol Avatar answered Oct 08 '22 00:10

Oriol