Используйте изображения, такие как флажки

165

Я хотел бы иметь альтернативу стандартному флажку - в основном я хотел бы использовать изображения и когда пользователь щелкает изображение, затемняет его и накладывает флажок.

По сути, я хочу сделать что-то похожее на Recaptcha 2, когда он заставляет вас нажимать на изображения, которые соответствуют определенным критериям. Вы можете увидеть демо Recaptcha здесь, но это может иногда заставить вас решать текстовые вопросы, в отличие от выбора изображения. Итак, вот скриншот:

Скриншот Google Recaptcha

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

Допустим, я хочу воспроизвести этот точный пример.

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

bgs264
источник
2
Вы можете иметь два одинаковых изображения: одно с галочкой, а другое без галочки. И меняйте изображения по клику
Алекс
23
@ Алекс Это было бы особенно негибким решением.
Сигуза
2
Вы пытались добавить / удалить CSS-класс по щелчку, который переопределяет размер изображения и делает некоторую :beforeмагию для изображения галочки?
Гексаголик
3
@ Алекс «Негибкий» в том смысле, что для изменения чего-либо потребовалось бы гораздо больше работы, например, добавление нового изображения в коллекцию или изменение значка «помечено», если этого не произойдет, если эффект создается программно в во время выполнения.
Сигуза
2
@Christian Замена флажков на что-то нестандартное является популярным дизайнерским решением (даже если это просто стилизованный флажок), а поиск хороших / простых способов сделать это, безусловно, представляет интерес для разработчиков, которым приходилось сталкиваться с этим. И этот вопрос (наложение замены флажка на что-то другое) определенно делает его интересным. В частности, обратите внимание , как принятый ответ не использует JS на всех, несмотря на кажущуюся сложность задачи
Izkata

Ответы:

309

Чисто семантическое решение HTML / CSS

Это легко реализовать самостоятельно, заранее не требуется готовое решение. Кроме того, это многому вас научит, так как вам не слишком легко работать с CSS.

Это то, что вам нужно сделать:

Ваши флажки должны иметь различные idатрибуты. Это позволяет вам подключиться <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);
}

В последнем сложном шаге вы используете :checkedпсевдо-селектор CSS , чтобы изменить изображение, когда флажок установлен:

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

+( Смежный селектор родственный ) гарантирует , что вы изменить только метки , которые непосредственно следуют скрытый флажок в разметке.

Вы можете оптимизировать это, помещая оба изображения в карту спрайта и применяя только изменение background-positionвместо замены изображения.

Конечно, вам нужно правильно расположить этикетку и применить display: block;и установить правильно widthи height.

Редактировать:

В примере с фрагментом кода и фрагменте кода, которые я создал после этих инструкций, используется та же методика, но вместо использования изображений для флажков, замены флажков выполняются исключительно с помощью 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>

connexo
источник
32
Рад, что вам это нравится! Начните возиться с CSS больше, это очень весело, и CSS может сделать намного больше, чем вы могли бы ожидать (кроме вертикального центрирования, это слишком сложно;)).
Connexo
1
Да, и понимание того, как это работает, заставит вас думать в будущем, каждый раз, когда вы захотите выполнить какое-нибудь действие DOM. И вы думали, что можете реагировать только на :hover:)
Connexo
Это будет моей следующей вещью, которую я буду смотреть на Pluralsight - некоторые вещи CSS :)
bgs264
6
Это очень мило! Я заметил небольшую проблему, когда вы дважды нажимаете на одну и ту же метку, она выбирает изображение. Это исправляет это: codepen.io/anon/pen/jPmNjg
Айеш К
1
Тик выглядел бы лучше, чем SVG. Контент CSS ставит вас в зависимость от ужасных системных шрифтов.
Адрия
31

Чистое решение CSS

