Toggle radio input using CSS only

前端 未结 6 1721
慢半拍i
慢半拍i 2020-12-09 04:00

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?

相关标签:
6条回答
  • 2020-12-09 04:29

    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>

    0 讨论(0)
  • 2020-12-09 04:36

    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.

    0 讨论(0)
  • 2020-12-09 04:37

    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>

    0 讨论(0)
  • 2020-12-09 04:37

    I have a solution which is halfway through:

    • It clears selection on double click but not on click (as requested)
    • But (and that's the "halfway"), it will not clear selection when double clicking the currently selected item (only when double clicking other items)

     .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%;
            }
    
            .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;
                width: 200px;
                height: 200px;
                z-index: 1;
                display: none;
            }
    
            .container #img1:checked ~ label[for=none],
            .container #img2:checked ~ label[for=none],
            .container #img3:checked ~ label[for=none] {
                display: block;
            }
    
            @keyframes hideNone {
                from {
                    z-index: 3;
                }
                to {
                    z-index: 3;
                }
            }
    
            .container #img1:checked ~ label[for=img1],
            .container #img2:checked ~ label[for=img2],
            .container #img3:checked ~ label[for=img3] {
                animation-name: hideNone;
                animation-delay: 0.3s;
                animation-duration: 99999s;
            }
    
            .container #img1:checked ~ label[for=none] {
                left: 0;
            }
    
            .container #img2:checked ~ label[for=none] {
                left: 220px;
            }
    
            .container #img3:checked ~ label[for=none] {
                left: 440px;
            }
    
            .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">
    
        <input id="none" type="radio" name="img-descr" checked>
        <label for="none"></label>
    
        <input type="button" autofocus>
        <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>

    Still thinking on how to improve it... :)

    0 讨论(0)
  • 2020-12-09 04:40

    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)

    0 讨论(0)
  • 2020-12-09 04:40

    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

    0 讨论(0)
提交回复
热议问题