web-dev-qa-db-fra.com

Utilisez des images comme des cases à cocher

J'aimerais avoir une alternative à une case à cocher standard. En gros, j'aimerais utiliser des images. Lorsque l'utilisateur clique sur l'image, la fait fondre et la superpose.

En gros, je veux faire quelque chose comme Recaptcha 2 quand il vous permet de cliquer sur des images qui répondent à certains critères. Vous pouvez voir une démonstration de Recaptcha ici mais cela peut parfois vous amener à résoudre des questions de texte, par opposition à la sélection d'images. Alors, voici une capture d'écran:

Google Recaptcha screenshot

Lorsque vous cliquez sur l'une des images (dans ce cas, contenant une image de steak), la taille de l'image sur laquelle vous cliquez est réduite et la coche bleue apparaît, indiquant que vous l'avez cochée.

Disons que je veux reproduire cet exemple exact.

Je me rends compte que je peux avoir 9 cases à cocher cachées et attacher un peu de jQuery afin que lorsque je clique sur l'image, elle sélectionne/désélectionne la case à cocher masquée. Mais qu'en est-il de la réduction de l'image/superposition de la tique?

154
bgs264

Solution sémantique HTML/CSS

C’est simple à mettre en œuvre, aucune solution préconçue n’est nécessaire. En outre, il vous en apprendra beaucoup car vous ne semblez pas très facile avec CSS. 

Voici ce que vous devez faire:

Vos cases à cocher doivent avoir des attributs id distincts. Cela vous permet de connecter un <label> à l'aide de l'attribut for- de l'étiquette.

Exemple:

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

Si vous associez l’étiquette à la case à cocher, le navigateur se comportera de la manière suivante: chaque fois que quelqu'un cliquera sur l’étiquette (ou sur l’image qu’elle contient), la case à cocher sera cochée.

Ensuite, vous masquez la case en y appliquant par exemple display: none;.

Il ne vous reste plus qu'à définir le style souhaité pour votre pseudo-élément label::before (qui sera utilisé comme élément de remplacement visuel de case à cocher):

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

Dans une dernière étape délicate, vous utilisez le pseudo-sélecteur :checked de CSS pour changer l'image lorsque la case à cocher est cochée:

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

Le + (sélecteur de fratrie adjacent) garantit que vous ne modifiez que les étiquettes qui suivent directement la case à cocher masquée dans la balise.

Vous pouvez optimiser cela en plaçant les deux images dans un spritemap et en appliquant uniquement une modification de background-position au lieu de permuter l'image.

Bien sûr, vous devez positionner correctement l'étiquette, appliquer display: block; et définir les correctes width et height.

Modifier:

L'exemple de code et le fragment, que j'ai créés après ces instructions, utilisent la même technique, mais au lieu d'utiliser des images pour les cases à cocher, les remplacements de cases à cocher sont effectués uniquement avec CSS, créant un ::before sur l'étiquette qui, une fois cochée , a content: "✓";. Ajoutez des bordures arrondies et des transitions douces et le résultat est vraiment sympathique!

Voici un codepen fonctionnel qui présente la technique et ne nécessite pas d'images pour la case à cocher:

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

Voici le même code dans un extrait:

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="http://lorempixel.com/100/100" /></label>
  </li>
  <li><input type="checkbox" id="cb2" />
    <label for="cb2"><img src="http://lorempixel.com/101/101" /></label>
  </li>
  <li><input type="checkbox" id="cb3" />
    <label for="cb3"><img src="http://lorempixel.com/102/102" /></label>
  </li>
  <li><input type="checkbox" id="cb4" />
    <label for="cb4"><img src="http://lorempixel.com/103/103" /></label>
  </li>
</ul>

278
connexo

Solution Pure CSS

Il existe trois périphériques ordonnés invoqués:

  1. Le :checked selector
  2. Le ::before pseudo-sélecteur
  3. Le css content property.

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>

28
jcuenod

Voir ce plugin jQuery: imgCheckbox (sur npm et bower)

Déni de responsabilité: Aucun javascript n'est nécessaire pour résoudre ce problème. La tension est entre maintenabilité et efficacité du code. Bien qu'il n'y ait pas besoin de plugin (ni de javascript), cela rend la création plus rapide et souvent plus facile à modifier.

Solution Barebones:

Avec très simple HTML (aucun problème avec les cases à cocher, les étiquettes, etc.):

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

