Usa immagini come caselle di controllo


165

Vorrei avere un'alternativa a una casella di controllo standard: fondamentalmente mi piacerebbe usare le immagini e quando l'utente fa clic sull'immagine, la sbiadisce e sovrappone una casella di spunta.

In sostanza, voglio fare qualcosa come fa Recaptcha 2 quando riesci a fare clic su immagini che soddisfano determinati criteri. Puoi vedere una demo di Recaptcha qui, ma a volte potrebbe farti risolvere le domande di testo, al contrario della selezione dell'immagine. Quindi ecco uno screenshot:

Schermata di Google Recaptcha

Quando si fa clic su una delle immagini (in questo caso, contenente un'immagine di bistecca), l'immagine su cui si fa clic si riduce di dimensioni e viene visualizzato il segno di spunta blu, a indicare che è stato selezionato.

Diciamo che voglio riprodurre questo esempio esatto.

Mi rendo conto di poter avere 9 caselle di controllo nascoste e allegare alcune jQuery in modo che quando faccio clic sull'immagine, selezioni / deselezioni la casella di controllo nascosta. Ma per quanto riguarda il restringimento dell'immagine / sovrapposizione del segno di spunta?


2
puoi avere due immagini identiche: una con segno di spunta e l'altra senza segno di spunta. E cambia le immagini con un clic
Alex

23
@Alex Sarebbe una soluzione particolarmente poco flessibile.
Siguza,

2
Hai provato ad aggiungere / rimuovere una classe CSS al clic che sovrascrive la dimensione dell'immagine e fa un po 'di :beforemagia per l'immagine tick?
Esaolico il

3
@Alex "Non flessibile", nel senso che richiederebbe molto più lavoro per cambiare qualcosa, come aggiungere una nuova foto alla collezione o cambiare l'icona "spuntata", quando ciò non sarebbe il caso se l'effetto fosse programmato su runtime.
Siguza,

2
@Christian Sostituire le caselle di controllo con qualcosa di personalizzato è una decisione di progettazione popolare (anche se è solo una casella di controllo in stile) e trovare modi buoni / semplici per farlo è sicuramente interessante per gli sviluppatori che hanno dovuto affrontarlo. E questa domanda (sovrapponendo la sostituzione della casella di controllo su qualcos'altro) la rende sicuramente interessante. In particolare, nota come la risposta accettata non utilizza affatto JS, nonostante l'apparente complessità del compito
Izkata,

Risposte:


309

Pura soluzione semantica HTML / CSS

È facile da implementare da solo, non è necessaria alcuna soluzione prefabbricata. Inoltre ti insegnerà molto in quanto non sembri troppo facile con i CSS.

Questo è quello che hai bisogno di fare:

Le tue caselle di controllo devono avere idattributi distinti . Ciò ti consente di collegarti <label>a, usando l' forattributo- label dell'etichetta.

Esempio:

<input type="checkbox" id="myCheckbox1" />
<label for="myCheckbox1"><img src="http://someurl" /></label>

Il collegamento dell'etichetta alla casella di controllo attiverà un comportamento del browser: ogni volta che qualcuno fa clic sull'etichetta (o sull'immagine al suo interno), la casella di controllo verrà attivata.

Successivamente, nascondi la casella di controllo applicando ad esempio display: none;ad essa.

Ora non resta che impostare lo stile desiderato per il tuo label::beforepseudo elemento (che verrà utilizzato come elementi di sostituzione della casella di controllo visiva):

label::before {
    background-image: url(../path/to/unchecked.png);
}

In un ultimo passaggio complicato, fai uso dello :checkedpseudo-selettore CSS per cambiare l'immagine quando la casella è selezionata:

:checked + label::before {
    background-image: url(../path/to/checked.png);
}

Il +( selettore di fratello adiacente ) si assicura di cambiare solo le etichette che seguono direttamente la casella di controllo nascosta nel markup.

Puoi ottimizzarlo inserendo entrambe le immagini in una mappa sprit e applicando solo una modifica background-positioninvece di scambiare l'immagine.

Naturalmente è necessario posizionare correttamente l'etichetta, applicare display: block;e impostare correttamente widthe height.

Modificare:

L'esempio e lo snippet di codepen, che ho creato dopo queste istruzioni, utilizzano la stessa tecnica, ma invece di utilizzare le immagini per le caselle di controllo, le sostituzioni delle caselle di controllo vengono eseguite esclusivamente con CSS , creando un ::beforesull'etichetta che, una volta selezionata, ha content: "✓";. Aggiungi alcuni bordi arrotondati e dolci transizioni e il risultato è davvero piacevole!

Ecco un codice funzionante che mostra la tecnica e non richiede immagini per la casella di controllo:

http://codepen.io/anon/pen/wadwpx

Ecco lo stesso codice in uno snippet:

ul {
  list-style-type: none;
}

li {
  display: inline-block;
}

input[type="checkbox"][id^="cb"] {
  display: none;
}

label {
  border: 1px solid #fff;
  padding: 10px;
  display: block;
  position: relative;
  margin: 10px;
  cursor: pointer;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

label::before {
  background-color: white;
  color: white;
  content: " ";
  display: block;
  border-radius: 50%;
  border: 1px solid grey;
  position: absolute;
  top: -5px;
  left: -5px;
  width: 25px;
  height: 25px;
  text-align: center;
  line-height: 28px;
  transition-duration: 0.4s;
  transform: scale(0);
}

label img {
  height: 100px;
  width: 100px;
  transition-duration: 0.2s;
  transform-origin: 50% 50%;
}

:checked+label {
  border-color: #ddd;
}

:checked+label::before {
  content: "✓";
  background-color: grey;
  transform: scale(1);
}

:checked+label img {
  transform: scale(0.9);
  box-shadow: 0 0 5px #333;
  z-index: -1;
}
<ul>
  <li><input type="checkbox" id="cb1" />
    <label for="cb1"><img src="https://picsum.photos/seed/1/100" /></label>
  </li>
  <li><input type="checkbox" id="cb2" />
    <label for="cb2"><img src="https://picsum.photos/seed/2/100" /></label>
  </li>
  <li><input type="checkbox" id="cb3" />
    <label for="cb3"><img src="https://picsum.photos/seed/3/100" /></label>
  </li>
  <li><input type="checkbox" id="cb4" />
    <label for="cb4"><img src="https://picsum.photos/seed/4/100" /></label>
  </li>
</ul>


32
Contento che ti piaccia! Inizia a giocherellare con i CSS di più, è molto divertente e i CSS possono fare molto di più di quanto probabilmente ti aspetteresti (tranne che per il centraggio verticale, è semplicemente troppo difficile;)).
connexo,

1
Sì, e capire come funziona ti farà pensare in futuro, ogni volta che vuoi un'azione DOM al clic. E hai pensato di poter reagire solo a :hover:)
connexo

Sarà la prossima cosa da guardare su Pluralsight - alcune cose CSS :)
bgs264,

6
Questo è molto carino! Ho notato un piccolo problema quando si fa clic due volte sulla stessa etichetta, seleziona l'immagine. Questo risolve: codepen.io/anon/pen/jPmNjg
Ayesh K

1
Tick ​​sarebbe sembrato migliore come SVG. Il contenuto CSS ti mette in balia di alcuni terribili caratteri di sistema.
Adria,

31

Soluzione CSS pura

Esistono tre dispositivi ordinati:

  1. Il :checkedselettore
  2. Lo ::beforepseudo-selettore
  3. La contentproprietà css .

label:before {
  content: url("https://cdn1.iconfinder.com/data/icons/windows8_icons_iconpharm/26/unchecked_checkbox.png");
  position: absolute;
  z-index: 100;
}
:checked+label:before {
  content: url("https://cdn1.iconfinder.com/data/icons/windows8_icons_iconpharm/26/checked_checkbox.png");
}
input[type=checkbox] {
  display: none;
}
/*pure cosmetics:*/
img {
  width: 150px;
  height: 150px;
}
label {
  margin: 10px;
}
<input type="checkbox" id="myCheckbox1" />
<label for="myCheckbox1">
  <img src="https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcR0LkgDZRDTgnDrzhnXGDFRSItAzGCBEWEnkLMdnA_zkIH5Zg6oag">
</label>
<input type="checkbox" id="myCheckbox2" />
<label for="myCheckbox2">
  <img src="https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcRhJjGB3mQxjhI5lfS9SwXou06-2qT_0MjNAr0atu75trXIaR2d">
</label>
<input type="checkbox" id="myCheckbox3" />
<label for="myCheckbox3">
  <img src="https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQuwWbUXC-lgzQHp-j1iw56PIgl_2eALrEENUP-ld72gq3s8cVo">
</label>


Come è possibile aggiungere un comportamento pulsante di opzione a queste caselle di controllo? Intendo quando si fa clic su un'immagine, l'immagine già selezionata viene deselezionata.
Libertad,

Chiunque si ponga la stessa domanda di @Libertad cambia semplicemente il tipo di ingressi in radio e dà loro lo stesso "attributo" <input type="radio" name="myRadio" id="myRadio1" />anche cambiare il tuo CSS per nascondere il proiettile:input[type=radio]{display: none;}
Lou

8

Vedi questo plugin jQuery: imgCheckbox (su npm e bower )

Disclaimer: non è necessario javascript per risolvere questo problema. La tensione è tra manutenibilità ed efficienza del codice. Sebbene non sia necessario un plug-in (o qualsiasi javascript), lo rende sicuramente più veloce da costruire e spesso più facile da modificare.

Soluzione barebone:

Con HTML molto semplice (nessuno dei casini con caselle di controllo, etichette, ecc.):

<img class="checkable" src="http://lorempixel.com/100/100" />

È possibile utilizzare toggleClass di jQuery per attivare / disattivare una selectedo checkedclasse clicksull'evento:

$("img.checkable").click(function () {
    $(this).toggleClass("checked");
});

Gli elementi selezionati vengono recuperati con

$(".checked")

Più freddezza:

È possibile modellare le immagini in base a questo, ma un grosso problema è che senza altri elementi DOM non è nemmeno possibile utilizzare ::beforee ::afteraggiungere elementi come segni di spunta. La soluzione è avvolgere le tue immagini con un altro elemento (ed è logico collegare anche il listener di clic all'elemento avvolto).

$("img.checkable").wrap("<span class='fancychecks'>")

Questo lascia il tuo HTML davvero pulito e il tuo js incredibilmente leggibile. Dai un'occhiata allo snippet ...

Utilizzando il plug-in jQuery imgCheckbox :

Ispirato dalla soluzione sopra, ho creato un plug-in che può essere usato facilmente come:

$("img").imgCheckbox();
  • Inietta i dati per le immagini verificate nel modulo
  • Supporta segni di spunta personalizzati
  • Supporta CSS personalizzato
  • Supporta elementi preselezionati
  • Supporta gruppi radio invece della semplice commutazione delle immagini
  • Ha richiamate di eventi
  • Impostazioni predefinite sensibili
  • Leggero e super facile da usare

Guardalo in azione (e vedi la fonte )


Mi piace anche questo approccio, ma ha una serie di aspetti negativi che vale la pena menzionare, il più grande dei quali è questo: supponendo che l'utente debba scegliere le immagini, le informazioni fornite dall'utente in questo modo sono sicuramente pensate per essere elaborate in qualche modo, tramite una chiamata AJAX o tramite un modulo di invio. Per la pruposi di un'ulteriore elaborazione delle informazioni fornite dall'utente, avere caselle di controllo in cui una serie di scelte devono essere riflesse ed elaborate è solo il modo naturale e semantico di farlo.
connexo,

Questo è vero, è nella mia lista delle cose da fare per il plugin - per dirottare l'invio del modulo e iniettare i dati nel modulo. Ma hai ragione, le caselle di controllo sono semantiche per i moduli
jcuenod,

Ho provato a utilizzare il tuo plug-in, ma se aggiungo più immagini dopo l'inizializzazione, non sembra esserci un modo per distruggere l'istanza precedente in modo da poter includere le nuove immagini
Ian Kim,

@IanKim interessante caso d'uso, puoi spiegare di più su cosa stai cercando di fare in un problema su Github? github.com/jcuenod/imgCheckbox
jcuenod

È un plugin fantastico! per favore pubblica un Webjar =)
naXa

6

Aggiungerei un div extra con position: relative;e class="checked"che abbia la stessa larghezza / altezza dell'immagine e della posizione che left: 0; top: 0;contiene nel contenere l'icona. Comincia con display: none;.

Ora puoi ascoltare il click-event:

$( '.captcha_images' ).click( function() {
    $(this + '.checked').css( 'display', 'block' );
    $(this).animate( { width: '70%', height: '70%' } );
});

In questo modo è possibile ottenere l'icona e ridimensionare l'immagine in un modo più piccolo.

Avviso: volevo solo mostrarti la "logica" dietro i miei pensieri, questo esempio potrebbe non funzionare o contiene alcuni bug.


La tecnica che ho dimostrato è così semplice e robusta, che viene persino spesso applicata in situazioni in cui non si hanno caselle di spunta semantiche, come attivare o disattivare la visualizzazione di altri elementi e simili. Questo è il caso d'uso in cui non è solo la soluzione più semplice e flessibile, ma anche la migliore semanticamente.
connexo,

2
Sì hai ragione. All'inizio volevo sottolineare la tua prima risposta e migliorarla (prima della modifica), perché mi piace No-JS e piacevoli modi semantici, ma poi ho letto che l'OP vuole qualcosa in jQuery, quindi ho cambiato la mia risposta. Ricordo dove ho ottenuto un downvote, perché l'OP non voleva una soluzione "migliore" o "nel modo giusto", ma il modo esatto in cui ha scritto. Forse c'è solo qualcosa che ho letto o non ho capito o dipende dall'OP?
Cagatay Ulubay,

2

Ho notato che altre risposte non usano <label>(perché no?), O richiedono corrispondenze fore idattributi. Ciò significa che se si hanno ID in conflitto, il codice non funzionerà e sarà necessario ricordarsi di creare ID univoci ogni volta.

Inoltre, se si nasconde il inputcon display:noneo visibility:hidden, il browser non si concentrerà su di esso.

Una casella di controllo e il relativo testo (o, in questo caso, immagine) possono essere racchiusi in un'etichetta:

.fancy-checkbox-label > input[type=checkbox] {
  position: absolute;
  opacity: 0;
  cursor: inherit;
}
.fancy-checkbox-label {
  font-weight: normal;
  cursor: pointer;
}
.fancy-checkbox:before {
  font-family: FontAwesome;
  content: "\f00c";
  background: #fff;
  color: transparent;
  border: 3px solid #ddd;
  border-radius: 3px;
  z-index: 1;
}
.fancy-checkbox-label:hover > .fancy-checkbox:before,
input:focus + .fancy-checkbox:before {
  border-color: #bdbdff;
}
.fancy-checkbox-label:hover > input:not(:checked) + .fancy-checkbox:before {
  color: #eee;
}
input:checked + .fancy-checkbox:before {
  color: #fff;
  background: #bdbdff;
  border-color: #bdbdff;
}
.fancy-checkbox-img:before {
  position: absolute;
  margin: 3px;
  line-height: normal;
}
input:checked + .fancy-checkbox-img + img {
  transform: scale(0.9);
  box-shadow: 0 0 5px #bdbdff;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" integrity="sha384-T8Gy5hrqNKT+hzMclPo118YTQO6cYprQmhrYwIiQ/3axmI1hQomh7Ud2hPOy8SP1" crossorigin="anonymous">
<p>
  <label class="fancy-checkbox-label">
    <input type="checkbox">
    <span class="fancy-checkbox"></span>
    A normal checkbox
  </label>
</p>
<p>
  <label class="fancy-checkbox-label">
    <input type="checkbox">
    <span class="fancy-checkbox fancy-checkbox-img"></span>
    <img src="http://placehold.it/150x150">
  </label>
</p>


1

Ecco un breve esempio di selezione di un'immagine come una casella di controllo

Esempio aggiornato usando Knockout.js:

var imageModel = function() {
    this.chk = ko.observableArray();
};
ko.applyBindings(new imageModel());
    input[type=checkbox] {
        display:none;
      }
 
  input[type=checkbox] + label
   {
       display:inline-block;
        width:150px;
        height:150px;
        background:#FBDFDA;
        border:none;
   }
   
   input[type=checkbox]:checked + label
    {
        background:#CFCFCF;
        border:none;
        position:relative;
        width:100px;
        height:100px;
        padding: 20px;
    }

   input[type=checkbox]:checked + label:after
    {
        content: '\2713';
        position:absolute;
        top:-10px;
        right:-10px;
        border-radius: 10px;
        width: 25px;
        height: 25px;
        border-color: white;
        background-color: blue;
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<input type='checkbox' name='image1' value='image1' id="image1" data-bind="checked: chk"/><label for="image1"></label><label for="image1"><img class='testbtn'/></label>

<div data-bind="html: chk"></div>


1
Mentre mi piace il tuo approccio, sarebbe utile per la maggior parte affermare che stai usando Knockout.js nel tuo esempio.
connexo,

@connexo Cheers, appena aggiornato per dire esempio usando Knockout.js
YaBCK

0

Espandere la risposta accettata per chiunque utilizzi WordPress e GravityForms per generare i propri moduli e desiderare popolare automaticamente i campi della casella di controllo con un elenco di post e le miniature in primo piano associate

// Change '2' to your form ID
add_filter( 'gform_pre_render_2', 'populate_checkbox' );
add_filter( 'gform_pre_validation_2', 'populate_checkbox' );
add_filter( 'gform_pre_submission_filter_2', 'populate_checkbox' );
add_filter( 'gform_admin_pre_render_2', 'populate_checkbox' );

function populate_checkbox( $form ) {

    foreach( $form['fields'] as &$field )  {

        // Change '41' to your checkbox field ID
        $field_id = 41;
        if ( $field->id != $field_id ) {
            continue;
        }

        // Adjust $args for your post type
        $args = array(
                'post_type' => 'pet',
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'tax_query' => array(
                        array(
                                'taxonomy' => 'pet_category',
                                'field' => 'slug',
                                'terms' => 'cat'
                        )
                )
        );

        $posts = get_posts( $args );

        $input_id = 1;

        foreach( $posts as $post ) {

            $feat_image_url = wp_get_attachment_image( get_post_thumbnail_id( $post->ID ), 'thumbnail' );
            $feat_image_url .= '<br />' . $post->post_title;

            if ( $input_id % 10 == 0 ) {
                $input_id++;
            }

            $choices[] = array( 'text' => $feat_image_url, 'value' => $post->post_title );
            $inputs[] = array( 'label' => $post->post_title, 'id' => "{$field_id}.{$input_id}" );

            $input_id++;
        }

        $field->choices = $choices;
        $field->inputs = $inputs;

    }

    return $form;
}

E il CSS:

.gform_wrapper .gfield_checkbox li[class^="gchoice_2_41_"] {
    display: inline-block;
}

.gform_wrapper .gfield_checkbox li input[type="checkbox"][id^="choice_2_41_"] {
    display: none;
}


.gform_wrapper .gfield_checkbox li label[id^="label_2_41_"] {
    border: 1px solid #fff;
    padding: 10px;
    display: block;
    position: relative;
    margin: 10px;
    cursor: pointer;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

label[id^="label_2_41_"]:before {
    font-family: "font-icons";
    font-size: 32px;
    color: #1abc9c;
    content: " ";
    display: block;
    background-color: transparent;
    position: absolute;
    top: -5px;
    left: -5px;
    width: 25px;
    height: 25px;
    text-align: center;
    line-height: 28px;
    transition-duration: 0.4s;
    transform: scale(0);
}

label[id^="label_2_41_"] img {
    transition-duration: 0.2s;
    transform-origin: 50% 50%;
}

:checked + label[id^="label_2_41_"] {
    border-color: #ddd;
}

/* FontAwesome tick */
:checked + label[id^="label_2_41_"]:before {
    content: "\e6c8";
    background-color: transparent;
    transform: scale(1);
}

:checked + label[id^="label_2_41_"] img {
    transform: scale(0.9);
    box-shadow: 0 0 5px #333;
    z-index: 0;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.