Використовуйте зображення, як прапорці


165

Я хотів би мати альтернативу стандартному прапорець - в основному я хотів би використовувати зображення, і коли користувач натискає зображення, вицвіть його і накладіть галочку.

По суті, я хочу зробити щось на зразок Recaptcha 2, коли змушує вас натискати зображення, що відповідають певним критеріям. Ви можете побачити демонстрацію Recaptcha тут, але іноді це може змусити вас вирішити текстові запитання на відміну від вибору зображення. Ось ось скріншот:

Скріншот Google Recaptcha

Коли ви клацаєте одне із зображень (в даному випадку містить зображення стейка), зображення, яке ви натискаєте, зменшується в розмірі і з’являється синя галочка, що вказує на те, що ви поставили його.

Скажімо, я хочу відтворити саме цей приклад.

Я розумію, що я можу мати 9 прихованих прапорців, і прикріплюю кілька jQuery, щоб після натискання на зображення він вибирав / знімав вибір прихованих прапорців. А як щодо зменшення зображення / накладання галочки?


2
у вас може бути два однакових зображення: одне з галочкою, а інше без галочки. І міняйте зображення на клік
Алекс

23
@Alex Це було б особливо негнучким рішенням.
Сигуза

2
Ви спробували додати / видалити клас CSS при натисканні, який переосмислює розмір зображення та робить якусь :beforeмагію для зображення галочки?
Гексаголік

3
@ Алекс "Негнучкий", в тому сенсі, що потрібно змінити щось, як-от додати нову картинку до колекції або змінити "галочку", якщо цього не буде, якщо ефект буде програмно створений на час виконання.
Сігуза

2
@Christian Заміна прапорців на щось на замовлення - це популярне дизайнерське рішення (навіть якщо це лише стилізований прапорець), а пошук хороших / простих способів зробити це, безумовно, цікавить чортів, яким довелося з цим боротися. І це питання (накладення заміни прапорця на щось інше), безумовно, робить його цікавим. Зокрема, зауважте, як прийнята відповідь взагалі не використовує JS, незважаючи на очевидну складність завдання
Ізката

Відповіді:


309

Чисте семантичне рішення HTML / CSS

Це легко здійснити самостійно, не потрібно заздалегідь прийняте рішення. Крім того, це навчить вас багато чому, оскільки вам не здається занадто простим із CSS.

Це те, що вам потрібно зробити:

У ваших прапорцях повинні бути чіткі idатрибути. Це дозволяє вам підключити a <label>до нього, використовуючи позначку for-attribute.

Приклад:

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

Прикріплення мітки до прапорця викликає поведінку веб-переглядача: Кожен раз, коли хтось натискає на мітку (або зображення всередині неї), цей прапорець буде змінено.

Далі ви ховаєте прапорець, застосувавши, наприклад, display: none;до нього.

Тепер все, що вам залишається зробити, це встановити потрібний вам стиль label::before псевдоелемента (який буде використовуватися як елементи візуальної заміни поля):

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

На останньому хитромудрому кроці ви використовуєте CSS ' :checked щоб змінити зображення, коли прапорець встановлений:

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

+( Суміжний селектор споріднений ) гарантує , що ви змінити тільки мітки , які безпосередньо випливають прихований прапорець в розмітці.

Ви можете оптимізувати це, розмістивши обидва зображення в спрайті та застосувавши лише зміни background-position замість заміни зображення.

Звичайно, ви повинні правильно розмістити етикетку та застосувати display: block;та встановити правильнуwidth та height.

Редагувати:

Приклад і фрагмент codepen, які я створив після цих інструкцій, використовують ту саму техніку, але замість використання зображень для прапорців, заміни прапорець здійснюються виключно CSS , створюючи ::beforeна етикетці, що після перевірки маєcontent: "✓"; . Додайте кілька закруглених меж і солодких переходів, і результат справді приємний!

Ось робочий коден, який демонструє техніку і не потребує зображень для прапорця:

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

Ось такий самий код у фрагменті:

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
Радий, що тобі подобається! Почніть більше обмінюватися з CSS, це дуже весело, і CSS може зробити набагато більше, ніж ви, можливо, коли-небудь очікували (крім вертикального центрування, це занадто складно;)).
коннексо

1
Так, і розуміння того, як це працює, змусить вас задуматися в майбутньому, кожного разу, коли ви хочете зробити якусь дію DOM при натисканні. І ти думав, що можеш реагувати лише на :hover:)
connexo

Це буде моє наступне, що слід подивитися на Pluralsight - деякі речі CSS :)
bgs264,

6
Це дуже приємно! Я помітив невелику проблему, коли два рази клацніть одну і ту ж мітку, вона вибирає зображення. Це виправляє: codepen.io/anon/pen/jPmNjg
Айеш К

1
Тик би виглядав краще як SVG. Вміст CSS надає вам перевагу у деяких жахливих системних шрифтах.
Адрія

31

Чистий CSS-розчин

Існує три акуратні пристрої:

  1. The :checkedселектор
  2. The ::beforeПсевдо-селектор
  3. contentВластивість 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>


Як можна додати поведінку перемикача до цих прапорців? Я маю на увазі, коли ви натискаєте на зображення, вже вибране зображення стає скасованим.
Лібертад

Той, хто задає собі те саме питання, що і @Libertad, просто змінить тип входів на радіо і дасть їм все те саме ім’я "атрибут", <input type="radio" name="myRadio" id="myRadio1" />також змінить ваш css, щоб приховати кулю:input[type=radio]{display: none;}
Лу

