Как изменить стиль чекбокса

В этой статье подробно разберём процесс кастомной стилизации чекбоксов и радиокнопок с помощью CSS.

В этой статье подробно разберём процесс кастомной стилизации чекбоксов и радиокнопок с помощью CSS.

Как осуществляется создание кастомного чекбокса или переключателя

Данный процесс осуществляется посредством скрытия стандартного элемента и создания с помощью CSS другого «поддельного», такого как мы хотим.

Но как же это будет работать, если стандартный input скрыть? Это можно выполнить благодаря тому, что в HTML переключить состояние checked можно не только с помощью самого элемента input, но и посредством связанного с ним label.

В HTML связывание label с input выполняется одним из 2 способов:

1. Посредством помещения элемента input в label:

<label>
  <input type="checkbox" name="happy" value="yes">Happy
</label>

2. Посредством задания элементу input атрибута id, а labelfor с таким же значением как у id.

<input type="checkbox" id="happy" name="happy" value="yes">
<label for="happy">Happy</label>

В этой статье мы подробно разберём шаги по кастомизации checkbox и radio, в которых label с input свяжем по 2 варианту. Создание «поддельного» чекбокса выполним с использованием псевдоэлемента ::before, который поместим в label. При этом никакие дополнительные элементы в разметку добавлять не будем.

Создание стильного чекбокса

Процесс замены стандартного вида чекбокса на кастомный осуществим посредством выполнения следующей последовательности шагов.

Шаг 1. Создадим разметку.

<input type="checkbox" class="custom-checkbox" id="happy" name="happy" value="yes">
<label for="happy">Happy</label>

При создании разметки очень важно соблюдать последовательность расположения элементов. Это необходимо, потому что в зависимости от того, как они расположены мы будем составлять выражения для выбора элементов в CSS и назначать им стили.

В этом примере элемент label расположен после input. Связь label с input осуществляется посредством соответствия значения for элемента label с id элемента input.

В примере к элементу input добавлен класс custom-checkbox. Данный класс мы будем использовать при составлении селекторов и тем самым с помощью него определять элементы к которым следует добавить стилизованный чекбокс вместо обычного. Т.е. его присутствие или отсутствие будет определять с каким чекбоксом (со стандартным или поддельным) будет выводится элемент input с type="checkbox".

Вид чекбокса в браузере по умолчанию

Шаг 2. Напишем стили для скрытия стандартного элемента input.

Вид чекбокса после скрытия

.custom-checkbox {
  position: absolute;
  z-index: -1;
  opacity: 0;
}

Мы не будем использовать display: none, а установим ему стили, с помощью которых уберём его из потока (position: absolute), поместим его ниже существующих элементов (z-index: -1), а также сделаем его полностью прозрачным (opacity: 0). Зачем это нужно? Это нам необходимо для того, чтобы мы могли получить состояние фокуса, а затем стилизовать «подделный» checkbox или radio, когда он будет находиться в нём.

Шаг 3. Создадим поддельный чекбокс.

Вид кастомного чекбокса

.custom-checkbox+label {
  display: inline-flex;
  align-items: center;
  user-select: none;
}
.custom-checkbox+label::before {
  content: '';
  display: inline-block;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  flex-grow: 0;
  border: 1px solid #adb5bd;
  border-radius: 0.25em;
  margin-right: 0.5em;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 50% 50%;
}

Создание «поддельного» чекбокса выполним с помощью псевдоэлемента ::before. Посредством CSS зададим ему размеры (в данном случае 1emx1em), а затем нарисуем его с помощью border: 1px solid #adb5bd. Свойства начинающие со слова background будут определять положение самого флажка (когда checkbox будет в состоянии checked).

Первое правило необходимо для вертикального центрирования флажка и надписи к нему. Это действие в примере выполнено через CSS Flexbox.

Шаг 4. Создадим стили при нахождении элемента в состоянии checked.

Вид стилизованного чекбокса в состоянии checked

.custom-checkbox:checked+label::before {
  border-color: #0b76ef;
  background-color: #0b76ef;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
}

В этом коде при получении элементом состояния checked применим к псевдоэлементу ::before находящемуся в label стили, посредством которых установим цвет границы, цвет фону и фоновую картинку (флажок) в формате svg.

Шаг 5. Добавим код для стилизации чекбокса при нахождении его в состояниях hover, active, focus и disabled.

Вид кастомного чекбокса в состояниях hover, active, focus и disabled

