Yikes! Wszystkie te obejścia doprowadziły mnie do wniosku, że pole wyboru HTML jest do bani, jeśli chcesz go stylizować.
Ostrzegając, nie jest to implementacja CSS. Pomyślałem, że podzielę się obejściem, na które wpadłem, na wypadek, gdyby ktokolwiek mógł uznać to za przydatne.
Użyłem canvas
elementu HTML5 .
Zaletą tego jest to, że nie musisz używać zewnętrznych obrazów i prawdopodobnie możesz zaoszczędzić trochę przepustowości.
Minusem jest to, że jeśli przeglądarka z jakiegoś powodu nie może poprawnie wyrenderować, to nie ma rezerwy. Jednak kwestia, czy problem ten pozostaje w 2017 r., Jest dyskusyjna.
Aktualizacja
Znalazłem stary kod dość brzydki, więc postanowiłem go przepisać.
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;
}
});
Oto działające demo .
Nowa wersja wykorzystuje prototypy i dziedziczenie różnicowe do stworzenia wydajnego systemu do tworzenia pól wyboru. Aby utworzyć pole wyboru:
var my_checkbox = Checkbox.create();
Spowoduje to natychmiastowe dodanie pola wyboru do DOM i połączenie zdarzeń. Aby zapytać, czy pole wyboru jest zaznaczone:
my_checkbox.is_checked(); // True if checked, else false
Należy również zauważyć, że pozbyłem się pętli.
Aktualizacja 2
Coś, czego nie wspomniałem w ostatniej aktualizacji, to fakt, że korzystanie z obszaru roboczego ma więcej zalet niż tworzenie pola wyboru, które wygląda tak, jak chcesz. Możesz również utworzyć wielostanowe pola wyboru, jeśli chcesz.
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;
}
});
Zmodyfikowałem nieco ten Checkbox
użyty w ostatnim fragmencie, aby był bardziej ogólny, dzięki czemu można go „rozszerzyć” za pomocą pola wyboru, które ma 3 stany. Oto demo . Jak widać, ma już więcej funkcji niż wbudowane pole wyboru.
Coś do rozważenia przy wyborze między JavaScript a CSS.
Stary, źle zaprojektowany kod
Demo pracy
Najpierw ustaw płótno
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'));
Następnie wymyśl sposób, aby sama aktualizacja płótna była możliwa.
(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
})();
Ostatnią częścią jest interaktywność. Na szczęście jest to dość proste:
canvas.onclick = function(){
checked = !checked;
}
To tutaj możesz mieć problemy w IE z powodu ich dziwnego modelu obsługi zdarzeń w JavaScript.
Mam nadzieję, że to komuś pomoże; to zdecydowanie odpowiadało moim potrzebom.