Custom radio and checkbox inputs using CSS

Feb 19
 
 
 
Custom radio and checkbox inputs using CSS

In my never ending quest to find weird and wonderful ways to abuse CSS and all its little intricacies, I have come up with a pretty good way of using CSS to create custom radio and checkbox inputs without JavaScript, that are accessible, keyboard controlled, don’t use any hacks and degrade nicely in non supporting browsers. The journey wasn’t easy and I was on the brink of filing it in the “to crazy” folder, never to be seen again. Luckily I had a brain wave that paid off and actually allowed this to be a very viable solution that degrades beautifully and works in 80% of the browsers. This is my story.

It’s a bug, no it’s intended…well actually it’s still a draft

So upon my initial investigation of how doing something like this would be possible, I came across what I initially thought was a bug with Firefox and IE8. Applying CSS generated content to form elements doesn’t work, turns out Firefox and IE8 are following the CSS3 draft specification as specified in the CSS3 Generated and Replaced Content Module.

The box model defines different rules for the layout of replaced elements than normal elements. Replaced elements do not have ‘::before‘ and ‘::after‘ pseudo-elements;…

Form elements fall under the “replaced elements” category and therefore don’t allow :before and :after pseudo-elements on them. However Safari, Chrome and Opera all allow generated content on form elements. Further to the odd behaviour Chrome and Safari will only apply generated content on checkboxes, radios and file inputs whereas Opera will allow it for all form elements, see test case.

You can see my initial attempt at creating custom radios and checkboxes. This applied the generated content directly to the inputs themselves. Open up the demo in Safari or Chrome to see it working. This presented yet another problem this time with Opera, clicking the radio or checkbox directly would never actually check the box whereas with Chrome and Safari the box would be checked and the custom replacement would change state accordingly. But if you clicked the label, which uses the for attribute to create the relationship to the corresponding input, it would check the input in Opera and change the custom check state correctly.

I then thought I would see if I could fix it by using some JavaScript to check the input onclick, this worked for Opera but stopped it working in Chrome and Safari as it was putting it in an indefinite indeterminate state, as it was checked then quickly unchecked by the JavaScript.

document.body.onclick = function (evt) {
    var node = evt.target;
 
    if(node.nodeName === "INPUT") {
        var isChecked = node.checked;
        (isChecked) ?
            isChecked = false :
	    isChecked = true;
    }
}

As there was no safe obvious way that didn’t involve browser sniffing or using bad object detection to determine if the browser behaved in this way. And the fact it was taking away from the whole point of this demo, to create a CSS only solution for custom forms, I scrapped my idea and went back to the drawing board.

Selectors, pseudo-classes & pseudo-elements

As you can see from the demo each radio and checkbox is replaced with a custom one. The difference here from my initial attempt, and to get around the fact you can’t apply generated content to form elements consistently, is to apply the generated content to the label rather than the input itself, and using some clever selectors I can determine the state of the radio/checkbox is in and adjust the custom replaced one accordingly. I also set the original input opacity to 0 so it won’t show through our custom one.

<p>
    <input type="radio" value="male" id="male" name="gender" />
    <label for="male">Male</label>
</p>

The HTML isn’t bloated and needs no extra mark-up