/* стили при наведении курсора на checkbox */
.custom-checkbox:not(:disabled):not(:checked)+label:hover::before {
  border-color: #b3d7ff;
}
/* стили для активного состояния чекбокса (при нажатии на него) */
.custom-checkbox:not(:disabled):active+label::before {
  background-color: #b3d7ff;
  border-color: #b3d7ff;
}
/* стили для чекбокса, находящегося в фокусе */
.custom-checkbox:focus+label::before {
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
/* стили для чекбокса, находящегося в фокусе и не находящегося в состоянии checked */
.custom-checkbox:focus:not(:checked)+label::before {
  border-color: #80bdff;
}
/* стили для чекбокса, находящегося в состоянии disabled */
.custom-checkbox:disabled+label::before {
  background-color: #e9ecef;
}

Открыть пример

Разработка кастомного переключателя

Стилизация переключателя (input с type="radio") выполняется аналогично, т.е. посредством тех же шагов которые мы применяли при кастомизации чекбокса.

Вид стилизованного чекбокса в браузере по умолчанию и в состоянии checked

Итоговый набор стилей для кастомного оформления input с type="radio":

<style>
  /* для элемента input c type="radio" */
  .custom-radio {
    position: absolute;
    z-index: -1;
    opacity: 0;
  }
  /* для элемента label связанного с .custom-radio */
  .custom-radio+label {
    display: inline-flex;
    align-items: center;
    user-select: none;
  }
  /* создание в label псевдоэлемента  before со следующими стилями */
  .custom-radio+label::before {
    content: '';
    display: inline-block;
    width: 1em;
    height: 1em;
    flex-shrink: 0;
    flex-grow: 0;
    border: 1px solid #adb5bd;
    border-radius: 50%;
    margin-right: 0.5em;
    background-repeat: no-repeat;
    background-position: center center;
    background-size: 50% 50%;
  }
  /* стили при наведении курсора на радио */
  .custom-radio:not(:disabled):not(:checked)+label:hover::before {
    border-color: #b3d7ff;
  }
  /* стили для активной радиокнопки (при нажатии на неё) */
  .custom-radio:not(:disabled):active+label::before {
    background-color: #b3d7ff;
    border-color: #b3d7ff;
  }
  /* стили для радиокнопки, находящейся в фокусе */
  .custom-radio:focus+label::before {
    box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
  }
  /* стили для радиокнопки, находящейся в фокусе и не находящейся в состоянии checked */
  .custom-radio:focus:not(:checked)+label::before {
    border-color: #80bdff;
  }
  /* стили для радиокнопки, находящейся в состоянии checked */
  .custom-radio:checked+label::before {
    border-color: #0b76ef;
    background-color: #0b76ef;
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
  }
  /* стили для радиокнопки, находящейся в состоянии disabled */
  .custom-radio:disabled+label::before {
    background-color: #e9ecef;
  }
</style>

<input class="custom-radio" name="color" type="radio" id="color-green" value="green">
<label for="color-green">Green</label>

Открыть пример

Ещё примеры по кастомизации checkbox и label

В этом разделе представлены следующие примеры:

  • оформление чекбокса, когда input расположен в label
  • оформление переключателя, когда input расположен в label

1. Стилизация checkbox, когда input расположен в label.

HTML разметка:

<label class="custom-checkbox">
  <input type="checkbox" value="value-1">
  <span>Indigo</span>
</label>

CSS код:

/* для элемента input c type="checkbox" */
.custom-checkbox>input {
  position: absolute;
  z-index: -1;
  opacity: 0;
}

/* для элемента label, связанного с .custom-checkbox */
.custom-checkbox>span {
  display: inline-flex;
  align-items: center;
  user-select: none;
}

/* создание в label псевдоэлемента before со следующими стилями */
.custom-checkbox>span::before {
  content: '';
  display: inline-block;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  flex-grow: 0;
  border: 1px solid #adb5bd;
  border-radius: 0.25em;
  margin-right: 0.5em;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 50% 50%;
}

/* стили при наведении курсора на checkbox */
.custom-checkbox>input:not(:disabled):not(:checked)+span:hover::before {
  border-color: #b3d7ff;
}

/* стили для активного чекбокса (при нажатии на него) */
.custom-checkbox>input:not(:disabled):active+span::before {
  background-color: #b3d7ff;
  border-color: #b3d7ff;
}

/* стили для чекбокса, находящегося в фокусе */
.custom-checkbox>input:focus+span::before {
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}

/* стили для чекбокса, находящегося в фокусе и не находящегося в состоянии checked */
.custom-checkbox>input:focus:not(:checked)+span::before {
  border-color: #80bdff;
}

/* стили для чекбокса, находящегося в состоянии checked */
.custom-checkbox>input:checked+span::before {
  border-color: #0b76ef;
  background-color: #0b76ef;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
}

/* стили для чекбокса, находящегося в состоянии disabled */
.custom-checkbox>input:disabled+span::before {
  background-color: #e9ecef;
}

Открыть пример

2. Стилизация radio, когда input расположен в label.

HTML разметка:

<label class="custom-radio">
  <input type="radio" name="color" value="indigo">
  <span>Indigo</span>
</label>

CSS код:

/* для элемента input c type="radio" */
.custom-radio>input {
  position: absolute;
  z-index: -1;
  opacity: 0;
}

/* для элемента label связанного с .custom-radio */
.custom-radio>span {
  display: inline-flex;
  align-items: center;
  user-select: none;
}

/* создание в label псевдоэлемента  before со следующими стилями */
.custom-radio>span::before {
  content: '';
  display: inline-block;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  flex-grow: 0;
  border: 1px solid #adb5bd;
  border-radius: 50%;
  margin-right: 0.5em;
  background-repeat: no-repeat;
  background-position: center center;
  background-size: 50% 50%;
}

/* стили при наведении курсора на радио */
.custom-radio>input:not(:disabled):not(:checked)+span:hover::before {
  border-color: #b3d7ff;
}

/* стили для активной радиокнопки (при нажатии на неё) */
.custom-radio>input:not(:disabled):active+span::before {
  background-color: #b3d7ff;
  border-color: #b3d7ff;
}

/* стили для радиокнопки, находящейся в фокусе */
.custom-radio>input:focus+span::before {
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}

/* стили для радиокнопки, находящейся в фокусе и не находящейся в состоянии checked */
.custom-radio>input:focus:not(:checked)+span::before {
  border-color: #80bdff;
}

/* стили для радиокнопки, находящейся в состоянии checked */
.custom-radio>input:checked+span::before {
  border-color: #0b76ef;
  background-color: #0b76ef;
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
}

/* стили для радиокнопки, находящейся в состоянии disabled */
.custom-radio>input:disabled+span::before {
  background-color: #e9ecef;
}

Открыть пример

Yikes! All these workarounds have led me to the conclusion that the HTML checkbox kind of sucks if you want to style it.

As a forewarning, this isn’t a CSS implementation. I just thought I’d share the workaround I came up with in case anyone else might find it useful.


I used the HTML5 canvas element.

The upside to this is that you don’t have to use external images and can probably save some bandwidth.

The downside is that if a browser for some reason can’t render it correctly, then there’s no fallback. Though whether this remains an issue in 2017 is debatable.

Update

I found the old code quite ugly, so I decided to give it a rewrite.

Object.prototype.create = function(args){
    var retobj = Object.create(this);

    retobj.constructor(args || null);

    return retobj;
}

var Checkbox = Object.seal({
    width: 0,
    height: 0,
    state: 0,
    document: null,
    parent: null,
    canvas: null,
    ctx: null,

    /*
     * args:
     * name      default             desc.
     *
     * width     15                  width
     * height    15                  height
     * document  window.document     explicit document reference
     * target    this.document.body  target element to insert checkbox into
     */
    constructor: function(args){
        if(args === null)
            args = {};

        this.width = args.width || 15;
        this.height = args.height || 15;
        this.document = args.document || window.document;
        this.parent = args.target || this.document.body;
        this.canvas = this.document.createElement("canvas");
        this.ctx = this.canvas.getContext('2d');

        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.addEventListener("click", this.ev_click(this), false);
        this.parent.appendChild(this.canvas);
        this.draw();
    },

    ev_click: function(self){
        return function(unused){
            self.state = !self.state;
            self.draw();
        }
    },

    draw_rect: function(color, offset){
        this.ctx.fillStyle = color;
        this.ctx.fillRect(offset, offset,
                this.width - offset * 2, this.height - offset * 2);
    },

    draw: function(){
        this.draw_rect("#CCCCCC", 0);
        this.draw_rect("#FFFFFF", 1);

        if(this.is_checked())
            this.draw_rect("#000000", 2);
    },

    is_checked: function(){
        return !!this.state;
    }
});

Here’s a working demo.

The new version uses prototypes and differential inheritance to create an efficient system for creating checkboxes. To create a checkbox:

var my_checkbox = Checkbox.create();

This will immediately add the checkbox to the DOM and hook up the events. To query whether a checkbox is checked:

my_checkbox.is_checked(); // True if checked, else false

Also important to note is that I got rid of the loop.

Update 2

Something I neglected to mention in the last update is that using the canvas has more advantages than just making a checkbox that looks however you want it to look. You could also create multi-state checkboxes, if you wanted to.

Object.prototype.create = function(args){
    var retobj = Object.create(this);

    retobj.constructor(args || null);

    return retobj;
}

Object.prototype.extend = function(newobj){
    var oldobj = Object.create(this);

    for(prop in newobj)
        oldobj[prop] = newobj[prop];

    return Object.seal(oldobj);
}

var Checkbox = Object.seal({
    width: 0,
    height: 0,
    state: 0,
    document: null,
    parent: null,
    canvas: null,
    ctx: null,

    /*
     * args:
     * name      default             desc.
     *
     * width     15                  width
     * height    15                  height
     * document  window.document     explicit document reference
     * target    this.document.body  target element to insert checkbox into
     */
    constructor: function(args){
        if(args === null)
            args = {};

        this.width = args.width || 15;
        this.height = args.height || 15;
        this.document = args.document || window.document;
        this.parent = args.target || this.document.body;
        this.canvas = this.document.createElement("canvas");
        this.ctx = this.canvas.getContext('2d');

        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.addEventListener("click", this.ev_click(this), false);
        this.parent.appendChild(this.canvas);
        this.draw();
    },

    ev_click: function(self){
        return function(unused){
            self.state = !self.state;
            self.draw();
        }
    },

    draw_rect: function(color, offsetx, offsety){
        this.ctx.fillStyle = color;
        this.ctx.fillRect(offsetx, offsety,
                this.width - offsetx * 2, this.height - offsety * 2);
    },

    draw: function(){
        this.draw_rect("#CCCCCC", 0, 0);
        this.draw_rect("#FFFFFF", 1, 1);
        this.draw_state();
    },

    draw_state: function(){
        if(this.is_checked())
            this.draw_rect("#000000", 2, 2);
    },

    is_checked: function(){
        return this.state == 1;
    }
});

var Checkbox3 = Checkbox.extend({
    ev_click: function(self){
        return function(unused){
            self.state = (self.state + 1) % 3;
            self.draw();
        }
    },

    draw_state: function(){
        if(this.is_checked())
            this.draw_rect("#000000", 2, 2);

        if(this.is_partial())
            this.draw_rect("#000000", 2, (this.height - 2) / 2);
    },

    is_partial: function(){
        return this.state == 2;
    }
});

I modified slightly the Checkbox used in the last snippet so that it is more generic, making it possible to «extend» it with a checkbox that has 3 states. Here’s a demo. As you can see, it already has more functionality than the built-in checkbox.

Something to consider when you’re choosing between JavaScript and CSS.

Old, poorly-designed code

Working Demo

First, set up a canvas

var canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d'),
    checked = 0; // The state of the checkbox
canvas.width = canvas.height = 15; // Set the width and height of the canvas
document.body.appendChild(canvas);
document.body.appendChild(document.createTextNode(' Togglable Option'));

Next, devise a way to have the canvas update itself.

(function loop(){
  // Draws a border
  ctx.fillStyle = '#ccc';
  ctx.fillRect(0,0,15,15);
  ctx.fillStyle = '#fff';
  ctx.fillRect(1, 1, 13, 13);
  // Fills in canvas if checked
  if(checked){
    ctx.fillStyle = '#000';
    ctx.fillRect(2, 2, 11, 11);
  }
  setTimeout(loop, 1000/10); // Refresh 10 times per second
})();

The last part is to make it interactive. Luckily, it’s pretty simple:

canvas.onclick = function(){
  checked = !checked;
}

This is where you might have problems in IE, due to their weird event handling model in JavaScript.


I hope this helps someone; it definitely suited my needs.

Оформление элементов формы — это старая проблема. Ситуация несомненно улучшается, но финала пока не видно. С появлением псевдо-контейнеров :after и :before стало возможным без дополнительных элементов и скриптов кастомизировать элемент INPUT:CHECKBOX.

<input type=«checkbox» id=«checkbox-id» />

<label for=«checkbox-id»>Чекбокс как есть</label>

В разных браузерах этот элемент будет выглядеть по разному. Chrome, Opera, IE, Yandex и прочие — будут по мере сил и фантазии разработчиков выводить checkbox с собственным оформлением.

Квадрат и галочку нельзя изменить стандартными стилями вроде:

// это работать не будет

input[type=«checkbox»] {

  border: 1px solid #f00;

  background: #f00;

  borderradius: 5;

}

Поэтому стоит задача полностью заменить вывод стандартного элемента на свой, и мы сделаем это, используя только CSS.

План действий такой:

  1. Скрываем вывод чек-бокса;
  2. Формируем нужный внешний вид чекбокса в псевдо — элементе label:before;
  3. Дополнительные стили формируют внешний вид текущего статуса.

Важно, чтобы элемент Label был связан с чекбокс (через параметр for), тогда нажатие на метку передаётся на связанный элемент, и все работает как нужно без дополнительных скриптов.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

/* прячем input checkbox */

input[type=«checkbox»] {

  display: none;

}

/* стили для метки */

label {

color: #000;

  cursor: default;

  fontweight: normal;

  lineheight: 30px;

  padding: 10px 0;

  verticalalign: middle;

}

/* формируем внешний вид чекбокса в псевдоэлементе before */

label:before {

  content: » «;

  color: #000;

  display: inlineblock;

  font: 20px/30px Arial;

  marginright: 15px;

  position: relative;

  textalign: center;

  textindent: 0px;

  width: 30px;

  height: 30px;

  background: #FFF;

  border: 1px solid #e3e3e3;

  borderimage: initial;

  verticalalign: middle;

}

/* вариации внешнего вида в зав-ти от статуса checkbox */

/* checked */

input:checked + label:before {

  content: «x»;

}

/* disabled */

input:disabled + label:before {

  background: #eee;

  color: #aaa;

}

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

Как видите для вывода галочки я использовал просто символ «x» из шрифта Arial. Далее вы можете сами решать как выглядит контейнер и галочка.

Я к примеру использую шрифт awesome, в котором есть литера галочки.

Вот тот же CSS с использованием FontAwesome:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

input[type=«checkbox»] {

display: none;

}

label {

color: #000;

cursor: default;

fontweight: normal;

lineheight: 30px;

padding: 10px 0;

verticalalign: middle;

}

label:before {

content: » «;

color: #000;

display: inlineblock;

/* шрифт Awesome*/

font: 20px/30px FontAwesome;

marginright: 15px;

position: relative;

textalign: center;

textindent: 0px;

width: 30px;

height: 30px;

background: #FFF;

border: 1px solid #e3e3e3;

borderimage: initial;

verticalalign: middle;

}

input:checked + label:before {

/* глифон — галочка */

content: «f00c»;

}

input:disabled + label:before {

background: #eee;

color: #aaa;

}

Так выглядит checkbox с галочкой из набора иконок Awesome.

Написать комментарий


Данная запись опубликована в 27.12.2017 17:23 и размещена в Танцы с CSS.
Вы можете перейти в конец страницы и оставить ваш комментарий.

Мало букафф? Читайте есчо !

Прогресс бары, анимация загрузки…

Январь 11, 2019 г.

Сайт, где вы найдете конструкторы анимации прогресс баров — loading.io. Я бы сказал налетай, подешевело, но всё абсолютно даром.

Основная особенность …

Читать

Как запретить растягивание textarea

Февраль 27, 2017 г.

Тэг TextArea — незаменимое поле ввода для текста. Современные браузеры по-умолчанию позволяют пользователям изменять размеры, растягивать его за правый …

Читать

Несколько примеров как изменить внешний вид чекбоксов с помощью CSS, изображений и немного JS.

1

Метод «Checkbox Hack»

Основан на связи <label> и помещенного в него инпута, т.е. по клику на него, инпут будет менять свое состояние.

<label>
	<input type="checkbox">
	Checkbox
</label>

HTML

Стоит заменить что в некоторых старых браузерах (например Safari) такой приём не работает и требует добавление атрибутов for у <label> и id у чекбокса.

<label for="element">
	<input type="checkbox" id="element">
	Checkbox
</label>

HTML

В зависимости от состояния чекбокса :checked, :disabled и :focus, следующему за ним элементу, например <span>, можно задавать стили с помощью селектора «+».

<label>
	<input type="checkbox">
	<span>Checkbox</span>
</label>

HTML

/* Dafault */
label input[type=checkbox] + span {
	...
}

/* Focus */
label input[type=checkbox]:focus + span {
	...
}

/* Checked */
label input[type=checkbox]:checked + span {
	...
}

/* Disabled */
label input[type=checkbox]:disabled + span {
	...
}
label input[type=checkbox]:disabled:checked + span {
	...
}

CSS

Сам чекбокс скрывается, но без использования display: none, что бы оставить функциональность фокуса.

label input[type=checkbox] {
	position: absolute;
	z-index: -1;
	opacity: 0;
	display: block;
	width: 0;
	height: 0;
}

CSS

По умолчанию, фокус появляется при клике на элемент, что не очень и нужно. Оставить выделение при фокусе только при нажатии клавиши Tab можно с помощью JQuery, добавляя класс focused родительскому элементу.

$(window).keyup(function(e){
	var target = $('label input[type=checkbox]:focus');
	if (e.keyCode == 9 && $(target).length){
		$(target).parent().addClass('focused');
	}
});

$('label input[type=checkbox]').focusout(function(){
	$(this).parent().removeClass('focused');
});

JS

Пример №1

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

HTML-разметка:

<label class="checkbox-other">
	<input type="checkbox" checked>
	<span>Checkbox #1</span>
</label>

<label class="checkbox-other">
	<input type="checkbox">
	<span>Checkbox #2</span>
</label>

<label class="checkbox-other">
	<input type="checkbox" disabled>
	<span>Checkbox #3</span>
</label>

<label class="checkbox-other">
	<input type="checkbox" checked disabled>
	<span>Checkbox #4</span>
</label>

HTML

Фокус по клавише Tab:

$(window).keyup(function(e){
	var target = $('.checkbox-other input:focus');
	if (e.keyCode == 9 && $(target).length){
		$(target).parent().addClass('focused');
	}
});

$('.checkbox-other input').focusout(function(){
	$(this).parent().removeClass('focused');
});

JS

CSS-стили:

.checkbox-other {
	display: block;
	margin: 0 0 10px 0;
	cursor: pointer;
	user-select: none;
	position: relative;
}
.checkbox-other input[type=checkbox] {
	position: absolute;
	z-index: -1;
	opacity: 0;
	display: block;
	width: 0;
	height: 0;
}
.checkbox-other span {
	display: inline-block;
	position: relative; 
	padding: 0 0 0 35px; 
	line-height: 22px;    
}
.checkbox-other span:before {
	content: "";
	display: inline-block;
	width: 22px;
	height: 22px;
	position: absolute;
	left: 0;
	top: 0;
	transition: background 0.3s ease;
	background: url(/checkbox-1.png) 0 0 no-repeat;
}

/* Checked */
.checkbox-other input[type=checkbox]:checked + span:before {
	background-image: url(/checkbox-2.png);
}

/* Focus */
.focused span:before {
	box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}

/* Hover */
.checkbox-other span:hover:before {
	filter: brightness(110%);
}

/* Active */
.checkbox-other span:active:before {
	filter: brightness(80%);
}

/* Disabled */
.checkbox-other input[type=checkbox]:disabled + span {
	color: #666;
	cursor: default;
}
.checkbox-other input[type=checkbox]:disabled + span:before {
	filter: grayscale(100%);
	opacity: 0.6;
}

CSS

Результат:

Пример №2

Подходит для случаев, когда галка выходит за края элемента. HTML-разметка и JS-код остается прежними.

.checkbox-other {
	display: block;
	margin: 0 0 10px 0;
	cursor: pointer;
	user-select: none;
	position: relative;
}
.checkbox-other input[type=checkbox] {
	position: absolute;
	z-index: -1;
	opacity: 0;
	display: block;
	width: 0;
	height: 0;
}
.checkbox-other span {
	display: inline-block;
	position: relative; 
	padding: 0 0 0 35px; 
	line-height: 22px;    
}
.checkbox-other span:before {
	content: "";
	display: inline-block;
	width: 22px;
	height: 22px;
	position: absolute;
	left: 0;
	top: 0;
	background: url(/checkbox-3.png) 0 0 no-repeat;
}

/* Checked */
.checkbox-other input[type=checkbox] + span:after {
	content: "";	
	opacity: 0;
	transition: opacity 0.3s ease;
}
.checkbox-other input[type=checkbox]:checked + span:after {
	display: inline-block;
	width: 22px;
	height: 22px;
	position: absolute;
	left: 4px;
	top: -5px;
	background: url(/checkbox-4.png) 0 0 no-repeat;
	opacity: 1;
}

/* Focus */
.focused span:before {
	box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}

/* Hover */
.checkbox-other span:hover:after {
	filter: brightness(110%);
}

/* Active */
.checkbox-other span:active:before,
.checkbox-other span:active:after {
	filter: brightness(80%);
}

/* Disabled */
.checkbox-other input[type=checkbox]:disabled + span {
	color: #666;
	cursor: default;
}
.checkbox-other input[type=checkbox]:disabled + span:before,
.checkbox-other input[type=checkbox]:disabled + span:after {
	filter: grayscale(100%);
	opacity: 0.6;
}

CSS

Результат:

Пример №3

Вариант с использованием символа галочки – ✓ или эмоджи ✔.

.checkbox-other {
	display: block;
	margin: 0 0 10px 0;
	line-height: 22px;
	cursor: pointer;
	user-select: none;
	position: relative;
}
.checkbox-other input[type=checkbox] {
	position: absolute;
	z-index: -1;
	opacity: 0;
	display: block;
	width: 0;
	height: 0;
}
.checkbox-other span {
	display: inline-block;
	position: relative; 
	padding: 0 0 0 35px; 
	line-height: 22px;    
}
.checkbox-other span:before {
	content: "";
	display: inline-block;
	width: 20px;
	height: 20px;
	position: absolute;
	left: 0;
	top: 0;
	border: 1px solid #2B7335;
	box-shadow: inset 0 0 3px #8a8a8a;
}

/* Checked */
.checkbox-other input[type=checkbox] + span:after {
	content: "";	
	opacity: 0;
	transition: opacity 0.3s ease;
}
.checkbox-other input[type=checkbox]:checked + span:after {
	content: "✓";
	color: green;
	font-size: 30px;
	font-weight: 900;
	position: absolute;
	left: 2px;
	top: -2px;
	opacity: 1;
}

/* Focus */
.focused span:before {
	box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}

/* Hover */
.checkbox-other span:hover:after {
	filter: brightness(110%);
}

/* Active */
.checkbox-other span:active:before,
.checkbox-other span:active:after {
	filter: brightness(80%);
}

/* Disabled */
.checkbox-other input[type=checkbox]:disabled + span {
	color: #666;
	cursor: default;
}
.checkbox-other input[type=checkbox]:disabled + span:before,
.checkbox-other input[type=checkbox]:disabled + span:after {
	filter: grayscale(100%);
	opacity: 0.6;
}

CSS

2

CSS свойство appearance

Пока нестандартезированое свойство -webkit-appearance: none отключает стандартное оформление элемнта формы, но сохраняет его функциональность, тем самым появляется возможность задать ему любые стили, но без псевдосвойст :before и :after. Полное описание на developer.mozilla.org.

<label class="checkbox-other">
	<input type="checkbox" checked> Checkbox #1
</label>

<label class="checkbox-other">
	<input type="checkbox"> Checkbox #2
</label>

<label class="checkbox-other">
	<input type="checkbox" disabled> Checkbox #3
</label>

<label class="checkbox-other">
	<input type="checkbox" checked disabled> Checkbox #4
</label>

HTML

.checkbox-other {
	display: block;
	margin: 0 0 10px 0;
	line-height: 22px;  
}
.checkbox-other input[type=checkbox] {
	-webkit-appearance: none;
	-moz-appearance: none;
	display: inline-block;
	width: 22px;
	height: 22px;
	margin: 0 5px 0 0;
	padding: 0;
	vertical-align: top;
	outline: none;
	transition: background 0.3s ease;
	background: url(/checkbox-1.png) 0 0 no-repeat;
	cursor: pointer;
}

/* Checked */
.checkbox-other input[type=checkbox]:checked {
	background-image: url(/checkbox-2.png);
}

/* Focus */
.focused input[type=checkbox] {
	box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}

/* Hover */
.checkbox-other input[type=checkbox]:hover {
	filter: brightness(110%);
}

/* Active */
.checkbox-other input[type=checkbox]:active {
	filter: brightness(80%);
}

/* Disabled */
.checkbox-other input[type=checkbox]:disabled {
	color: #666;
	cursor: default;
}
.checkbox-other input[type=checkbox]:disabled {
	filter: grayscale(100%);
	opacity: 0.6;
}

CSS

Свойство appearance поддерживается всеми современными брузерами. В старых брауезерах, чекбокбокс будет выводится как обычный.

Data on support for the css-appearance feature across the major browsers from caniuse.com

22.04.2020, обновлено 21.02.2021

Другие публикации

Отметить или снять все чекбоксы в таблице

Мини JQuery плагин позволяет отметить или снять одним кликом чекбоксы в таблицах и отметить чекбокс по клику на сроку…

Checkbox или radiobutton в меню dropdowns

Проблема в том что если вставить чекбокс, радиокнопку в меню dropdowns Bootstrap и кликнув по ним, меню сразу…

Раскрывающийся многоуровневый список

В данном примере описано как вывести многоуровневый список checkbox и radio button из БД с помощью PHP функций…

Селект с чекбоксами

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

Стилизация input file

Примеры изменения вида стандартного поля для загрузки файлов input type file с помощью CSS и JS.

Contenteditable – текстовый редактор

Если добавить атрибут contenteditable к элементу, его содержимое становится доступно для редактирования пользователю, а…

Наверняка вы задумались о том, как можно изменить стандартный вид флажков (чекбоксов), чтобы они выглядели привлекательней с учетом дизайна вашего сайта или задач одной конкретной страницы. В этой статье вы найдете ряд практических примеров, которые помогут вам стилизовать элементы <input type="checkbox">. Для начала разберем пример, который имеет вид переключателя. Давайте посмотрим, как можно стилизовать флажки на примере, который в html-разметке содержит только <input type="checkbox"> и <label>:

<input type=«checkbox» id=«demo1» checked>

<label for=«demo1» dataonlabel=«Вкл.» dataofflabel=«Выкл.»></label>

<input type=«checkbox» id=«demo2»>

<label for=«demo2» dataonlabel=«Да» dataofflabel=«Нет»></label>

Сам пример в действии:

Теперь рассмотрим CSS-стили:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

label { margin: 2em;}

input { display: none;}

input+label,

input+label::before,

input+label::after {

-webkit-transition: all .2s;

transition: all .2s;

}

input+label {

display: inline-block;

position: relative;

width: 130px;

height: 50px;

border-radius: 25px;

cursor: pointer;

}

input+label::before {

display: block;

content: attr(data-off-label);

position: absolute;

top: 15px;

right: 10px;

color: #fff;

font-family: Arial, sans-serif;

font-size: 18px;

}

input+label::after {

content: »;

position: absolute;

top: 2px;

left: 2px;

width: 44px;

height: 44px;

background-color: #fff;

border-radius: 50%;

}

input:checked+label::before {

content: attr(data-on-label);

left: 14px;

right: auto;

color: #fff;

}

input:checked+label::after {

left: 83px;

background-color: #f7f7f7;

}

#demo1+label { background-color: #ccc; }

#demo1+label::before { color: #999; }

#demo1:checked+label { background-color: #3498db; }

#demo1:checked+label::before { color: #fff; }

#demo2+label { background-color: #e74c3c; }

#demo2:checked+label { background-color: #1abc9c; }

Если проанализировать код CSS, то видно, что элемент input мы прячем (свойство display: none), а все остальные стили прописаны для элемента label, а также псевдоэлементов label::before и label::after. Изменения внешнего вида также осуществляются для псевдокласса :checked, который имеет смысл использовать для флажков и радио-кнопок.

Еще ряд похожих вариантов с анимацией вам предлагает Himalaya Singh в своем примере.

See the Pen Pure CSS Toggle Buttons | ON-OFF Switches by Himalaya Singh (@himalayasingh) on CodePen.18892

И еще один пример:

See the Pen Simple CSS Checkbox by Tristan White (@triss90) on CodePen.18892

Примеры стилизации флажков с ресурса codepen.io

Как работает стилизация

В этом примере видно, где расположен флажок, который обычно скрывается с помощью свойства display: none, и как стилизованы label. Откройте вкладку CSS и проанализируйте код.

See the Pen [Pure CSS] Delightful Checkbox Animation by Dylan Raga (@dylanraga) on CodePen.18892

Простое решение для флажков и переключателей от Jon Kantner.

See the Pen CSS Checkboxes and Radio Buttons by Jon Kantner (@jkantner) on CodePen.18892

Близкие к стандартным варианты флажков, переключателей и выпадающих списков от Kenan Yusuf

See the Pen Completely CSS: Custom checkboxes, radio buttons and select boxes by Kenan Yusuf (@KenanYusuf) on CodePen.18892

Зачеркивание при выборе флажка с анимацией

See the Pen Animated Fill and Strikethrough Checkboxes by Jon Kantner (@jkantner) on CodePen.18892

Несколько интересных решений для флажков и переключателей от Brad Bodine

See the Pen CSS3 Checkbox Styles by Brad Bodine (@bbodine1) on CodePen.18892

Несколько похожих переключений состояний чекбокса от Olivia Ng

See the Pen Toggles by Elen (@ambassador)
on CodePen.0

Разные виды переключателей от Mauricio Allende

See the Pen Pure CSS toggle buttons by Elen (@ambassador) on CodePen.0

Анимированное переключение состояний флажка в виде пилюли

See the Pen Pill Switch 💊 by Elen (@ambassador) on CodePen.18892

Круглая кнопка с анимацией от mandycodestoo

See the Pen 100dayscss-66 by @mandycodestoo (@mandycodestoo) on CodePen.18892

Анимация текста флажков и радио-кнопок от Raúl Barrera

See the Pen Pure CSS Fancy Checkbox/Radio by Raúl Barrera (@raubaca) on CodePen.18892

Подсветка текста label + анимация выбора чекбокса от Adam Quinlan

See the Pen chippy checkbox inputs by Adam Quinlan (@quinlo) on CodePen.18892

Анимированные флажки с изменением цвета на основе css-переменных от Stas Melnikov

See the Pen #CodePenChallenge | Pure CSS Checkboxes by Stas Melnikov (@melnik909) on CodePen.18892

Анимация флажков с переворотом

See the Pen Flip checkbox by Elen (@ambassador) on CodePen.18892

Анимация флажков и переключателей в стиле Material Design от Matt Sisto

See the Pen CSS «Ripple/Wave» checkbox and radio button by Matt Sisto (@msisto) on CodePen.18892

Перекатывающийся шарик от Jon Kantner

Вариант 1

See the Pen Toy Toggle Switch by Jon Kantner (@jkantner) on CodePen.18892

Вариант 2 со скрепкой

See the Pen Paper Clip Toggle Switch by Jon Kantner (@jkantner) on CodePen.18892

Карандаш для отметки выбора флажка

Еще один вариант анимации от Jon Kantner, но с появлением карандаша. Отличное решение для тестов, например.

See the Pen Pencil and Paper Checkboxes by Jon Kantner (@jkantner) on CodePen.18892

Меняем цветовую схему переключателем

Автор Jon Kantner предлагает вашему вниманию вариант кода, при котором клик на чекбоксе меняет цвет фона.

Вариант 1

See the Pen Toggle Switch with Rolling Label by Jon Kantner (@jkantner) on CodePen.18892

Вариант 2

See the Pen Light/Dark Mode Toggle With Curtain Effect by Jon Kantner (@jkantner) on CodePen.18892

Переключатель энергии

See the Pen Blocky Toggle Switch by Jon Kantner (@jkantner) on CodePen.18892

Реализация аккордеона на чистом CSS с использованием чекбоксов от Alex Bergin

See the Pen CSS + HTML only Accordion Element by Alex Bergin (@abergin) on CodePen.18892

Переключатель цены от Aniruddha Banerjee

See the Pen Pricing Card Design by Aniruddha Banerjee (@imanirudh1) on CodePen.0

Выбор группы иконок от Håvard Brynjulfsen

See the Pen Checkbox group styled as tiles by Håvard Brynjulfsen (@havardob) on CodePen.0

Использование переключателя для показа скрытого контента

Скрытый checkbox нужен для отображения блока с информацией, которая не видна изначально. Автор Lisi.

See the Pen Expand Information by Lisi (@lisilinhart)on CodePen.0

Сложные примеры

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

Шестеренки в переключателе с анимацией

Автор leimapapa 

See the Pen ⚙️ Giant Gear Toggle ⚙️ by leimapapa (@leimapapa) on CodePen.0

Флажок-выключатель

Отличная стилизация <input type="checkbox"> в виде выключателя с внутренней подсветкой от Yoav Kadosh.

See the Pen Realistic Red Switch (Pure CSS) by Yoav Kadosh (@ykadosh) on CodePen.18892

Лампа-переключатель

Вариант попроще внешне от Jon Kantner, но в коде вы найдете очень меого правил.

See the Pen Light Bulb Toggle Switch by Jon Kantner (@jkantner) on CodePen.18892

Флажок-переключатель

Настоящий переключатель от Jon Kantner. Здесь использован не только CSS, но и JS-код.

See the Pen Skeuomorphic Lever Checkbox by Jon Kantner (@jkantner) on CodePen.18892

Еще один вариант 3D-переключателя

Автор Yoav Kadosh

See the Pen 3D Orange Switch (Pure CSS) by Yoav Kadosh (@ykadosh) on CodePen.0

3D-трансформации с анимацией

Глядя на этот пример, понимаешь, что стилизация переключателей — это наименьшее из того, что сделал автор Ivan Grozdic . Отличный вариант для туристического сайта в плане выбора услуг.

See the Pen Pricing — pure css — #16 by Ivan Grozdic (@ig_design) on CodePen.18892

Пример генератора пароля с использованием флажков

See the Pen Random Password Generator — HTML | CSS | JS by Sikriti Dakua (@dev_loop) on CodePen.18892

ToDo List (список дел) от Will Boyd

Интересно то, что при отметке чекбокса вы получаете список дел с подсчетом сделанных и несделанных заданий на основе только лишь CSS, совсем без JavaScript-кода, за счет использования свойства counter-increment и свойства order Flexbox-модели.

See the Pen Checkbox Trickery: To-Do List by Will Boyd (@lonekorean) on CodePen.18892

И еще один ToDo List от Daniel Ramos

Только CSS, без JavaScript

See the Pen To do List + CSS by Daniel Ramos (@DanielRamos)  on CodePen.0

Бонус. Невключаемый чекбох

Для тех, кто дочитал до конца — бонус — чекбокс, который нельзя оставить включенным, так как вы рассердите мишку. Он даже рычать умеет и хмурить брови. Наслаждайтесь ))) Написано на React. Автор Jhey.

