iOS7 Style Pure CSS Toggle

iOS7 Style Pure CSS Toggle

Posted on Sep 19, 2013

I see these switch-style toggles everywhere lately - maybe it's the influence that iOS has on the design world. The source of the trend aside, I see a lot of folks using javascript to create them. This seems a little silly to me, since the HTML and CSS to accomplish them already exists (and is well supported to boot!). Have I piqued your curiosity? Read on, intrepid coder.

As with a lot of my smaller tutorials, we're going to be keeping the code for this one as simple as humanly possible. We're using one html input (a checkbox) along with its label. To style the element, we're using one CSS class and a couple of pseudo-elements along with the :checked pseudo-class.

An important thing to note for this switch is that the animation (using the CSS3 transition property) is only supported on some browsers, as we're applying it to the pseudo-elements. Chris Coyier over at CSS-Tricks.com has a handy table (if a little bit dated at this point) showing the support for this.

Enough jabbering - on to the code.

First, we establish the building block for the switch: a simple checkbox.

<input type="checkbox" name="toggle" id="toggle">
<label for="toggle"></label>

Got that? Ok—let's make it pretty. First, we're going to get rid of that pesky default checkbox. Each browser styles it a little differently, and we want complete control of the look, so we're going to take away it's width and height and then make it totally transparent. This means that the checkbox is still functional (that part is important), but not visible, and not affecting other elements' placement.

input#toggle {
max-height: 0;
max-width: 0;
opacity: 0;
}

Good stuff. Now that we've got that taken care of, we can style the actual switch. We're using the checkbox's label for this. There are three parts to the switch:

  • The container (this uses the actual label)
  • The switch itself (this uses the :after pseudo-element)
  • The switch's background (this uses the :before pseudo-element)
input#toggle + label {
display: block;
position: relative;
box-shadow: inset 0 0 0px 1px #d5d5d5;
text-indent: -5000px;
height: 30px;
width: 50px;
border-radius: 15px;
}

input#toggle + label:before {
content: "";
position: absolute;
display: block;
height: 30px;
width: 30px;
top: 0;
left: 0;
border-radius: 15px;
background: rgba(19,191,17,0);
-moz-transition: .25s ease-in-out;
-webkit-transition: .25s ease-in-out;
transition: .25s ease-in-out;
}

input#toggle + label:after {
content: "";
position: absolute;
display: block;
height: 30px;
width: 30px;
top: 0;
left: 0px;
border-radius: 15px;
background: white;
box-shadow: inset 0 0 0 1px rgba(0,0,0,.2), 0 2px 4px rgba(0,0,0,.2);
-moz-transition: .25s ease-in-out;
-webkit-transition: .25s ease-in-out;
transition: .25s ease-in-out;
}

A few things about that chunk of code. First off, you may notice that I'm using an inset box-shadow instead of border for my outlines. This allows me to have borders that overlap each other, so that the switch is flush to each side of its container. I'm also using CSS3 transitions to animate the switch, and as mentioned above, this isn't as supported as it should be for pseudo-elements (although support is getting better). Lastly, I'm using border-radius to round out the corners.

Now let's style the active state:

input#toggle:checked + label:before {
width: 50px;
background: rgba(19,191,17,1);
}

input#toggle:checked + label:after {
left: 20px;
box-shadow: inset 0 0 0 1px rgba(19,191,17,1), 0 2px 4px rgba(0,0,0,.2);
}

This moves the switch 20 pixels to the right and widens the background so that it is visible behind the switch, while also changing the inset box-shadow to the same color as the background. And presto—a beautiful and functional switch for your next project. Feel free to check out the demo!

Like what you see?


There are 26 comments. Add Yours.

*

*

Notify me of new replies

Allowed tags: <b><i><br>

*

