Sử dụng hình ảnh như hộp kiểm


164

Tôi muốn có một giải pháp thay thế cho hộp kiểm tiêu chuẩn - về cơ bản tôi muốn sử dụng hình ảnh và khi người dùng nhấp vào hình ảnh, hãy làm mờ nó ra và phủ lên một ô đánh dấu.

Về bản chất, tôi muốn làm một cái gì đó giống như Recaptcha 2 khi bạn nhấp vào hình ảnh đáp ứng một tiêu chí nhất định. Bạn có thể xem bản demo Recaptcha tại đây nhưng đôi khi có thể giúp bạn giải quyết các câu hỏi bằng văn bản, trái ngược với lựa chọn hình ảnh. Vì vậy, đây là một ảnh chụp màn hình:

Ảnh chụp màn hình Google Recaptcha

Khi bạn nhấp vào một trong các hình ảnh (trong trường hợp này, có chứa hình ảnh bít tết), hình ảnh bạn nhấp thu nhỏ kích thước và dấu tick màu xanh xuất hiện, cho biết bạn đã đánh dấu nó.

Hãy nói rằng tôi muốn tái tạo ví dụ chính xác này.

Tôi nhận ra rằng tôi có thể có 9 hộp kiểm ẩn và đính kèm một số jQuery để khi tôi nhấp vào hình ảnh, nó sẽ chọn / bỏ chọn hộp kiểm ẩn. Nhưng những gì về sự thu hẹp của hình ảnh / lớp phủ đánh dấu?


2
bạn có thể có hai hình ảnh giống hệt nhau: một hình có dấu và hình kia không có dấu. Và thay đổi hình ảnh khi nhấp
Alex

22
@Alex Đó sẽ là một giải pháp đặc biệt khó tin.
Siguza

2
Bạn đã thử thêm / xóa một lớp CSS khi nhấp vào ghi đè kích thước hình ảnh và có :beforephép thuật nào cho hình ảnh đánh dấu không?
Hexaholic

3
@Alex "Không thể phản hồi" theo nghĩa là nó sẽ đòi hỏi nhiều công việc hơn để thay đổi bất cứ điều gì, như thêm một hình ảnh mới vào bộ sưu tập hoặc thay đổi biểu tượng "đánh dấu", khi điều này sẽ không xảy ra nếu hiệu ứng được tạo ra theo cách lập trình tại thời gian chạy.
Siguza

2
@Christian Thay thế các hộp kiểm bằng một cái gì đó tùy chỉnh là một quyết định thiết kế phổ biến (ngay cả khi đó chỉ là một hộp kiểm có kiểu dáng) và việc tìm ra những cách tốt / đơn giản để làm điều đó chắc chắn là điều đáng quan tâm đối với các nhà phát triển đã phải đối phó với nó. Và câu hỏi này (phủ lên hộp thay thế trên một cái gì đó khác) chắc chắn làm cho nó trở thành một câu hỏi thú vị. Cụ thể, lưu ý cách câu trả lời được chấp nhận hoàn toàn không sử dụng JS, mặc dù sự phức tạp rõ ràng của nhiệm vụ
Izkata

Câu trả lời:


308

Giải pháp HTML / CSS ngữ nghĩa thuần túy

Điều này là dễ dàng để tự thực hiện, không cần giải pháp làm sẵn. Ngoài ra, nó sẽ dạy cho bạn rất nhiều vì bạn dường như không quá dễ dàng với CSS.

Đây là những gì bạn cần làm:

Các hộp kiểm của bạn cần phải có các idthuộc tính riêng biệt . Điều này cho phép bạn kết nối <label>với nó, bằng cách sử dụng phân phối của nhãn for.

Thí dụ:

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

Gắn nhãn vào hộp kiểm sẽ kích hoạt hành vi của trình duyệt: Bất cứ khi nào ai đó nhấp vào nhãn (hoặc hình ảnh bên trong nhãn), hộp kiểm sẽ được bật.

Tiếp theo, bạn ẩn hộp kiểm bằng cách áp dụng ví dụ display: none;cho nó.

Bây giờ, tất cả những gì còn lại phải làm là đặt kiểu bạn muốn cho label::beforephần tử giả (sẽ được sử dụng làm phần tử thay thế hộp kiểm trực quan):

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

Trong bước khó khăn cuối cùng, bạn sử dụng :checkedbộ chọn giả CSS để thay đổi hình ảnh khi hộp kiểm được chọn:

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

Các +( liền kề anh chị em chọn ) đảm bảo bạn chỉ thay đổi nhãn trực tiếp theo các hộp kiểm ẩn trong đánh dấu.

Bạn có thể tối ưu hóa điều đó bằng cách đặt cả hai hình ảnh vào một spritemap và chỉ áp dụng thay đổi background-positionthay vì hoán đổi hình ảnh.