See the Pen Impossible Checkbox v2 🐻 by Jhey (@jh3y)
on CodePen.0

Просмотров: 10 685

Yikes! All these workarounds have led me to the conclusion that the HTML checkbox kind of sucks if you want to style it.

As a forewarning, this isn’t a CSS implementation. I just thought I’d share the workaround I came up with in case anyone else might find it useful.


I used the HTML5 canvas element.

The upside to this is that you don’t have to use external images and can probably save some bandwidth.

The downside is that if a browser for some reason can’t render it correctly, then there’s no fallback. Though whether this remains an issue in 2017 is debatable.

Update

I found the old code quite ugly, so I decided to give it a rewrite.

Object.prototype.create = function(args){
    var retobj = Object.create(this);

    retobj.constructor(args || null);

    return retobj;
}

var Checkbox = Object.seal({
    width: 0,
    height: 0,
    state: 0,
    document: null,
    parent: null,
    canvas: null,
    ctx: null,

    /*
     * args:
     * name      default             desc.
     *
     * width     15                  width
     * height    15                  height
     * document  window.document     explicit document reference
     * target    this.document.body  target element to insert checkbox into
     */
    constructor: function(args){
        if(args === null)
            args = {};

        this.width = args.width || 15;
        this.height = args.height || 15;
        this.document = args.document || window.document;
        this.parent = args.target || this.document.body;
        this.canvas = this.document.createElement("canvas");
        this.ctx = this.canvas.getContext('2d');

        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.addEventListener("click", this.ev_click(this), false);
        this.parent.appendChild(this.canvas);
        this.draw();
    },

    ev_click: function(self){
        return function(unused){
            self.state = !self.state;
            self.draw();
        }
    },

    draw_rect: function(color, offset){
        this.ctx.fillStyle = color;
        this.ctx.fillRect(offset, offset,
                this.width - offset * 2, this.height - offset * 2);
    },

    draw: function(){
        this.draw_rect("#CCCCCC", 0);
        this.draw_rect("#FFFFFF", 1);

        if(this.is_checked())
            this.draw_rect("#000000", 2);
    },

    is_checked: function(){
        return !!this.state;
    }
});