Vous pouvez utiliser toggleClass de jQuery pour activer/désactiver une classe selected ou checked sur l'événement click:

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

Les articles cochés sont récupérés avec

$(".checked")

Plus de fraîcheur:

Vous pouvez styliser les images à partir de cela, mais un gros problème est que sans autres éléments DOM, vous ne pouvez même pas utiliser ::before et ::after pour ajouter des éléments tels que des coches. La solution consiste à envelopper vos images avec un autre élément (et il est également logique d'attacher l'auditeur de clic à l'élément enveloppé).

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

Cela laisse votre code HTML vraiment propre et votre texte incroyablement lisible. Jetez un coup d'œil à l'extrait ...

/* Note that this js actually responds
   to a click event on the wrapped element!
   (not the image) */
$("img.checkable").wrap("<span class='fancychecks'>")
  .parent().click(function() {
    $(this).toggleClass("checked");
  });
/* style the images */
span.fancychecks img {
  display: block;
  margin: 0;
  padding: 0;
  transition-duration: 300ms;
  transform: scale(1);
  filter: none;
  -webkit-filter: grayscale(0);
}
span.fancychecks.checked img {
  transform: scale(0.8);
  filter: gray;
  filter: grayscale(1);
  -webkit-filter: grayscale(1);
}

/* style the parent spans */
span.fancychecks {
  padding: 0;
  margin: 5px;
  display: inline-block;
  border: 1px solid transparent;
  transition-duration: 300ms;
}
span.fancychecks.checked {
  border-color: #ccc;
}

/* Using conexo's fantastic CSS, make the checkmarks */
span.fancychecks::before {
  background-color: rgba(50, 200, 50, 0.7);
  color: white;
  content: "✓";
  font-weight: bold;
  border-radius: 50%;
  position: absolute;
  margin: 2px;
  top: 1;
  left: 1;
  z-index: 1;
  width: 25px;
  height: 25px;
  text-align: center;
  line-height: 28px;
  transform: scale(0);
  transition-duration: 300ms;
}
span.fancychecks.checked::before {
  transform: scale(1);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<img class="checkable" src="http://lorempixel.com/100/100/city/1" />
<img class="checkable" src="http://lorempixel.com/100/100/city/2" />
<img class="checkable" src="http://lorempixel.com/100/100/city/3" />

Utilisation du plugin imgCheckbox jQuery:

Inspiré par la solution ci-dessus, j'ai construit un plugin qui peut être utilisé aussi facilement que:

$("img").imgCheckbox();
  • Injecte les données pour les images vérifiées dans votre formulaire
  • Prend en charge les coches personnalisées
  • Prend en charge les CSS personnalisés
  • Prend en charge les éléments présélectionnés
  • Prend en charge les groupes radio au lieu du simple basculement d'images
  • A des rappels d'événements
  • Valeurs par défaut sensibles
  • Léger et super facile à utiliser

Voir en action (et voir la source )

8
jcuenod

J'ajouterais un div supplémentaire avec position: relative; et class="checked" qui a la même largeur/hauteur que l'image et la position dans left: 0; top: 0; contenant l'icône. Cela commence par display: none;.

Maintenant, vous pouvez écouter l'événement click-:

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

De cette façon, vous pouvez obtenir l'icône et redimensionner l'image en plus petit.

Remarque: je voulais juste vous montrer la "logique" qui se cache derrière mes pensées, cet exemple pourrait ne pas fonctionner ou contenir des bugs.

6
Cagatay Ulubay

Voici un exemple rapide de sélection d'une image comme une case à cocher

Exemple mis à jour à l'aide de 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>

2
Chris Beckett

J'ai remarqué que d'autres réponses n'utilisaient pas <label> (pourquoi pas?) Ou exigeaient des attributs for et id correspondants. Cela signifie que si vous avez des identifiants en conflit, votre code ne fonctionnera pas et vous devez vous rappeler de créer des identifiants uniques à chaque fois.

De même, si vous masquez la variable input avec display:none ou visibility:hidden, le navigateur ne se concentrera pas dessus.

Une case à cocher et son texte (ou dans ce cas, une image) peuvent être enveloppés dans une étiquette:

.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>

2
rybo111

Pour développer la réponse acceptée par toute personne utilisant WordPress et GravityForms afin de générer leurs formulaires et souhaitant renseigner automatiquement les champs de case à cocher avec une liste de publications et leur Vignette en vedette associée 

// 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;
}

Et le 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;
}
0
essexboyracer