Comments

  1. Mazhar Ahmed

    Mazhar Ahmed

    Oct 12, 2013 at 11:36 AM
    Awesome, I just made my own iCheckBox today and now found yours. It's great.

    Reply to Mazhar Ahmed

  2. Ramon Y

    Ramon Y

    Dec 13, 2013 at 02:53 PM
    This was a good start and really helped me out. But you might find this to be more accurate to what Apple's toggle looks like, and I removed the need for the label. Enjoy.

    http://www.cyberantics.net/toggle.html

    Reply to Ramon Y

    1. Jesse

      Jesse

      Dec 17, 2013 at 10:14 AM
      Thanks Ramon - that is quite nice! The one thing you may want to be wary of is using any input like this:

      < input >< / input >

      That closing tag is not the correct usage of the input html element. Technically, it allows you to eliminate the label but isn't the proper way to write input. If you are writing XHTML (your demo isn't - it's just using html5), then your closing tag would be "< input / >".

      For more info on this, check here: http://www.w3schools.com/tags/tag_input.asp

      Additionally, you may want to use CSS to remove the outline around the checkbox on :focus and :active. Just a thought!

      Thanks again for your feedback and the interesting tweak. Keep up the awesome work.

  3. Ben

    Ben

    Jan 17, 2014 at 02:43 AM
    Very clean. I dropped two on a page. They don't play nice together. How would it work with two on the same page?

    Reply to Ben

    1. Jesse

      Jesse

      Jan 23, 2014 at 01:13 PM
      It's important to remember to include unique values and ids for each checkbox - that is not included in the demo. Also, each label should reference its unique checkbox id. For instance, here is a set of two checkboxes that belong to the same group, but operate independently:

      <input type="checkbox" name="checkbox-group" id="red-id" value="red"/>
      <label for="red-id">Red</label>
      <input type="checkbox" name="checkbox-group" id="blue-id" value="blue"/>
      <label for="blue-id">Blue</label>


      Hope this helps!

    2. Vytas

      Vytas

      Mar 29, 2014 at 08:45 AM
      Looks great, however I can't make working two together... Can you present demo of two working together?

      Thanks

    3. Jesse

      Jesse

      Mar 29, 2014 at 08:53 AM
      I'll see what I can do!

    4. Jesse

      Jesse

      May 22, 2014 at 10:55 AM
      The demo has been updated with two toggles on the same page. It was done using the advice I initially gave to Ben above.

  4. Andreas Uppström

    Andreas Uppström

    Mar 19, 2014 at 06:33 AM
    Very nice, works "out of the box"!
    Thanks!

    Reply to Andreas Uppström

    1. Jesse

      Jesse

      Mar 19, 2014 at 07:46 AM
      Thanks, Andreas! There's a lot of these floating around, but I'm most happy with my solution (not necessarily better, but more to my own preference).

  5. John

    John

    May 22, 2014 at 12:52 PM
    I know this is an old post, but how would you go about adding text inside the switch that is centered or having text show up next to it that is inline with the switch? I've managed to get text inside but it doesn't center the text vertically.

    Reply to John

    1. Jesse

      Jesse

      May 22, 2014 at 01:47 PM
      You may want to play around with display:table and display:table-cell. That's how I typically achieve vertically centered items. Either that, or set the line-height of your text to the same height as your switch.

    2. John

      John

      May 22, 2014 at 03:55 PM
      Setting the line-height worked great! thanks!

  6. Curtis

    Curtis

    Jun 04, 2014 at 12:38 PM
    I love this but i'll have to try to figure out a solution for IE8.

    Reply to Curtis

    1. Jesse

      Jesse

      Jun 04, 2014 at 12:50 PM
      I would recommend CSS3PIE. Works quite nicely to force IE to behave like a respectable browser.

  7. lynn comer

    lynn comer

    Jun 19, 2014 at 01:12 PM
    Thanks for the demo with 2 toggles on the same page. When I try that with id=toggle1 and id=toggle2 so that I'm using unique ids, the "input#toggle doesn't work on anything other than "toggle". Can you help? Looks great, btw.

    Reply to lynn comer

    1. Jesse

      Jesse

      Jun 19, 2014 at 01:24 PM
      You need to change the CSS reference from an id to a class, and reference all toggles in your html with that class.

    2. Lynn Comer

      Lynn Comer

      Jun 19, 2014 at 01:35 PM
      That did it! Should have thought of it. Thanks for a great design!

    3. Jesse

      Jesse

      Jun 19, 2014 at 01:48 PM
      Glad to help :)

  8. Stephen Bayer

    Stephen Bayer

    Jun 26, 2014 at 05:08 PM
    This is very nice, except for the fact that you lose the label text which is very important in most cases since a row of toggle switches doesn't really help if the user doesn't know what they are for. I've been mucking around with the css trying to get the label to be visible under the "toggle control" without success. Is there any suggestion as to dealing with this type of situation.

    Reply to Stephen Bayer

    1. stephen bayer

      stephen bayer

      Jun 26, 2014 at 05:33 PM
      Got it! The text-indent "removes" the text by moving really far off the side of the screen. Instead, the color of the text can be made with an opacity of 0 and a vertical text shadow that displays under the button. Vendor prefixes are also in order, as well as fall back for browsers that do not support these techniques. But if the user agent already knows about sudo classes such as :before and :after, it will probably have some support for color opacity and text-shadow.


      input#toggle + label {
      display: block;
      position: relative;
      box-shadow: inset 0 0 0px 1px #d5d5d5;
      color: rgba(255, 255, 255, 0);
      text-shadow: 0 35px rgba(0,0,0,1);
      height: 30px;
      width: 50px;
      border-radius: 15px;
      }

    2. Jesse

      Jesse

      Jun 30, 2014 at 09:29 AM
      Very nice, Stephen! If you ever want to add support for pseudo elements like :before and :after you should check out CSS3Pie ( http://css3pie.com/ ). Thanks for your awesome input!

    3. Jesse

      Jesse

      Jul 21, 2014 at 04:39 PM
      Actually revisited this post on Codepen and styled a version with on and off state labels. You should check it out if you have a moment!

      http://codepen.io/designcouch/pen/sDAvk

  9. Nazeer Basha Shaik

    Nazeer Basha Shaik

    Jul 09, 2014 at 03:41 AM
    Awesome work man.... Keep it up.. God always with U.. :-)

    Reply to Nazeer Basha Shaik

    1. Jesse

      Jesse

      Jul 09, 2014 at 10:57 AM
      Thank you kind sir - I aim to please!

  10. Rami

    Rami

    Aug 31, 2014 at 11:13 AM
    it's brilliant thank u

    Reply to Rami