Tất nhiên bạn cần định vị nhãn chính xác và áp dụng display: block;và đặt chính xác widthheight.

Biên tập:

Ví dụ và đoạn mã, mà tôi đã tạo sau các hướng dẫn này, sử dụng cùng một kỹ thuật, nhưng thay vì sử dụng hình ảnh cho các hộp kiểm, việc thay thế hộp kiểm được thực hiện hoàn toàn bằng CSS , tạo ::beforenhãn trên nhãn, sau khi được chọn, đã được kiểm tra content: "✓";. Thêm một số đường viền tròn và chuyển tiếp ngọt ngào và kết quả là thực sự thích!

Dưới đây là một codepen hoạt động thể hiện kỹ thuật và không yêu cầu hình ảnh cho hộp kiểm:

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

Đây là cùng một mã trong một đoạn:

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
Vui vì bạn thích nó! Bắt đầu loay hoay với CSS nhiều hơn, thật thú vị và CSS có thể làm được nhiều hơn những gì bạn có thể mong đợi (ngoại trừ việc định tâm dọc, điều đó quá khó;)).
Connexo

1
Vâng, và hiểu cách nó hoạt động sẽ khiến bạn suy nghĩ trong tương lai, mỗi khi bạn muốn một số hành động DOM khi nhấp chuột. Và bạn nghĩ rằng bạn chỉ có thể phản ứng với :hover:)
Connexo

Đó sẽ là điều tiếp theo của tôi để xem trên Pluralsight - một số nội dung CSS :)
bss264

6
Điều này là rất tốt đẹp! Tôi nhận thấy một vấn đề nhỏ khi bạn nhấp vào cùng một nhãn hai lần, nó chọn hình ảnh. Điều này sửa nó: codepen.io/anon/pen/jPmNjg
Ayesh K

1
Tick ​​sẽ có vẻ tốt hơn như SVG. Nội dung CSS khiến bạn phải chịu một số phông chữ hệ thống khủng khiếp.
Adria

31

Giải pháp CSS thuần túy

Có ba thiết bị gọn gàng được gọi:

  1. Bộ :checkedchọn
  2. Bộ ::beforechọn giả
  3. Các contenttài sản 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>


Làm thế nào có thể thêm một hành vi nút radio vào các hộp kiểm này? Ý tôi là khi bạn bấm vào một hình ảnh thì hình ảnh đã chọn sẽ bị bỏ chọn.
Libertad

Bất cứ ai tự hỏi mình câu hỏi tương tự như @Libertad chỉ cần thay đổi loại đầu vào thành radio và đặt cho họ tất cả cùng tên "thuộc tính" <input type="radio" name="myRadio" id="myRadio1" />cũng thay đổi css của bạn để ẩn dấu đầu dòng:input[type=radio]{display: none;}
Lou

8

Xem plugin jQuery này: imgCheckbox (trên npmbower )

Tuyên bố miễn trừ trách nhiệm: Không cần javascript để giải quyết vấn đề này. Sự căng thẳng là giữa khả năng duy trì và hiệu quả của mã. Mặc dù không cần plugin (hoặc bất kỳ javascript nào), nhưng nó chắc chắn sẽ giúp xây dựng nhanh hơn và thường dễ thay đổi hơn.

Giải pháp barebones:

Với HTML rất đơn giản (không có gì lộn xộn với các hộp kiểm và nhãn, v.v.):

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

Bạn có thể sử dụng toggleClass của jQuery để bật / tắt một selectedhoặc checkedlớp trong clicksự kiện:

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

Các mục đã kiểm tra được tìm nạp với

$(".checked")

Cộng với sự mát mẻ:

Bạn có thể định kiểu hình ảnh dựa trên điều này nhưng một vấn đề lớn là không có các yếu tố DOM khác, bạn thậm chí không thể sử dụng ::before::afterthêm các thứ như dấu kiểm. Giải pháp là bọc hình ảnh của bạn bằng một yếu tố khác (và thật hợp lý khi gắn trình nghe nhấp chuột vào thành phần được bao bọc).

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

Điều này làm cho html của bạn thực sự sạch sẽ và js của bạn cực kỳ dễ đọc. Hãy xem đoạn trích ...

Sử dụng Plugin imgCheckbox jQuery:

Lấy cảm hứng từ giải pháp trên, tôi đã xây dựng một plugin có thể được sử dụng dễ dàng như:

$("img").imgCheckbox();
  • Tiêm dữ liệu cho hình ảnh được kiểm tra vào mẫu của bạn
  • Hỗ trợ dấu kiểm tùy chỉnh
  • Hỗ trợ CSS tùy chỉnh
  • Hỗ trợ các yếu tố được chọn trước
  • Hỗ trợ các nhóm radio thay vì chuyển đổi hình ảnh đơn giản
  • Có cuộc gọi lại sự kiện
  • Mặc định hợp lý
  • Nhẹ và siêu dễ sử dụng