p:not(#foo) > input + label
{
    background: url(gr_custom-inputs.png) 0 -1px no-repeat;
    height: 16px;
    padding: 0 0 0 18px;
}

Basically this selector is looking for a label that is immediately preceded by a sibling input, that is a child of a paragraph that doesn’t have an id of foo and lastly it has the :before pseudo-element so we can add our custom radio input. The reason for the not selector is to not apply these styles in IE8, I’ll explain why further down.

Update: Thanks to Lea and Mr.MoOx for their suggestions this now uses a sprite image. Rather than insert the image in the content property, I apply a background and insert 3 non-breaking space characters, since the content property doesn’t accept named entities I used the unicode equivalent of \00a0. The reason I insert 3 is because Firefox 1.5 won’t show the full background unless I put 3 in there and using a fullstop and applying color: transparent doesn’t work in FF 1.5.

To get this working in older browsers such as Firefox 3 and down I use a negative margin to get it to sit in the right place. Support for absolutely positioned generated content was only recently added in Firefox 3.5+. I then adjust the newer browsers by offsetting the left value to be equivalent of the left margin.

Update 2: Thanks to Marius for demonstrating that the :before pseudo-element is superfluous and adding the background directly to the label itself with a few adjustments works just fine and removes the hacky need for using the content property with 3 non-breaking space.

I moved the previous demo and it’s source files to a legacy folder so you can still get them if you want.

Now all the radios have been replaced by our custom versions we need to be able to tell if the radio is checked so we can adjust our custom state.

p:not(#foo) > input[type=radio]:checked + label {
    background-position: 0 -241px;
}

Again this is the same as the previous selector with one difference, we add the :checked pseudo-class available in the CSS3 selectors module to determine the radios state in CSS and change it upon the user checking the radio.

Of course the control doesn’t end there we also utilise the :hover, :focus, :active & :disabled pseudo-classes to change the radio on hover, when it has focus (for keyboard support), when the input is active (click and hold your mouse cursor to see this state change) and when it’s disabled. Mixing this with the :checked pseudo-class lets us control all possible states of the radio input and gives us great control and flexibility that doesn’t require a mouse nor JavaScript to control the states.

p:not(#foo) > input[type=radio]:hover + label,
p:not(#foo) > input[type=radio]:focus + label,
p:not(#foo) > input[type=radio] + label:hover { 
    background-position: 0 -181px; 
}
p:not(#foo) > input[type=radio]:hover:checked + label,
p:not(#foo) > input[type=radio]:focus:checked + label,
p:not(#foo) > input[type=radio]:checked + label:hover  { 
    background-position: 0 -261px;
 }
p:not(#foo) > input[type=radio]:disabled + label,
p:not(#foo) > input[type=radio]:hover:disabled + label,
p:not(#foo) > input[type=radio]:focus:disabled + label,
p:not(#foo) > input[type=radio]:disabled + label:hover,
p:not(#foo) > input[type=radio]:disabled + label:hover:active { 
    background-position: 0 -221px; 
}
p:not(#foo) > input[type=radio]:disabled:checked + label,
p:not(#foo) > input[type=radio]:hover:disabled:checked + label,
p:not(#foo) > input[type=radio]:focus:disabled:checked + label,
p:not(#foo) > input[type=radio]:disabled:checked + label:hover,
p:not(#foo) > input[type=radio]:disabled:checked + label:hover:active {
     background-position: 0 -301px; 
}
p:not(#foo) > input[type=radio]:active + label,
p:not(#foo) > input[type=radio] + label:hover:active { 
    background-position: 0 -201px; 
}
p:not(#foo) > input[type=radio]:active:checked + label,
p:not(#foo) > input[type=radio]:checked + label:hover:active {
     background-position: 0 -281px; 
}

Another addition I have made to the CSS is also changing the input states when the user hovers, clicks or focuses on the label it will now change the input to reflect those actions.

IE8 is almost there

IE8 can do everything, except it doesn’t support the :checked pseudo-class and therefore makes this technique useless. So I use the not() pseudo-class, which IE8 doesn’t support, to work around this unfortunate lack of ability. Let’s hope IE9 adds the CSS3 selector module1. This of course degrades nicely in non-supporting browsers and fallback to the browser default form elements.

1 IE9 does support the CSS3 selector module so this technique has across the board support for all major browsers.

Accessible and friendly

CSS generated content doesn’t get in the way of a screen reader and they have a clear view of the form elements CSS generated content is no longer used it’s now a background image on the label rather than doing it on the generated content see update (I would appreciate any accessibility experts or screen reader users to please comment to correct or agree with me). Users, who have trouble operating a mouse or, like me, prefer navigating forms with the keyboard as it’s faster, aren’t left out. Tabbing through the inputs changes the states, pressing spacebar to check a radio or checkbox also changes the state. I also change the label colour and give it a text-shadow to give a nicer indication that the current input has focus.

The disabled and checked attributes work as intended with this solution and don’t require any trickery to achieve that.

<p>
    <input type="radio" disabled value="male" id="male" name="gender" />
    <label for="male">Male</label>
</p>
<p>
    <input type="radio" checked value="Female" id="female" name="gender" />
    <label for="female">Female</label>
</p>

As you can see from the above mark-up adding the disabled or checked attributes (disabled=”disabled” & checked=”checked” also work) will allow us to target those states using the :checked and :disabled pseudo-classes. As well as change the style if we use JavaScript to disable any inputs based on users actions.

Browser support and notes

As of writing the following browsers have been tested and known to work with the demo:

  • Firefox 1.5+
  • Opera 9.6+
  • Safari 3.2+*
  • iPhone/iPod Safari**
  • Chrome 4+
  • IE9+

Will run this demo through browsershots and update it accordingly if the browser support works in any lower versions mentioned

* This would work in Safari 3.2 except due to a bug. The checked pseudo-class will work just fine if it has the checked attribute on the input but won’t change the input state if the user checks the input with their mouse or keyboard (the actual input will check but the CSS state won’t update the custom input image).

* This now works in Safari 3.2 but, and a big but, the behaviour is quite bizarre. Clicking a radio or checkbox will change the custom state but clicking it again to uncheck won’t show until you have hovered away from or taken focus away from the input. If you have Safari 3.2 installed try the new demo to get a better understanding of what’s happening.

** To get the iPhone to work with this demo I had to apply the pointer-events CSS property. Since the input is actually sitting on top of the background image we no longer need to apply pointer events to the label.

p:not(#foo) > input + label
{
    pointer-events: none;
}

Here for legacy reasons no longer needed for iPhone support

Since having the generated content sit over the top of the actual checkbox, iPhone Safari needed a kick up the bum with the pointer-events property so we could click through the custom checkbox to the actual checkbox. Desktop Safari works fine without it.

Drawbacks

Resolved see update above. This technique has only 1 drawback I can think of, IE support is not a drawback for me, you can’t use a big sprite image to save all the radio and checkbox states, they need to be individual images. Using CSS generated content to insert an image doesn’t give you control of the image position like a background image does. The images are small in size and the initial load of each state shouldn’t be noticed. If however you wish to preload all the images take a look at my CSS based image preload technique. That technique will create quite a few http request depending on how many images you preload but since they’re small in size it shouldn’t be a major concern.

Short URL: http://cssn.in/ja/023

 
 
 

Post filed under: css.

Skip to comment form.

Comments

  1. You have two checkboxes with id=stop (“This is checked and disabled” and “Please make the CSS Ninja stop from trying to make me rich or poor”) so when you hover the second it actually applies the style to the wrong element; well, except when you hover the “checkbox”, in which case it’s OK.
    Might be a bug in Chrome 5-dev though (5.0.322.2 dev)

    In Firefox 3.6, label only becomes blue when you hover the checkbox/radio (without transition as it’s not yet supported); while in Opera 10.50 beta (rev. 3248) it changes on focus instead of hover !?

    Thomas Broyer, February 19th, 2010
  2. Great idea, as usual :D

    As for the sprites:
    http://leaverou.me/2010/02/cssninjas-custom-forms-revisited-to-work-with-css-sprites/

    I’m probably missing something but what is it?

    Lea Verou, February 19th, 2010
  3. For the css sprite, mayebe something like these will work ?

    .selector:before
    {
        content: " ";/* or &amp;nbsp; ? */
        font-size: 70px; /* just big enough*/
        overflow: hidden;
        width: 16px;
        height: 16px;
        background: url(radio_normal.png);
    }
    Mr.MoOx, February 19th, 2010
  4. @Thomas – thanks for pointing those out will update the demo when I get chance.

    It’s seems that the browser’s handle the hover on inputs differently, as you said. Will investigate further and do some updates to the article/demo.

    The Css Ninja, February 20th, 2010
  5. @Lea – As I said on your article brilliant. I did try a background but I never tried it with an invisible character in the content property so that’s why it didn’t work for me. Thanks!

    The Css Ninja, February 20th, 2010
  6. @Mr.MoOx – Seems you and Lea came up with the similar solution for sprites, thank you both. Makes this technique whole lot better now.

    The Css Ninja, February 20th, 2010
  7. Yeap, my solution wouldn’t work with Firefox 2 and below.
    It doesn’t support absolutely positioned generated content (as you pointed out yourself as well), so the position alone doesn’t force the generated content to appear like a block element.
    It doesn’t support the inline-block display value either (which was a bit redundant in my solution, but would help in this case, IF it was supported), so that doesn’t work either.
    So …it’s stuck being inline, with its character content dictating its width, as you pointed out yourself as well. :-(

    Lea Verou, February 20th, 2010
  8. Works great on my Android phone (which uses some version of Chrome). I use the trackball to “hover” from one field to the next so I see the fade effects.
    Also good example of CSS transitions that make it look like its using JavaScript when it’s not!

    The only nitpick I noticed was on my computer, clicking the checkboxes with the mouse, there is a few pixels of “dead zone” on the bottom of the checkbox– this probably can be fixed with padding or just making the box bigger..

    Michael Butler, February 21st, 2010
  9. Nice!

    Only real bug I get is that I’m seeing clipping of the bottom of the j/y/g characters in the line “Please make the CSS Ninja stop from trying to make me rich or poor”…

    I would also like critique the applied styling a little:

    1) The blue-text-on-selection effect is unexpected (i.e. compared to normal HTML forms) hence actually detracts from the overall user experience – it should apply the standard dotted outline instead.

    2) However, that’s not to say that the blue-text formatting is completely useless, I suggest that it would work well as a hover effect instead, though only if consistently applied to all form elements (i.e. graphically to the radio/check/text fields – perhaps using another state in the image state – in addition to being applied to the text labels that accompany them)

    MarcusT, February 21st, 2010
  10. Amazing.

    Dave, February 22nd, 2010
  11. @Michael – Great to hear it works on the android phone.

    Good pick up with the dead zone, just quickly testing with firebug if I put height: 16px on the input itself it will expand to the height of the custom input. Will have to investigate further to see if it works across the board, it should.

    The Css Ninja, February 22nd, 2010
  12. @MarcusT – The clipping would be because I set the line-height to be the same as the font size on the label, increasing or removing that should stop the character clipping.

    1) Yeah that makes sense, styling elements like that should be a lot more subtle than what I did but I wanted it to be obvious for this demo. That’s probably why I’m not a designer ;)

    The Css Ninja, February 22nd, 2010
  13. For the inline/block problem, maybe a blank.gif image for content will be a better solution ?

    Mr.MoOx, February 22nd, 2010
  14. Not a fan of that solution reminds of the spacer gif days, I don’t see the 3 non-breaking spaces as an issue.

    I went through the demo with a screen reader and it ignores generated content so it doesn’t get in the way.

    Also it worth noting that display: inline-block wasn’t added to firefox until 3.0, you could however do it with display: -moz-inline-block this allows me to only have to have 1 non-breaking space to display the generated content, without it being cut-off. But as stated in the MDC docs it’s very buggy and doesn’t actually behave like and inline-block should, it acts like block element and forces the label text on another line.

    The Css Ninja, February 23rd, 2010
  15. Nice job!

    In FF 3.0 in Linux (Fedora), probably due to Fedora’s fonts, the 3 spaces in the content property weren’t enough and all the checkboxes/radio images were clipped.

    I guess this is the downside of using characters to force width which doesn’t really feel like a very ‘accurate’ solution. Shame as always about IE too :|

    Nick, February 25th, 2010
  16. There’s still a problem with the clipping, but it’s not a visible one. In Safari (or anything else that uses Webkit) the clickable box or text is a few pixels higher than the visible content. If you click just above the checkbox (3px or less) it’s taken as input, while the bottom (4-7px) of the box or text doesn’t do anything.

    Safari 4.0.4 on Mac OS 10.6.2

    Nico, February 25th, 2010
  17. Great job. One thing I noticed is that if the text goes over 2 lines (i.e. make the screen smaller), the text disappears behind the checkbox/radiobutton.

    Ron Derksen, February 25th, 2010
  18. This ‘improvement’:

    1) Takes WAY too many lines of code to implement
    2) Is deeply questionable from a usability perspective (yes, form controls SHOULD look like the native widgets; style them lightly, if at all)
    3) Is not robust, cross-browser
    4) Smells deeply like a hack

    PLEASE don’t use this!

    Banned in Boston, February 25th, 2010
  19. have you tried using input[checked] instead of input:checked to get around the pseudoclasss support issues? According to PPK (http://www.quirksmode.org/css/contents.html), attribute selector support goes back to IE7.

    Ryan Cannon, February 25th, 2010
  20. @Nick – Yeah that was the down side of using a sprite background image. Compared to the previous solution I had of individual images which didn’t need a certain amount of characters to show the input in the older browsers that don’t support all CSS properties on generated content.

    @Nico – I have updated the demo to set a height on the input so the clickable area isn’t cut short at the bottom any more. I tested in Safari/Chrome on Windows and it seems OK to me. Can you let me know if you’re still having issues.

    @Ron – Good find. That can be fixed by removing the float: left on the label, that way when it wraps it won’t cut off the text.

    @Ryan – I got excited there for a second, while doing input[checked] works on the inputs that already have the checked attribute it doesn’t check the radio or input when I click it as there is no physical attribute on the input for the attribute selector to match against. I will investigate further but IE8 support still looks sketchy. Cheers!

    The Css Ninja, February 25th, 2010
  21. @Banned –

    Takes WAY too many lines of code to implement

    Certainly a valid point and in my example I was covering every possible state available in CSS. In reality 3 states would be sufficient; unchecked, checked and disabled this would obviously reduce the amount of CSS.

    Is deeply questionable from a usability perspective (yes, form controls SHOULD look like the native widgets; style them lightly, if at all)

    If you are doing user testing and you aren’t diverging from the browser default design drastically I don’t see this as a usability issue. I would like to here more feedback or even if someone has done a study on how users react, if at all, to forms controls that are different from the browser default styling?

    Is not robust, cross-browser

    It’s works across the board for CSS3 selector module supporting browsers and degrades back to browser default checkboxes in IE, could you extend further on why you think this is not robust?

    Smells deeply like a hack

    Again saying it and not demonstrating why doesn’t make your argument very strong. I’m using valid CSS3 selectors and no hacks are actually in the CSS file.

    The Css Ninja, February 25th, 2010
  22. And if you use http://www.keithclark.co.uk/labs/ie-css3/ to have the :checked in IE8 (and why not 6-7-8). ?

    Will it works ?

    Benjamin, February 25th, 2010
  23. I’m using valid CSS3 selectors and no hacks are actually in the CSS file.

    But the :not(#foo) is not very sexy :/

    Benjamin, February 25th, 2010
  24. @Benjamin – The :checked pseudo-class emulation in IE isn’t the problem it’s the CSS generated content which wasn’t added to IE until 8. You can very well use Keith Clarks’ ie-css3 solution to do this in IE8.

    But the :not(#foo) is not very sexy :/

    But it’s still a valid CSS3 selector… you could argue that all pseudo-class/elements are not sexy but they are damn useful.

    The Css Ninja, February 25th, 2010
  25. If you are doing user testing and you aren’t diverging from the browser default design drastically I don’t see this as a usability issue. I would like to here more feedback or even if someone has done a study on how users react, if at all, to forms controls that are different from the browser default styling?

    Visual _recognition_ at a glance (i.e., familiarity) is a key principle of usability — this what makes icons work (or, fail to work, when violated). In the live demo: the radio buttons look too much like bullets; the check boxes look like ‘empty’ icons (or square bullets). Admittedly, in the context of a form, a user will likely figure out what they are eventually, so this is not a huge problem. But it can slow users down and potentially cause confusion.

    It’s works across the board for CSS3 selector module supporting browsers and degrades back to browser default checkboxes in IE, could you extend further on why you think this is not robust?

    Again saying it and not demonstrating why doesn’t make your argument very strong. I’m using valid CSS3 selectors and no hacks are actually in the CSS file.

    I’m sorry, but when I see convoluted (if legal) stuff like this:

    p:not(#foo) > input + label:before { ... }” and:

    and this:

    The reason for the not selector is to not apply these styles in IE8, I’ll explain why further down.

    and this:

    The reason I insert 3 is because Firefox 1.5 won’t show the full background unless I put 3 in there and using a fullstop and applying color: transparent doesn’t work in FF 1.5. To get this working in older browsers such as Firefox 3 and down I use a negative margin to get it to sit in the right place. Support for absolutely positioned generated content was only recently added in Firefox 3.5+. I then adjust the newer browsers by offsetting the left value to be equivalent of the left margin.

    then I claim that it is not _robust_ because you’re having to tweak the CSS (and pretty extensively) to get it to work cross-browser.

    As far a labeling it a hack, I agree that that’s a subjective judgment. But, (not to boast) having: 23 years of software development experience, 17 years of Web experience, and 13 years of UX experience, one I feel qualified to make.

    ==========
    Please don’t take the above too harshly. I am impressed by the amount of effort you’ve put into this work and your willingness to discuss its merits. My concerns about the usability of it would be controlled by the restraint (or otherwise) that one might exhibit in using it. My concerns about the robustness of the CSS may eventually go away when older browsers die off (and, just perhaps, we get a new version of CSS with decent syntax).

    Banned in Boston, February 27th, 2010
  26. @Banned –

    Visual _recognition_ at a glance (i.e., familiarity) is a key principle of usability — this what makes icons work (or, fail to work, when violated). In the live demo: the radio buttons look too much like bullets; the check boxes look like ‘empty’ icons (or square bullets).

    I certainly never claimed to have any real design skills and I would say my radio and checkboxes show that. I was merely showing the technique with the design an afterthought; of course a real UX designer would obviously know this and employ the right design to not alienate their users with odd looking form elements.

    I’m sorry, but when I see convoluted (if legal) stuff like this:

    “p:not(#foo) > input + label:before { … }” and:

    I still stand by that selector, given it does look confusing to the non-developers, is completely valid and used correctly.

    However I do agree with you that the revised solution I made to incorporate a sprite image is quite hacky with the inserting of html entities in the content property. I find that my original solution that had individual images and didn’t require the non-breaking spaces to be inserted worked cross browser and didn’t require “hacks” like that.

    Please don’t take the above too harshly.

    I certainly haven’t. I welcome and thank you for taking the time to respond in a much more constructive matter, especially someone of your experience. Cheers.

    The Css Ninja, February 27th, 2010
  27. I don’t understand why you have to use :before. Can’t you simply style the label instead of inserting something in front of it? The only disadvantage to setting the background image on the label itself is that you cannot use sprite sheets (or if you do you need to use a column of sprites, and then you can’t change the height of the label). But this is a small prize to pay to making it even better than it is now. But maybe I just missed something…

    Marius Gundersen, March 3rd, 2010
  28. @Marius – That’s a pretty good point. However I just did some quick testing and put the background on the label rather than using :before to insert it and it seems the label becomes unclickable and won’t change the state of the input unless the input is clicked directly itself. It’s as if the for attribute relationship gets ignored, will have to look into it further.

    The Css Ninja, March 4th, 2010
  29. Genius, pure genius!

    Richard Le Poidevin, March 10th, 2010
  30. I’ve made a demo without :before, and it seems to work in the latest browsers on windows (haven’t tested on mac or linux). You can have a look at it at http://www.mariusgundersen.net/random/cssInput.html

    Marius Gundersen, March 12th, 2010
  31. Nice work Marius, will update my article and give you credits. Cheers!

    The Css Ninja, March 12th, 2010
  32. Demo does not work in IE 8 in any modes

    Serge, March 13th, 2010
  33. I pointed out in the article that this technique doesn’t work in IE8 because it does not support the checked pseudo-class. I noticed a small padding issue on the label in IE, is that what you’re referring to? It’s fixed now, demo and source files have been updated.

    The Css Ninja, March 13th, 2010
  34. Arrgh, don’t know how I am just seeing this site today for first time, but after seeing this and the other stuff posted, you realize how much work I need to do now!!!

    Lol, you have set me back and need to catch up, good stuff here.

    Thanks! :D

    Jared, March 31st, 2010
  35. Hi, and thx for sharing experience, this is a very good work :)

    I think there is a doubloon in the first 2 css rules (in red) :

    in the next rule there is two times “p:not(#foo) > input[type=radio]:focus + label” :

    p:not(#foo) > input[type=radio]:hover + label,
    p:not(#foo) > input[type=radio]:focus + label,
    p:not(#foo) > input[type=radio] + label:hover,
    p:not(#foo) > input[type=radio]:focus + label {
    background-position: 0 -181px;
    }

    and in this one, two times : “p:not(#foo) > input[type=radio]:focus:checked + label”

    p:not(#foo) > input[type=radio]:hover:checked + label,
    p:not(#foo) > input[type=radio]:focus:checked + label,
    p:not(#foo) > input[type=radio]:checked + label:hover,
    p:not(#foo) > input[type=radio]:focus:checked + label {
    background-position: 0 -261px;
    }

    dway, April 9th, 2010
  36. dway, thank you for picking up on that I have corrected the example code and updated the demo and source files.

    The Css Ninja, April 9th, 2010
  37. Pure AWesome. I love seeing articles like this, where the author is doing things just to see if he/she can. While this is indeed cool, I can’t personally see putting in the time to style a radio button. I with @banned in that people know what they are when they see the default styles, and over styling them can add some confusion. I am fine with some styling, but this seems way over-kill. Thank you though for doing it! Cause it is great to at least see how this could be done.

    Jeremy Carlson, April 15th, 2010
  38. works perfectly In opera mobIle

    andy, April 16th, 2010
  39. Hello,

    This technique is awesome, but I’ve found an accessibility issue.
    If you turn of images (or if you encounter network problems to load images), you can not be visually aware of the state of the inputs.

    This is due to the use of the opacity property to hide the inputs.

    Here is a solution to fix it :

    Instead of hiding the inputs by themselves, make the label hiding it by using the z-index property like this :

    p > input
    {
        padding: 0;
        margin: 0;
        height: 16px;
        width: 16px;
        float: left;
        position: absolute;
        left: 0;
        /* opacity: 0; /* Remove this */
        z-index: 1; /* Add this */
    }
    p > label 
    { 
        float: left; 
        line-height: 16px; 
        color: #fff; 
        padding: 0 0 0 18px;
        -moz-transition: color 1s ease; 
        -o-transition: color 1s ease; 
        -webkit-transition: color 1s ease; 
        transition: color 1s ease; 
        position: relative; /* Add this */ 
        z-index: 2; /*Add this*/ 
    }

    With this solution, you have to be sure that your label’s background is large enough to fully cover the input. Of course, if you have a design that require a transparent background, it will become tricky.

    Jeremie, April 16th, 2010
  40. @andy – Thanks Andy good to hear it works in Opera Mobile.

    @Jeremie – When I originally was working out how to do this I didn’t hide the inputs by setting their opacity but found that different browser rendered the radios slighty different with some peeking out behind the background image etc. However it’s certainly worth considering doing your technique as like you said if for whatever reason some images won’t load you can still see the old inputs.

    The Css Ninja, April 17th, 2010
  41. A very nice one, my problem now is that I’m trying to achive this result for a Drupal project I’m working on, and Drupal build forms in a way where input is a label’s child:

    
    

    I need some advice, I think you can be very helpfull here Ninja!!

    Kayo, June 28th, 2010
  42. @Kayo – You need to have the markup in a specific order for this to work cross browser. Unfortunately not being able to control how the markup is fed out will make this demo impossible to work.

    The Css Ninja, July 5th, 2010
  43. This is awesome ! Thanks for sharing ! BTW, I think you are not only a front-end developer but also a front-end designer !

    Sam, July 15th, 2010
  44. Hi Ninja, thank you for the good work and sharing it…
    I’m currently creating a website and i think that i’ll have to come up with a decision to sacrifice ie7 & ie8 :(
    i do have a question pls: is there a way to avoid adding the around the checkboxes/ radios ???

    have you done something similar for the select box? if not, do you know any good ones??

    Thank you so much
    Regards

    Reda, July 21st, 2010
  45. @Reda –

    …i’ll have to come up with a decision to sacrifice ie7 & ie8

    Keith Clark mentioned a couple of days ago that using his ie-css3 script worked in IE8 with most of my demos. Could give that try and just not support IE7 down.

    is there a way to avoid adding the around the checkboxes/ radios ???

    Did you miss a word there, not sure what you mean?

    The Css Ninja, July 22nd, 2010

Trackbacks

  1. [...] I read today CSS Ninja’s (Ryan Sheddon’s) brilliant new technique about the creation of custom checkboxes and radio buttons with CSS alone. [...]

    CSSNinja’s custom forms revisited to work with CSS sprites « Lea Verou, February 19th, 2010
  2. [...] Phone 7 Series is a game-changer Windows Phone 7 development policies and guidelines leaked? Custom radio and checkbox inputs using CSS OneRiot Launches New API for Real-Time Search and Introduces Twitter-Style Ads 50 Useful Coding [...]

    Foursquare respond to privacy issues – Web Review 19/02/10 « Vexed Digital Blog, February 19th, 2010
  3. [...] A healthy dose of useful CSS links CSSVault Object Oriented CSS Guide to CSS support for Email Clients W3C CSS class names CSS Ninja [...]

    General CSS tips/tricks « Pat IT Dude Blog, February 24th, 2010
  4. [...] Seddon, also referred to as the CSS Ninja, has created some impressive custom radio and checkbox inputs with pure CSS. The technique, which he posted late last week, is using some nifty selectors and pseudo-madness to [...]

    Custom radio inputs using pure CSS, February 25th, 2010
  5. [...] “the CSS Ninja” goes from here to explain his quest which includes fun CSS such as: PLAIN TEXT [...]

    Ajaxian » Custom checkbox and radio buttons using CSS, February 25th, 2010
  6. [...] “the CSS Ninja” goes from here to explain his quest which includes fun CSS such as: PLAIN TEXT [...]

    Custom checkbox and radio buttons using CSS « dot nikis, February 25th, 2010
  7. [...] Webentwicklung: Custom radio and checkbox inputs using CSS [...]

    Destillat #10 | duetsch.info - Open Source, Wet-, Web-, Software, February 26th, 2010
  8. [...] Custom radio and checkbox inputs using CSS [...]

    Link Love: CSS Tricks, March 24th, 2010
  9. [...] Custom radio and checkbox inputs using CSS [...]

    Link Love: CSS Tricks « Web Design, April 9th, 2010
  10. [...] things that previously required JavaScript, in pure CSS (no JavaScript whatsoever). This includes cross-browser CSS-styled checkboxes, a lightbox in pure CSS, and an easy way to preload images using [...]

    My favourite web development blogs « Daniel15's Blog, April 24th, 2010
  11. [...] 8.Custom radio and checkbox inputs using CSS Way of using CSS to create custom radio and checkbox inputs without JavaScript, that are accessible andkeyboard controlled. DEMO [...]

    The Power Of CSS:40 Totally Pure CSS Solutions Without Javascript | DesignBeep, July 13th, 2010
  12. [...] 8.Custom radio and checkbox inputs using CSS Way of using CSS to create custom radio and checkbox inputs without JavaScript, that are accessible andkeyboard controlled. DEMO [...]

    The Power Of CSS:40 Totally Pure CSS Effects With Demos | Afif Fattouh - Web Specialist, July 21st, 2010

Leave a comment