8

Перегляньте цей плагін jQuery: imgCheckboxnpm та bower )

Відмова від відповідальності: Для вирішення цієї проблеми не потрібен JavaScript. Напруженість полягає в ремонтопридатності та ефективності коду. Хоча плагін (чи будь-який JavaScript) не потребує, він, безумовно, робить його швидшим у створенні та часто простіше змінювати.

Рішення Barebones:

З дуже простим HTML (жоден з безладдя з прапорцями та мітками тощо):

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

Ви можете використовувати jQuery toggleClass для вмикання / вимкнення класу selectedабо checkedкласу clickподії:

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

Перевірені елементи витягнуті

$(".checked")

Плюс прохолода:

Ви можете стилізувати зображення, виходячи з цього, але велика проблема полягає в тому, що без інших елементів DOM ви навіть не можете використовувати ::beforeта ::afterдодавати такі речі, як галочки. Рішення полягає в тому, щоб обернути свої зображення іншим елементом (і має сенс приєднати слухач кліків до обгорнутого елемента).

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

Це залишає ваш html дійсно чистим, а ваш js неймовірно читабельним. Погляньте на фрагмент ...

Використання плагіна jguery imgCheckbox :

Натхненний рішенням вище, я створив плагін, який можна використовувати так просто, як:

$("img").imgCheckbox();
  • Вводить дані у перевірені зображення у вашу форму
  • Підтримує спеціальні галочки
  • Підтримує індивідуальний CSS
  • Підтримує попередньо обрані елементи
  • Підтримує радіогрупи замість простого перемикання зображень
  • Має зворотні виклики подій
  • Розумні дефолти
  • Легкий і супер простий у використанні

Дивіться це в діїдивіться джерело )


Мені також подобається такий підхід, але він має ряд недоліків, які варто згадати, найбільший з них такий: якщо припустити, що користувач має намір вибирати зображення, інформація, надана користувачем таким чином, неодмінно призначена для того, щоб якось обробити, будь це через дзвінок AJAX або через форму надсилання. Для цілей подальшої обробки інформації, наданої користувачем, встановлення прапорців, де необхідно відобразити та обробити низку варіантів, є лише природним, семантичним способом цього зробити.
коннексо

Це правда, це в моєму списку todo для плагіна - щоб викрасти подання форми та ввести дані у форму. Але ви праві, прапорці семантичні для форм
jcuenod

Я спробував використати ваш плагін, але якщо я додаю більше зображень після ініціалізації, схоже, не існує способу знищити попередній екземпляр, щоб нові зображення могли бути включені
Іан Кім

@IanKim цікавий випадок використання, чи можете ви пояснити більше того, що ви намагаєтесь зробити у випуску на Github? github.com/jcuenod/imgCheckbox
jcuenod

Це дивовижний плагін! опублікуйте, будь ласка, Webjar =)
naXa

6

Я хотів би додати додатковий DIV з position: relative;і class="checked"який має таку ж ширину / висоту , як зображення має і чим положення в left: 0; top: 0;містить значок. Це починається з display: none;.

Тепер ви можете слухати click-event:

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

Таким чином ви можете отримати піктограму, а також змінити розмір зображення в менший спосіб.

Зауважте: Просто хотів показати вам "логіку", що лежить в моїх думках, цей приклад може не працювати або в ньому є деякі помилки.


Я продемонстрував методику, настільки просту і надійну, що навіть часто застосовується в ситуаціях, коли у вас немає семантичних прапорців, як перемикання відображення інших елементів тощо. Це справа, де це не тільки найпростіше, гнучкіше рішення, але і семантично найкраще.
коннексо

2
Так, ви праві. Спочатку я хотів вказати на вашу першу відповідь і вдосконалити її (перед редагуванням), тому що мені подобається No-JS і приємні семантичні способи, але, ніж я читав, що ОП хоче щось у jQuery, тому я змінив свою відповідь. Я пам’ятаю, де я отримав протизаконну заяву, тому що ОП не хотіло рішення «кращого» чи «правильного шляху», але точно написав його. Можливо, є щось, що я перечитав або не зрозумів, або це залежить від ОП?
Cagatay Ulubay

2

Я помітив, що інші відповіді або не використовують <label>(чому ні?), Або вимагають відповідності forта idатрибутів. Це означає, що якщо у вас є збірні ідентифікатори, ваш код не працюватиме, і ви повинні пам’ятати, щоби робити унікальні ідентифікатори кожен раз.

Крім того, якщо ви ховаєте за inputдопомогою display:noneабо visibility:hidden, браузер не зосередиться на ньому.

Прапорець та його текст (або в цьому випадку зображення) можуть бути загорнуті в етикетку:

.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

Ось короткий приклад вибору зображення на зразок прапорця

Оновлений приклад за допомогою 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
Хоча мені подобається ваш підхід, для більшості було б корисно констатувати, що ви використовуєте Knockout.js у своєму прикладі.
коннексо

@connexo Ура, щойно оновлений для прикладу, використовуючи Knockout.js
YaBCK

0

Щоб розширити прийняту відповідь для всіх, хто використовує WordPress & GravityForms, щоб генерувати свої форми та бажати автоматично заповнити поля прапорців зі списком публікацій та пов’язаних із ними Featured Thumbnail

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

І 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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.