Xem nó trong hành động (và xem nguồn )


Tôi cũng thích cách tiếp cận này, nhưng nó có một số nhược điểm đáng nói, vấn đề lớn nhất là: Giả sử người dùng có nghĩa là chọn hình ảnh, thông tin được cung cấp bởi người dùng theo cách này chắc chắn sẽ được xử lý bằng cách nào đó, được nó thông qua một cuộc gọi AJAX hoặc thông qua một hình thức gửi. Đối với các ưu tiên của việc xử lý thêm thông tin do người dùng cung cấp, việc có các hộp kiểm trong đó một số lựa chọn phải được phản ánh và xử lý chỉ là cách làm tự nhiên, ngữ nghĩa.
Connexo

Đây là sự thật, nó nằm trong danh sách việc cần làm của tôi đối với plugin - để chiếm quyền điều khiển biểu mẫu và đưa dữ liệu vào biểu mẫu. Nhưng bạn đã đúng, các hộp kiểm là ngữ nghĩa cho các biểu mẫu
jcuenod

Tôi đã thử sử dụng plugin của bạn, nhưng nếu tôi thêm nhiều hình ảnh sau khi khởi tạo thì dường như không có cách nào để phá hủy phiên bản trước đó để có thể đưa vào các hình ảnh mới
Ian Kim

@IanKim trường hợp sử dụng thú vị, bạn có thể giải thích thêm về những gì bạn đang cố gắng thực hiện trong một vấn đề trên github không? github.com/jcuenod/imgCheckbox
jcuenod

Đó là một plugin tuyệt vời! vui lòng xuất bản một Webjar =)
naXa

6

Tôi sẽ nối thêm một div với position: relative;class="checked"có cùng chiều rộng / chiều cao như hình ảnh có và hơn vị trí left: 0; top: 0;chứa biểu tượng. Nó bắt đầu với display: none;.

Bây giờ bạn có thể nghe click-event:

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

Bằng cách này bạn có thể lấy biểu tượng và thay đổi kích thước hình ảnh theo cách nhỏ hơn.

Lưu ý: Chỉ muốn cho bạn thấy "logic" đằng sau suy nghĩ của tôi, ví dụ này có thể không hoạt động hoặc có một số lỗi trong đó.


Kỹ thuật tôi đã trình diễn rất đơn giản và mạnh mẽ, thậm chí nó thường được áp dụng trong các tình huống mà bạn không có bất kỳ hộp kiểm nào về mặt ngữ nghĩa, như bật tắt hiển thị các yếu tố khác và tương tự. Đây là usecase nơi nó không chỉ là giải pháp dễ nhất, linh hoạt nhất, mà còn là giải pháp tốt nhất về mặt ngữ nghĩa.
Connexo

2
Vâng bạn đã đúng. Lúc đầu tôi muốn chỉ ra câu trả lời đầu tiên của bạn và cải thiện nó (trước khi chỉnh sửa), vì tôi thích No-JS và các cách ngữ nghĩa hay, nhưng tôi đọc được rằng OP muốn một cái gì đó trong jQuery nên tôi đã thay đổi câu trả lời của mình. Tôi nhớ nơi tôi có một downvote, bởi vì OP không muốn một giải pháp "tốt hơn" hay "đúng cách", nhưng chính xác là cách anh ấy viết. Có lẽ có điều gì đó tôi đã đọc quá mức hoặc không hiểu hoặc nó phụ thuộc vào OP?
Cagatay Ulubay

2

Tôi đã nhận thấy các câu trả lời khác không sử dụng <label>(tại sao không?) Hoặc yêu cầu kết hợp foridthuộc tính. Điều này có nghĩa là nếu bạn có ID xung đột, mã của bạn sẽ không hoạt động và bạn phải nhớ tạo ID duy nhất mỗi lần.

Ngoài ra, nếu bạn ẩn inputbằng display:nonehoặc visibility:hidden, trình duyệt sẽ không tập trung vào nó.

Một hộp kiểm và văn bản của nó (hoặc trong trường hợp này, hình ảnh) có thể được bọc trong một nhãn:

.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

Dưới đây là một ví dụ nhanh về việc chọn một hình ảnh như một hộp kiểm

Ví dụ cập nhật bằng 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
Mặc dù tôi thích cách tiếp cận của bạn, nhưng nó sẽ hữu ích cho hầu hết để nói rằng bạn đang sử dụng Knockout.js trong ví dụ của bạn.
Connexo

@connexo Chúc mừng, vừa được cập nhật để nói ví dụ bằng Knockout.js
YaBCK

0

Để mở rộng câu trả lời được chấp nhận cho bất kỳ ai sử dụng WordPress & GravityForms để tạo biểu mẫu của họ và muốn tự động điền vào các trường hộp kiểm với danh sách các bài đăng và Hình thu nhỏ nổi bật được liên kết của họ

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

Và 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;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.