Here’s a working demo.

The new version uses prototypes and differential inheritance to create an efficient system for creating checkboxes. To create a checkbox:

var my_checkbox = Checkbox.create();

This will immediately add the checkbox to the DOM and hook up the events. To query whether a checkbox is checked:

my_checkbox.is_checked(); // True if checked, else false

Also important to note is that I got rid of the loop.

Update 2

Something I neglected to mention in the last update is that using the canvas has more advantages than just making a checkbox that looks however you want it to look. You could also create multi-state checkboxes, if you wanted to.

Object.prototype.create = function(args){
    var retobj = Object.create(this);

    retobj.constructor(args || null);

    return retobj;
}

Object.prototype.extend = function(newobj){
    var oldobj = Object.create(this);

    for(prop in newobj)
        oldobj[prop] = newobj[prop];

    return Object.seal(oldobj);
}

var Checkbox = Object.seal({
    width: 0,
    height: 0,
    state: 0,
    document: null,
    parent: null,
    canvas: null,
    ctx: null,

    /*
     * args:
     * name      default             desc.
     *
     * width     15                  width
     * height    15                  height
     * document  window.document     explicit document reference
     * target    this.document.body  target element to insert checkbox into
     */
    constructor: function(args){
        if(args === null)
            args = {};

        this.width = args.width || 15;
        this.height = args.height || 15;
        this.document = args.document || window.document;
        this.parent = args.target || this.document.body;
        this.canvas = this.document.createElement("canvas");
        this.ctx = this.canvas.getContext('2d');

        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.addEventListener("click", this.ev_click(this), false);
        this.parent.appendChild(this.canvas);
        this.draw();
    },

    ev_click: function(self){
        return function(unused){
            self.state = !self.state;
            self.draw();
        }
    },

    draw_rect: function(color, offsetx, offsety){
        this.ctx.fillStyle = color;
        this.ctx.fillRect(offsetx, offsety,
                this.width - offsetx * 2, this.height - offsety * 2);
    },

    draw: function(){
        this.draw_rect("#CCCCCC", 0, 0);
        this.draw_rect("#FFFFFF", 1, 1);
        this.draw_state();
    },

    draw_state: function(){
        if(this.is_checked())
            this.draw_rect("#000000", 2, 2);
    },

    is_checked: function(){
        return this.state == 1;
    }
});

