Usa imágenes como casillas de verificación

165

Me gustaría tener una alternativa a una casilla de verificación estándar, básicamente me gustaría usar imágenes y cuando el usuario hace clic en la imagen, la desvanece y superpone una casilla de verificación.

En esencia, quiero hacer algo como lo hace Recaptcha 2 cuando hace que hagas clic en imágenes que cumplen con ciertos criterios. Puede ver una demostración de Recaptcha aquí, pero a veces puede hacer que resuelva preguntas de texto, en lugar de la selección de imágenes. Así que aquí hay una captura de pantalla:

Captura de pantalla de Google Recaptcha

Cuando hace clic en una de las imágenes (en este caso, que contiene una imagen de filete), la imagen en la que hace clic se reduce de tamaño y aparece la marca azul, lo que indica que la ha marcado.

Digamos que quiero reproducir este ejemplo exacto.

Me doy cuenta de que puedo tener 9 casillas de verificación ocultas y adjunto algunos jQuery para que cuando haga clic en la imagen, seleccione / deseleccione la casilla de verificación oculta. Pero, ¿qué pasa con la reducción de la imagen / superposición de la marca?

bgs264
fuente
2
puede tener dos imágenes idénticas: una con tick y otra sin tick. Y cambie las imágenes al hacer clic
Alex
23
@Alex Esa sería una solución particularmente poco flexible.
Siguza
2
¿Has intentado agregar / eliminar una clase CSS al hacer clic que anula el tamaño de la imagen y hace algo de :beforemagia para la imagen de marca?
Hexaholic
3
@Alex "Unflexible" en el sentido de que requeriría mucho más trabajo cambiar cualquier cosa, como agregar una nueva imagen a la colección o cambiar el ícono "marcado", cuando este no sería el caso si el efecto se crea programáticamente en tiempo de ejecución
Siguza
2
@Christian Reemplazar casillas de verificación con algo personalizado es una decisión de diseño popular (incluso si es solo una casilla de verificación con estilo), y encontrar formas buenas / simples de hacerlo definitivamente es de interés para los desarrolladores que han tenido que lidiar con eso. Y esta pregunta (superponer el reemplazo de la casilla de verificación en otra cosa) definitivamente la hace interesante. En particular, observe cómo la respuesta aceptada no utiliza JS en absoluto, a pesar de la aparente complejidad de la tarea
Izkata

Respuestas:

309

Solución semántica pura de HTML / CSS

Esto es fácil de implementar por su cuenta, no se necesita una solución prefabricada. También te enseñará mucho, ya que no pareces demasiado fácil con CSS.

Esto es lo que necesitas hacer:

Sus casillas de verificación deben tener idatributos distintos . Esto le permite conectar un <label>a, utilizando el foratributo de la etiqueta .

Ejemplo:

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

Al adjuntar la etiqueta a la casilla de verificación, se activará el comportamiento del navegador: cada vez que alguien haga clic en la etiqueta (o en la imagen que contiene), se activará la casilla de verificación.

A continuación, oculta la casilla de verificación aplicándola, por ejemplo display: none;.

Ahora todo lo que queda por hacer es establecer el estilo que desea para su label::beforepseudo elemento (que se utilizará como elementos de reemplazo de la casilla de verificación visual):

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

En un último paso complicado, utiliza el :checkedpseudo selector de CSS para cambiar la imagen cuando la casilla de verificación está marcada:

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

El +( selector de hermanos adyacentes ) se asegura de que solo cambie las etiquetas que siguen directamente a la casilla de verificación oculta en el marcado.

Puede optimizar eso colocando ambas imágenes en un mapa de sprites y solo aplicando un cambio en background-positionlugar de intercambiar la imagen.

Por supuesto, debe colocar la etiqueta correctamente y aplicar display: block;y configurar correctamente widthy height.

Editar:

El ejemplo y el fragmento de código, que creé después de estas instrucciones, usan la misma técnica, pero en lugar de usar imágenes para las casillas de verificación, los reemplazos de las casillas de verificación se realizan únicamente con CSS , creando una ::beforeetiqueta que, una vez marcada, tiene content: "✓";. Agregue algunos bordes redondeados y transiciones dulces y el resultado es realmente agradable.

Aquí hay un código abierto que muestra la técnica y no requiere imágenes para la casilla de verificación:

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

Aquí está el mismo código en un fragmento:

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>

connexo
fuente
32
Me alegro de que te guste! Comience a jugar un poco más con CSS, es muy divertido y CSS puede hacer mucho más de lo que probablemente esperaría (excepto el centrado vertical, eso es demasiado difícil;)).
connexo
1
Sí, y comprender la forma en que funciona te hará pensar en el futuro, cada vez que quieras alguna acción DOM al hacer clic. Y pensaste que solo puedes reaccionar ante :hover:)
connexo
Ese será mi próximo paso para ver en Pluralsight - algunas cosas de CSS :)
bgs264
66
¡Esto esta muy bien! Noté un pequeño problema cuando haces clic en la misma etiqueta dos veces, selecciona la imagen. Esto lo arregla: codepen.io/anon/pen/jPmNjg
Ayesh K
1
Tick ​​se habría visto mejor como SVG. El contenido CSS lo pone a merced de algunas fuentes terribles del sistema.
Adria
31

Solución CSS pura

Se invocan tres dispositivos limpios:

  1. El :checkedselector
  2. El ::beforepseudo-selector
  3. La contentpropiedad 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>

