Even Better CSS3 Toggle Switches!

Contributing Editor

Many of you liked my previous article, How to Create a Toggle Switch in CSS3. However, a few issues were raised in the comments and on Twitter

  1. How do you apply toggles to radio buttons?
  2. Can accessibility be improved?
  3. Why doesn’t it work on older mobile Webkit browsers?

I’ve made some improvements, so please view the demonstration page and the HTML/CSS code…

Radio Button Support

An easy one to start with. Radio buttons function almost identically to checkboxes so we can simply apply a class of “switch” to every input to make it work, e.g.

<div>
<input type="radio" id="radio1" name="radio" class="switch" />
<label for="radio1">first radio button</label>
</div>

<div>
<input type="radio" id="radio2" name="radio" class="switch" checked="checked" />
<label for="radio2">second radio button</label>
</div>

<div>	
<input type="radio" id="radio3" name="radio" class="switch" />
<label for="radio3">third radio button</label>
</div>

It’s very satisfying to see two switches alter position at the same time!

Amended Accessibility

Richard from Accessible Web Design raised a couple of concerns. First, the switches change between red and green; if you’re color-blind, it would not be easy to determine whether the switch was on or off. To remedy the problem, I’ve added a check and cross character to the background:

toggle characters

No additional element were required — I simply used a cross character instead of a space and positioned it on the right of the background using text-indent:

input.switch:empty ~ label:before
{
	content: '2718';
	text-indent: 2.4em;
	color: #900;
}

When the checkbox/radio is checked, it changes to a check character and is moved to the left of the background:

input.switch:checked ~ label:before
{
  content: '2714';
  text-indent: 0.5em;
  color: #6f6;
}

Cross-Browser CSS3 Animation
Originally, I placed the check/cross character on the white switch itself. This is complex for the browser since it must create a transition between two different characters. Firefox worked, but Chrome and IE10 take an easier route: they abandon the animation completely! It appears that Webkit and Trident will not permit animation on a pseudo element if its content is changing — even if you explicitly state that only the margin or color should be animated.

To address the issue, I applied the check/cross to the :before toggle background and removed its transition effect (the color will not smoothly change, but it’s hardly noticeable). Only the white :after switch position is animated now.

The next accessibility issue: keyboard focus. The previous toggles were difficult to use with keyboard only so I’ve applied a different label color and a box shadow to the toggle when it has focus:

input.switch:focus ~ label
{
  color: #000;
}

input.switch:focus ~ label:before
{
  box-shadow: 0 0 0 3px #999;
}

The result is possibly a little too subtle, but it’s easy to add your own effects:

toggle focus

The focus effect works in Firefox, IE and Opera — but fails in Chrome 26? It looks like a browser bug unless anyone knows differently?

More Webkit Woes

The final problem: the toggle switches fail in mobile browsers using older versions of Webkit such as Safari on the iPad 1.0 and the Android browser. The engine supports labels, is happy with :checkbox selectors and displays the initial state, but doesn’t want to modify pseudo elements after the initial page load. I even broke my own requirements and added a little JavaScript, but the browser laughed at my feeble attempts and wouldn’t budge.

Pseudo element animation has only been added to Webkit recently. It’s frustrating and, unlike the old IE6/7 days, it’s difficult to find workarounds which don’t adversely affect other browsers.

Anyway, assuming legacy Webkit users aren’t part of your demographic, please use the HTML/CSS code however you like. Alternatively, you’ll need to add further (real) elements or JavaScript to make it work.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Ondreas

    Really nice & handy snippet, Craig! I’ve test it on my Android 2.3.4 (I know, quite old) and it works flawlessly on latest Firefox 20.0.1 & Firefox Beta 21.0; Opera 12.10 works too but would need some tweaks for CSS3 transitions. Mobile Chrome is not available for my device so I test it on Dolphin Browser which uses Webkit engine and (as you have mentioned) it fails completely. I’ll try to find some time to play with it. It would be great to find a way to make it work everywhere.

    • http://www.optimalworks.net/ Craig Buckler

      Thanks Ondreas. I was hoping to solve it in CSS alone but I suspect the most viable option is to use a little JS to append a few more nodes and animate those.

  • http://tipsbloggerdancomputer.blogspot.com tips bloger dan computer

    tanks for sharing

  • James

    I don’t see any animation in Opera 12.15 but as I often change lots of browser settings I don’t know whether it’s my install and setup causing that.

    • http://www.optimalworks.net/ Craig Buckler

      Opera is a little way behind the other browsers in CSS3 animation support. All that should change when they adopt Blink.

  • Norbert Sienkiewicz

    On default web browser in android 4.1.2 is also not working

    • http://www.optimalworks.net/ Craig Buckler

      Unfortunately, that’s because it uses an older webkit engine. Android Chrome is fine … and it’s rumored to become the next default browser on the OS.

  • http://accessibleweb.eu Richard

    Thanks for the update Craig, and thanks for the mention. Definitely much improved from an accessibility point of view. If I was being picky I would add a couple of things:
    1) The colour contrast of the symbols against the background could be improved. A white (or light colour) cross and a black (or dark colour tick) would work, however it seems a little counter-intuitive. Could instead be done with the same colour symbols but a white or black border around them.
    2) It is fun to be able to operate radio buttons in this way, but for keyboard users it means changing behaviour between using the checkbox version and the radio button version (tab then spacebar to go through and set the checkboxes, but cursor keys to change the radio buttons then tab to move on). Not a big deal but a bit of a usability issue along the “don’t make me think” lines.

    Thanks again for the update. Sharing and improving these things is what makes the web improve for everyone.

    • http://www.hugwebdesign.com Daniel Hug

      Richard,

      You don’t have to use a mouse to navigate through radio buttons. When radio buttons are operating in a group (they have the same value for their name attribute), keyboard users can use their up and down arrows to toggle the selected value.

  • https://plus.google.com/u/0/107814904974476592421/ netikseo

    Nice, I was wondering how to add text to the toggles on a previous post as it’s more user friendly and this post explain how. Thanks!
    Also from usability point of view when I see toggle switch on iPad I want to “slide” it and after several unsuccessful attempts I figure out I need to tick it. :) Thing to consider for mobile devices…:)