var Checkbox3 = Checkbox.extend({
    ev_click: function(self){
        return function(unused){
            self.state = (self.state + 1) % 3;
            self.draw();
        }
    },

    draw_state: function(){
        if(this.is_checked())
            this.draw_rect("#000000", 2, 2);

        if(this.is_partial())
            this.draw_rect("#000000", 2, (this.height - 2) / 2);
    },

    is_partial: function(){
        return this.state == 2;
    }
});

I modified slightly the Checkbox used in the last snippet so that it is more generic, making it possible to «extend» it with a checkbox that has 3 states. Here’s a demo. As you can see, it already has more functionality than the built-in checkbox.

Something to consider when you’re choosing between JavaScript and CSS.

Old, poorly-designed code

Working Demo

First, set up a canvas

var canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d'),
    checked = 0; // The state of the checkbox
canvas.width = canvas.height = 15; // Set the width and height of the canvas
document.body.appendChild(canvas);
document.body.appendChild(document.createTextNode(' Togglable Option'));

Next, devise a way to have the canvas update itself.

(function loop(){
  // Draws a border
  ctx.fillStyle = '#ccc';
  ctx.fillRect(0,0,15,15);
  ctx.fillStyle = '#fff';
  ctx.fillRect(1, 1, 13, 13);
  // Fills in canvas if checked
  if(checked){
    ctx.fillStyle = '#000';
    ctx.fillRect(2, 2, 11, 11);
  }
  setTimeout(loop, 1000/10); // Refresh 10 times per second
})();