Вызваны три аккуратных устройства:

  1. :checkedселектор
  2. ::beforeПсевдо-селектор
  3. Свойство CSS content.

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
источник
Как можно добавить поведение переключателя для этих флажков? Я имею в виду, когда вы нажимаете на изображение, уже выбранное изображение отменяется.
Либертад
Тот, кто задает себе тот же вопрос, что и @Libertad, просто меняет тип ввода на радио и присваивает им одно и то же имя «атрибут», а <input type="radio" name="myRadio" id="myRadio1" />также меняет свой css, чтобы скрыть маркер:input[type=radio]{display: none;}
Лу
8

Посмотрите этот плагин jQuery: imgCheckbox (на npm и bower )

Отказ от ответственности: Javascript не требуется для решения этой проблемы. Разрыв между ремонтопригодностью и эффективностью кода. Хотя нет необходимости в плагине (или любом javascript), он, безусловно, ускоряет его сборку и часто облегчает его изменение.

Barebones Решение:

С очень простым HTML (без всяких проблем с флажками, метками и т. Д.):

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

Вы можете использовать toQuClass класса jQuery, чтобы включить или выключить класс selectedили событие:checkedclick

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

Проверенные элементы выбираются с

$(".checked")

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

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

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

Это делает ваш HTML действительно чистым и невероятно читаемым. Посмотрите на фрагмент ...

Используя плагин imgCheckbox jQuery:

Вдохновленный решением выше, я создал плагин, который можно использовать так же легко, как:

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

Посмотрите это в действиипосмотрите источник )

jcuenod
источник
Мне также нравится этот подход, но у него есть ряд недостатков, о которых стоит упомянуть, самый большой из которых заключается в следующем: если предположить, что пользователь должен выбирать изображения, то информация, предоставленная пользователем таким образом, безусловно, должна как-то обрабатываться, будь то это через вызов AJAX или через форму отправки. Для целей дальнейшей обработки информации, предоставленной пользователем, наличие флажков, в которых должен быть отражен и обработан ряд вариантов, является просто естественным, семантическим способом сделать это.
Connexo
Это правда, это в моем списке задач для плагина - захватить отправку формы и вставить данные в форму. Но вы правы, флажки являются семантическими для форм
jcuenod
Я попытался использовать ваш плагин, но если я добавляю больше изображений после инициализации, то, похоже, нет способа уничтожить предыдущий экземпляр, чтобы можно было включить новые изображения
Ян Ким,
@IanKim интересный пример использования, не могли бы вы подробнее рассказать о том, что вы пытаетесь сделать в проблеме на github? github.com/jcuenod/imgCheckbox
jcuenod
Это потрясающий плагин! пожалуйста, опубликуйте Webjar =)
naXa
6

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

Теперь вы можете прослушать clickсобытие:

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

Таким образом, вы можете получить значок, а также изменить размер изображения в меньшую сторону.

Обратите внимание: я просто хотел показать вам «логику» моих мыслей, этот пример может не работать или в нем есть ошибки.

Кагатай Улубай
источник
Техника, которую я продемонстрировал, настолько проста и надежна, что даже часто применяется в ситуациях, когда у вас нет семантических флажков, например, переключение отображения других элементов и тому подобное. Это тот случай, когда это не только самое простое и гибкое решение, но и семантически лучшее.
Connexo
2
Да, ты прав. Сначала я хотел указать на ваш первый ответ и улучшить его (до редактирования), потому что мне нравятся No-JS и хорошие семантические способы, но потом я прочитал, что OP хочет чего-то в 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>

rybo111
источник
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>

YaBCK
источник
1
Хотя мне нравится ваш подход, для большинства было бы полезно заявить, что вы используете Knockout.js в своем примере.
Connexo
@connexo Cheers, только что обновлен, чтобы привести пример, используя Knockout.js
YaBCK
0

Чтобы расширить принятый ответ для тех, кто использует WordPress & GravityForms для создания своих форм и хочет автоматически заполнить поля флажков списком сообщений и связанных с ними избранных миниатюр

// 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;
}
essexboyracer
источник