iOS7 Style Pure CSS Toggle

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.

html
<div class="wrapper">
  <input type="checkbox" name="toggle" id="toggle">
  <label for="toggle"></label>
</div>

See the Pen qdBErE by Jesse Couch (@designcouch) on CodePen.

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.

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

See the Pen 9977d37b52c36f41f3b23f0642dcb7a2 by Jesse Couch (@designcouch) on CodePen.

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:

css
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;
}

See the Pen a8d0fe979771e1e40e2d346fe90daeb5 by Jesse Couch (@designcouch) on CodePen.

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:

css
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);
}

See the Pen f486cd7b1cc27ee2b7025a8764d0e4fd by Jesse Couch (@designcouch) on CodePen.

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.

demo

See the Pen qdBErE by Jesse Couch (@designcouch) on CodePen.

Did I help you out?

Read More

←  Responsive CSS3 Lightbox with No Javascript My Take on iOS7  →

There are 27 comments. Add Yours.

A Note from the Moderator

Thanks for taking the time to comment! I'll respond as quickly as possible if necessary. In the meantime, please keep the following in mind:

  • All comments must be appropriate. I'll delete 'em if you get nasty.
  • Please allow for response time. I'm here as much as possible, but can't always respond as quickly as some would like.
  • Please stay on topic.
  • I don't work for free—if you want custom work, feel free to get in touch and I'll write up a quote!
  1. Mazhar Ahmed

    Mazhar Ahmed

    Oct 12, 2013

    Awesome, I just made my own iCheckBox today and now found yours. It's great.

    Reply to Mazhar

  2. Ramon Y

    Ramon Y

    Dec 13, 2013

    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

    1. Jesse

      Jesse

      Dec 17, 2013

      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

    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

      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

      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

      I'll see what I can do!

    4. Jesse

      Jesse

      May 22, 2014

      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

    Very nice, works "out of the box"!
    Thanks!

    Reply to Andreas

    1. Jesse

      Jesse

      Mar 19, 2014

      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

    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

      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

      Setting the line-height worked great! thanks!

  6. Curtis

    Curtis

    Jun 04, 2014

    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

      I would recommend CSS3PIE. Works quite nicely to force IE to behave like a respectable browser.

  7. lynn comer

    lynn comer

    Jun 19, 2014

    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

    1. Jesse

      Jesse

      Jun 19, 2014

      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

      That did it! Should have thought of it. Thanks for a great design!

    3. Jesse

      Jesse

      Jun 19, 2014

      Glad to help :)

  8. Stephen Bayer

    Stephen Bayer

    Jun 26, 2014

    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

    1. stephen bayer

      stephen bayer

      Jun 26, 2014

      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

      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

      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

    Awesome work man.... Keep it up.. God always with U.. :-)

    Reply to Nazeer

    1. Jesse

      Jesse

      Jul 09, 2014

      Thank you kind sir - I aim to please!

  10. Rami

    Rami

    Aug 31, 2014

    it's brilliant thank u

    Reply to Rami

  11. Zasjoe

    Zasjoe

    Nov 05, 2014

    Very nice toggle buttons! I like that "checked" pseudo-class in CSS! It allows to do many things! Anyways, here is one more example of it:
    http://basicuse.net/articles/pl/textile/html_css/styling_checkbox_as_toggle_button_using_only_css3
    I think, it works the same way as yours.

    Reply to Zasjoe