The last part is to make it interactive. Luckily, it’s pretty simple:

canvas.onclick = function(){
  checked = !checked;
}

This is where you might have problems in IE, due to their weird event handling model in JavaScript.


I hope this helps someone; it definitely suited my needs.

Yikes! All these workarounds have led me to the conclusion that the HTML checkbox kind of sucks if you want to style it.

As a forewarning, this isn’t a CSS implementation. I just thought I’d share the workaround I came up with in case anyone else might find it useful.


I used the HTML5 canvas element.

The upside to this is that you don’t have to use external images and can probably save some bandwidth.

The downside is that if a browser for some reason can’t render it correctly, then there’s no fallback. Though whether this remains an issue in 2017 is debatable.

Update

I found the old code quite ugly, so I decided to give it a rewrite.

Object.prototype.create = function(args){
    var retobj = Object.create(this);

    retobj.constructor(args || null);

    return retobj;
}

var Checkbox = Object.seal({
    width: 0,
    height: 0,
    state: 0,
    document: null,
    parent: null,
    canvas: null,
    ctx: null,

    /*
     * args:
     * name      default             desc.
     *
     * width     15                  width
     * height    15                  height
     * document  window.document     explicit document reference
     * target    this.document.body  target element to insert checkbox into
     */
    constructor: function(args){
        if(args === null)
            args = {};

        this.width = args.width || 15;
        this.height = args.height || 15;
        this.document = args.document || window.document;
        this.parent = args.target || this.document.body;
        this.canvas = this.document.createElement("canvas");
        this.ctx = this.canvas.getContext('2d');

        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.addEventListener("click", this.ev_click(this), false);
        this.parent.appendChild(this.canvas);
        this.draw();
    },

    ev_click: function(self){
        return function(unused){
            self.state = !self.state;
            self.draw();
        }
    },

    draw_rect: function(color, offset){
        this.ctx.fillStyle = color;
        this.ctx.fillRect(offset, offset,
                this.width - offset * 2, this.height - offset * 2);
    },

    draw: function(){
        this.draw_rect("#CCCCCC", 0);
        this.draw_rect("#FFFFFF", 1);

        if(this.is_checked())
            this.draw_rect("#000000", 2);
    },

    is_checked: function(){
        return !!this.state;
    }
});

