How to create a toggle button with input = checkbox without using the label element?

4

Create / transform a <input type="checkbox"> on a toggle button without needing the <label> element as in these examples:

An example I made based on the Andreas Storm code was this:

body {
    background: #eee;
}

.toggle {
    margin-bottom: 20px;
}

.toggle > input {
    display: none;
}

.toggle > label {
    position: relative;
    display: block;
    height: 28px;
    width: 52px;
    background-color: #f7f7f7;
    border: 1px #a2e3e6 solid;
    border-radius: 100px;
    cursor: pointer;
    transition: all 0.3s ease;
}
.toggle > label:after {
    position: absolute;
    left: 1px;
    top: 1px;
    display: block;
    width: 26px;
    height: 26px;
    border-radius: 100px;
    background: #fff;
    box-shadow: 0px 3px 3px rgba(0,0,0,0.05);
    content: '';
    transition: all 0.3s ease;
}
.toggle > label:active:after {
    transform: scale(1.15, 0.85);
}
.toggle > input:checked ~ label {
    background-color: #4cda64;
    border-color: #4cda64;
}
.toggle > input:checked ~ label:after {
    left: 25px;
}
.toggle > input:disabled ~ label {
    background-color: #d5d5d5;
    pointer-events: none;
}
.toggle > input:disabled ~ label:after {
    background-color: rgba(255, 255, 255, 0.3);
}
<div class="toggle">
    <input type="checkbox" id="foo">
    <label for="foo"></label>
</div>

<div class="toggle">
    <input type="checkbox" id="bar" checked>
    <label for="bar"></label>
</div>

<div class="toggle">
    <input type="checkbox" id="baz" disabled>
    <label for="baz"></label>
</div>

Would it be possible to create something like this without a label and without any other element (and without JavaScript too)?

    
asked by anonymous 19.02.2018 / 14:12

2 answers

5

It is possible to use two pseudo elements, ::before and ::after , you will also need to use the -webkit-appearance: and -moz-appearance: (and future appearance: ) properties.

Of course the effect will only work on Firefox, WebKit browsers (Safari, iOS and Android) and Chrome (and Chromium based browsers), Edge and IE will not work

It should look like this:

/*Adiciona border-box para o input e para os pseudo-elementos*/
input[type=checkbox], input[type=checkbox]::after, input[type=checkbox]::before {
    box-sizing: border-box;
}

/*Estiliza e remove a aparencia padrão do elemento*/
input[type=checkbox] {
    outline: none;
    position: relative;
    z-index: 1;
    margin: 2px;
    padding: 0;
    cursor: pointer;
    width: 48px;
    height: 24px;
    overflow: hidden;
    -webkit-appearance: none;
    -moz-appearance: none;
    appearance: none;
}

/*cria os elementos before e after*/
input[type=checkbox]::before, input[type=checkbox]::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    z-index: 2;

    /*efeito animado*/
    transition: left .15s cubic-bezier(.25, .8, .25, .1),
                transform .15s ease-in;
}

/*Cor padrão de quando o elemento não esta selecionado*/
input[type=checkbox]::before {
    background-color: #ccc;
    width: 100%;
    height: 100%;
    border-radius: 28px;
}

/*estiliza para parecer um botão toggle*/
input[type=checkbox]::after {
    margin: 2px 0 0 2px;
    background: #fff;
    width: 20px;
    height: 20px;
    border-radius: 100%;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
}

/*troca a cor se estiver com a propriedade checked no html ou o usuário "checar"*/
input[type=checkbox]:checked::before {
    background-color: #75a940;
}

/*muda a posição do botão toggle se estiver checado*/
input[type=checkbox]:checked::after {
    left: 24px;
}

/*Efeito opicional de quando preciona o botão*/
input[type=checkbox]:active::after {
    transform: scale(1.15, 0.85);
}

/*Se o input tiver com o atributo disabled a cor é alterada*/
input[type=checkbox]:disabled::before {
     background-color: #b1b4b7 !important;
}

/*Se o input tiver com o atributo disabled a cor é alterada*/
input[type=checkbox]:disabled::after {
     background-color: #dcd8d8 !important;
}

/*OUTRAS CORES = Cores alternativas*/

input[type=checkbox].red:checked::before {
     background-color: #fd4554;
}

input[type=checkbox].blue:checked::before {
     background-color: #0f90dc;
}

input[type=checkbox].red:checked::before {
     background-color: #fd4554;
}

input[type=checkbox].purple:checked::before {
     background-color: #9e3eff;
}
<input type="checkbox">
<input type="checkbox" class="red">
<input type="checkbox" class="blue">
<input type="checkbox" class="purple">
<input type="checkbox" class="purple" disabled>

<hr>

<input type="checkbox" checked>
<input type="checkbox" class="red" checked>
<input type="checkbox" class="blue" checked>
<input type="checkbox" class="purple" checked>
<input type="checkbox" class="purple" checked disabled>
    
19.02.2018 / 14:12
0

I have a similar option to Guilherme, however I give all:unset in the checkbox first to clear all default formatting of user-agent

Then I type input itself as I want and use only ::after . It worked in Chrome and FireFox, I believe that Safari tb will work. In IE and Edge does not go as expected.

OBS: From an accessibility point of view, since it is an item of form without label , it would be interesting to assign a aria-label=" " to ckeckbox saying which is about that btn. If you are interested here is the W3C recommendation on the subject link

  .btn {
    all: unset;
    position: relative;
    display: inline-block;
    width: 60px;
    height: 30px;
    background-color: #f00;
    border-radius: 15px;
    cursor: pointer;
    border: 1px solid #ccc;
    box-shadow: inset 0 0 5px 0 rgba(0,0,0,0.75);
    transition: background-color 100ms ease-in-out;
  }
  .btn:checked {
    background-color: #090;
  }
  .btn::after {
    content: "";
    position: absolute;
    height: 20px;
    width: 20px;
    box-sizing: border-box;
    border: 1px solid #666;
    border-radius: 50%;
    box-shadow: 0 0 8px rgba(0,0,0,0.5);
    background-image: radial-gradient(#fff 0%, #999 100%);
    top: 50%;
    left: 5px;
    transform: translateY(-50%) scale(1, 1);
    transition: left 200ms ease-in-out, transform 150ms ease-in-out;
  }
  .btn:checked::after {
    left: calc(100% - 25px);
  }
  .btn:active::after {
    transform: translateY(-50%) scale(1.15, 0.85);
  }
  <input class="btn" type="checkbox" aria-label="btn seleciona opção x">
    
15.07.2018 / 03:21