jcuenod
fuente
¿Cómo es posible agregar un comportamiento de botón de radio a estas casillas de verificación? Quiero decir que cuando haces clic en una imagen, la imagen ya seleccionada se deselecciona.
Libertad
Quien se hace la misma pregunta que @Libertad simplemente cambia el tipo de entradas a la radio y les da a todos el mismo nombre "atributo" <input type="radio" name="myRadio" id="myRadio1" />también cambia su CSS para ocultar la viñeta:input[type=radio]{display: none;}
Lou
8

Ver este plugin jQuery: imgCheckbox (en NPM y Bower )

Descargo de responsabilidad: no se necesita JavaScript para resolver este problema. La tensión está entre la mantenibilidad y la eficiencia del código. Si bien no es necesario un complemento (o ningún javascript), seguro que lo hace más rápido de construir y, a menudo, más fácil de cambiar.

Solución Barebones:

Con HTML muy simple (ninguno de los problemas con casillas de verificación y etiquetas, etc.):

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

Puede utilizar jQuery toggleClass para activar / desactivar una selectedo checkedclase en el clickevento:

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

Los elementos marcados se obtienen con

$(".checked")

Más frescura:

Puede diseñar las imágenes basándose en esto, pero un gran problema es que sin otros elementos DOM ni siquiera puede usar ::beforey ::afteragregar cosas como marcas de verificación. La solución es envolver sus imágenes con otro elemento (y también tiene sentido adjuntar el detector de clics al elemento envuelto).

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

Esto deja su html realmente limpio y su js increíblemente legible. Echa un vistazo al fragmento ...

Usando el plugin imgCheckbox jQuery:

Inspirado por la solución anterior, he creado un complemento que se puede usar tan fácilmente como:

$("img").imgCheckbox();
  • Inyecta los datos de las imágenes marcadas en tu formulario
  • Admite marcas de verificación personalizadas
  • Admite CSS personalizado
  • Soporta elementos preseleccionados
  • Admite grupos de radio en lugar de alternar simples imágenes
  • Tiene devoluciones de llamada de eventos
  • Valores predeterminados sensibles
  • Ligero y súper fácil de usar.

Véalo en acción (y vea la fuente )

jcuenod
fuente
También me gusta este enfoque, pero tiene varias desventajas que vale la pena mencionar, la más importante es esta: suponiendo que el usuario esté destinado a elegir imágenes, la información dada por el usuario de esta manera seguramente debe procesarse de alguna manera, ser a través de una llamada AJAX o mediante un formulario de envío. Para los propósitos de un mayor procesamiento de la información dada por el usuario, tener casillas de verificación donde se deben reflejar y procesar una serie de opciones es solo la forma semántica y natural de hacerlo.
connexo
Esto es cierto, está en mi lista de tareas pendientes para el complemento: secuestrar el envío del formulario e inyectar los datos en el formulario. Pero tienes razón, las casillas de verificación son semánticas para los formularios
jcuenod
Intenté usar su complemento, pero si agrego más imágenes después de la inicialización, no parece haber una forma de destruir la instancia anterior para que se puedan incluir las nuevas imágenes
Ian Kim
Caso de uso interesante de @IanKim, ¿puede explicar más sobre lo que está tratando de hacer en un problema en github? github.com/jcuenod/imgCheckbox
jcuenod
¡Es un complemento increíble! publica un Webjar =)
naXa
6

Agregaría un div adicional con position: relative;y class="checked"que tiene el mismo ancho / alto que la imagen y que la posición que left: 0; top: 0;contiene el icono. Se inicia con display: none;.

Ahora puedes escuchar el clickevento:

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

De esta manera, puede obtener el icono y también cambiar el tamaño de la imagen a una forma más pequeña.

Aviso: Solo quería mostrarle la "lógica" detrás de mis pensamientos, este ejemplo podría no funcionar o tiene algunos errores.

Cagatay Ulubay
fuente
La técnica que demostré es tan simple y robusta que incluso se aplica a menudo en situaciones en las que no tiene ninguna casilla de verificación semántica, como alternar la visualización de otros elementos y similares. Este es el caso de uso donde no solo es la solución más fácil y flexible, sino también la mejor semánticamente.
connexo
2
Sí tienes razón. Al principio quería señalar su primera respuesta y mejorarla (antes de editar), porque me gusta No-JS y buenas formas semánticas, pero luego leí que el OP quiere algo en jQuery, así que cambié mi respuesta. Recuerdo dónde obtuve un voto negativo, porque el OP no quería una solución "mejor" o "correcta", sino la forma exacta en que escribió. ¿Tal vez hay algo que leí demasiado o no entendí o depende del OP?
Cagatay Ulubay
2

He notado que otras respuestas no usan <label>(¿por qué no?), O requieren coincidencias fory idatributos. Esto significa que si tiene identificaciones en conflicto, su código no funcionará y debe recordar hacer identificaciones únicas cada vez.

Además, si oculta inputcon display:noneo visibility:hidden, el navegador no se centrará en él.

Una casilla de verificación y su texto (o en este caso, imagen) se pueden envolver en una etiqueta:

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

rybo111
fuente
1

Aquí un ejemplo rápido de seleccionar una imagen como una casilla de verificación

Ejemplo actualizado 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>

YaBCK
fuente
1
Si bien me gusta su enfoque, sería útil para la mayoría decir que está utilizando Knockout.js en su ejemplo.
connexo
@connexo Cheers, recién actualizado para decir un ejemplo usando Knockout.js
YaBCK
0

Para ampliar la respuesta aceptada para cualquier persona que use WordPress y GravityForms para generar sus formularios y desee rellenar automáticamente los campos de casilla de verificación con una lista de publicaciones y su Miniatura destacada asociada

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

Y el 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;
}
essexboyracer
fuente