Here’s a working demo.

The new version uses prototypes and differential inheritance to create an efficient system for creating checkboxes. To create a checkbox:

var my_checkbox = Checkbox.create();

This will immediately add the checkbox to the DOM and hook up the events. To query whether a checkbox is checked:

my_checkbox.is_checked(); // True if checked, else false

Also important to note is that I got rid of the loop.

Update 2

Something I neglected to mention in the last update is that using the canvas has more advantages than just making a checkbox that looks however you want it to look. You could also create multi-state checkboxes, if you wanted to.

Object.prototype.create = function(args){
    var retobj = Object.create(this);

    retobj.constructor(args || null);

    return retobj;
}

Object.prototype.extend = function(newobj){
    var oldobj = Object.create(this);

    for(prop in newobj)
        oldobj[prop] = newobj[prop];

    return Object.seal(oldobj);
}

var Checkbox = Object.seal({
    width: 0,
    height: 0,
    state: 0,
    document: null,
    parent: null,
    canvas: null,
    ctx: null,

    /*
     * args:
     * name      default             desc.
     *
     * width     15                  width
     * height    15                  height
     * document  window.document     explicit document reference
     * target    this.document.body  target element to insert checkbox into
     */
    constructor: function(args){
        if(args === null)
            args = {};

        this.width = args.width || 15;
        this.height = args.height || 15;
        this.document = args.document || window.document;
        this.parent = args.target || this.document.body;
        this.canvas = this.document.createElement("canvas");
        this.ctx = this.canvas.getContext('2d');

        this.canvas.width = this.width;
        this.canvas.height = this.height;
        this.canvas.addEventListener("click", this.ev_click(this), false);
        this.parent.appendChild(this.canvas);
        this.draw();
    },

    ev_click: function(self){
        return function(unused){
            self.state = !self.state;
            self.draw();
        }
    },

    draw_rect: function(color, offsetx, offsety){
        this.ctx.fillStyle = color;
        this.ctx.fillRect(offsetx, offsety,
                this.width - offsetx * 2, this.height - offsety * 2);
    },

    draw: function(){
        this.draw_rect("#CCCCCC", 0, 0);
        this.draw_rect("#FFFFFF", 1, 1);
        this.draw_state();
    },

    draw_state: function(){
        if(this.is_checked())
            this.draw_rect("#000000", 2, 2);
    },

    is_checked: function(){
        return this.state == 1;
    }
});

var Checkbox3 = Checkbox.extend({
    ev_click: function(self){
        return function(unused){
            self.state = (self.state + 1) % 3;
            self.draw();
        }
    },

    draw_state: function(){
        if(this.is_checked())
            this.draw_rect("#000000", 2, 2);

        if(this.is_partial())
            this.draw_rect("#000000", 2, (this.height - 2) / 2);
    },

    is_partial: function(){
        return this.state == 2;
    }
});

I modified slightly the Checkbox used in the last snippet so that it is more generic, making it possible to «extend» it with a checkbox that has 3 states. Here’s a demo. As you can see, it already has more functionality than the built-in checkbox.

Something to consider when you’re choosing between JavaScript and CSS.

Old, poorly-designed code

Working Demo

First, set up a canvas

var canvas = document.createElement('canvas'),
    ctx = canvas.getContext('2d'),
    checked = 0; // The state of the checkbox
canvas.width = canvas.height = 15; // Set the width and height of the canvas
document.body.appendChild(canvas);
document.body.appendChild(document.createTextNode(' Togglable Option'));

Next, devise a way to have the canvas update itself.

(function loop(){
  // Draws a border
  ctx.fillStyle = '#ccc';
  ctx.fillRect(0,0,15,15);
  ctx.fillStyle = '#fff';
  ctx.fillRect(1, 1, 13, 13);
  // Fills in canvas if checked
  if(checked){
    ctx.fillStyle = '#000';
    ctx.fillRect(2, 2, 11, 11);
  }
  setTimeout(loop, 1000/10); // Refresh 10 times per second
})();

The last part is to make it interactive. Luckily, it’s pretty simple:

canvas.onclick = function(){
  checked = !checked;
}

This is where you might have problems in IE, due to their weird event handling model in JavaScript.


I hope this helps someone; it definitely suited my needs.

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить стиль часов на экране блокировки хуавей
  • Как изменить стиль часов на экране блокировки хонор 10 лайт
  • Как изменить стиль часов на экране блокировки самсунг
  • Как изменить стиль часов на экране блокировки редми
  • Как изменить стиль часов на экране блокировки андроид

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии