Creating a simple, accessible on/off switch
Intro
This presentation is based on a simple GitHub Repo and page available here:
Checkbox and radio button switch: https://russmaxdesign.github.io/switch-checkbox/ Github: https://github.com/russmaxdesign/switch- checkbox
During this presentation, I’m going to ask you some questions - which you can answer in the chat window.
I'll be giving away three SitePoint Premium annual memberships as prizes to the best/quickest answers.
That gives you unrestricted access to over $20,000 worth of SitePoint books and courses! https://www.sitepoint.com/ premium/
I want to start with a couple of accessibility-related questions.
And yes, these are incredibly easy, “prize-winnable” questions.
Question 1: What is the easiest and most effective way of identifying common accessibility problems in your site/ app?
Answer
Unplug the mouse The easiest and most effective way to check your site is using keyboard-only.
A large number of users rely on key-strokes (TAB, ARROW, ENTER, SPACE) or the equivalent of these keystrokes in order to navigate and interact with sites/apps.
If you cannot navigate or interact with your site/app using keystrokes only, then your site is potentially inaccessible to a large number of users.
Question 2: Why is this one of the most evil CSS rules you could ever write? *:focus  {  outline:  none;  }
Answer
Because this rule make it hard, if not impossible, for keyboard-only users to see which element is in focus and therefore very hard to navigate and interact with your site/app.
Time to explore how to style a simple radio button or checkbox!
Custom radios & checkboxes
Web designers and developers have always struggled with how to customise radio buttons and checkboxes.
The main issue is that radio buttons and checkboxes are notoriously hard to style - especially across multiple browsers and devices.
In the past, some developers resorted to JavaScript-based solutions to solve this problem.
In some cases this involved using JavaScript to remove the original radio or checkbox element making the end result inaccessible for a wide range of assistive technologies.
A solution
It is possible to style these elements without having to use JavaScript. And more importantly, we can make the end result accessible.
Let’s take a simple example of an on/off switch that can be applied to either radio or checkbox elements:
unchecked checked
The solution I’m about to demo, has five key accessibility features.
Well… many of these are not really features, they are just default behaviours that should not be overridden.
Feature 1: We will use the appropriate semantic elements - input and label elements. We will explicitly associate these elements using matching “for" and "id" values.
Feature 2: The label content can be used to describe the purpose of each switch for screen readers. This content is hidden off-screen.
Feature 3: We will make the two different states (“on” and “off”) clearly distinguishable using a tick icon for the “on” state. This will aid colour- blind users and some types of cognitive-impaired users.
(Keeping in mind that we should never use “color alone” to signal important information.)
unchecked checked
Feature 4: Because we are using native elements, the default keyboard behaviour will still be available. (Users can select a radio button or checkbox using the SPACE bar).
Feature 5: We will make the focus and hover states clearly visible. The focus state is especially important for keyboard only users.
checked checked hover checked focus
The markup
<div  class="switch">      <input          class="switch__control"          type="radio"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> input label
<div  class="switch">      <input          class="switch__control"          type="radio"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> radio
<div  class="switch">      <input          class="switch__control"          type="checkbox"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> checkbox
<div  class="switch">      <input          class="switch__control"          type="radio"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> id for
The class names
We will use BEM-like class names as these allow us to see the relationship between the parent element, descendant elements and modifiers.
/*  parent  module  */   .switch  {  }   /*  parent  modifiers  */   .switch-­‐-­‐xl  {  }   .switch-­‐-­‐lg  {  }   .switch-­‐-­‐md  {  }   .switch-­‐-­‐sm  {  }   .switch-­‐-­‐xs  {  }
/*  parent  module  */   .switch  {  }   /*  descendants  of  parent  module  */   .switch__control  {  }   .switch__label  {  }   .switch__content  {  }
How does it work
We can use the parent container (“switch”) to create the overall dimensions of the switch.
Parent Container “switch”
The radio button or checkbox control (“switch__control”) is then positioned on top of the parent. It will be given the same dimensions as the parent.
Control “switch__control”
The label (“switch__label”) is placed on top of the radio button and also given the same dimensions as the parent. We are hiding the control under the label.
We will then style the background of the label to look like a switch - including adding rounded corners and our background icon.
Label “switch__label”
And finally, the label content (“switch__content”) is hidden off screen so that it is available for screen readers, but does not clutter the visual appearance of the switch.
Adding states
Checkbox and radio button elements can be manually changed by users - from unchecked to checked etc.
These elements can also be given predefined boolean “checked” and “disabled” attributes.
<!-­‐-­‐  no  additional  attributes  -­‐-­‐>   <input  type="checkbox">   <!-­‐-­‐  boolean  checked  attribue  -­‐-­‐>   <input  type="checkbox"  checked>   <!-­‐-­‐  boolean  disabled  attribute  -­‐-­‐>   <input  type="checkbox"  disabled>
However, for this solution, most of the styling is applied to the label element, rather than the input.
Unfortunately, the label element has no checked, unchecked or disabled state of its own.
We can get around this using adjacent sibling selectors, which target any label element that is adjacent to (comes directly after) the input.
/*  unchecked  input  */   .switch__control  +  label  {  }   /*  checked  input  */   .switch__control:checked  +  label  {  }   /*  disabled  input  */   .switch__control[disabled]  +  label  {  }
unchecked checked disabled
We also want to style the :focus and :hover states of the switch, which can also be done using adjacent-sibling selectors.
/*  unchecked  input  */   .switch__control:hover  +  label  {  }   .switch__control:focus  +  label  {  }   /*  checked  input  */   .switch__control:checked:hover  +  label  {  }   .switch__control:checked:focus  +  label  {  }
unchecked hover unchecked focus unchecked checked checked hover checked focus disabled
SASS variables
Time for our final “prize-winnable” question (and yes, this one is also super-easy to answer)…
Question 3: Why would we want to be able to control all of the dimensions of our switch using one master SASS variable?
Answer
Because this makes it easier to maintain and to scale as needed.
We can define this one master variable by dividing our switch into scalable units.
12x 6x 4x 1x
So, we have four different variables for the dimensions: - switch width - switch height - toggle width/height - gutter (space) around the toggle
$switch-­‐width:      3em;   $switch-­‐height:    ($switch-­‐width  /  2);          /*  1.5em  */   $toggle-­‐width:      ($switch-­‐width  /  3);            /*  1em  */   $toggle-­‐gutter:    ($switch-­‐width  /  12);        /*  .25em  */
Now it becomes easy to create a range of size variations, just by resetting the font-size.
$switch-­‐xl:    1.6em;   $switch-­‐lg:    1.4em;   $switch-­‐md:    1.2em;   $switch-­‐sm:    1em;   $switch-­‐xs:    .8em;
We can also set some quick variables for each of the background-colors used in different states.
$color-­‐toggle:                      #fff;   $color-­‐unchecked-­‐static:  #aaa;   $color-­‐unchecked-­‐hover:    #777;   $color-­‐checked-­‐static:      #00a000;   $color-­‐checked-­‐hover:        #006e00;   $color-­‐disabled:                  #ddd;
Transitions
I’m generally not a fan of transitions or animations unless they are being used to help “tell the story” of a UI component - help users understand what is happening.
Transitions should not draw attention to themselves. Ideally they should be simple and subtle.
For the checkbox, we could do a very simple transition to animate the switch from unchecked to checked - to help users understand what has happened.
We can do this by transitioning the “left” property as it changes from unchecked to checked.
.switch__label:after  {   left:  $toggle-­‐gutter;   transition:  left  .04s;   }   .switch__control:checked  +  label:after  {      left:  $switch-­‐height  +  $toggle-­‐gutter;   }
We can also softly animate the background-color to avoid a jarring change.
.switch__label  {   background:  $color-­‐unchecked-­‐static;   transition:  background  .2s;   }   .switch__control:hover  +  label,   .switch__control:focus  +  label  {      background:  $color-­‐unchecked-­‐hover;   }  
Demos
Checkbox and radio button switch: https://russmaxdesign.github.io/switch-checkbox/ Github: https://github.com/russmaxdesign/switch- checkbox
A simple, accessible language switcher module: https://russmaxdesign.github.io/language- switcher/ Github: https://github.com/russmaxdesign/language- switcher
Upvote - downvote module: https://russmaxdesign.github.io/upvote-downvote/ Github: https://github.com/russmaxdesign/upvote- downvote
Russ Weakley Max Design Site: maxdesign.com.au Twitter: twitter.com/russmaxdesign Slideshare: slideshare.net/maxdesign Linkedin: linkedin.com/in/russweakley

Creating a Simple, Accessible On/Off Switch

  • 1.
    Creating a simple,accessible on/off switch
  • 2.
  • 3.
    This presentation isbased on a simple GitHub Repo and page available here:
  • 4.
    Checkbox and radiobutton switch: https://russmaxdesign.github.io/switch-checkbox/ Github: https://github.com/russmaxdesign/switch- checkbox
  • 5.
    During this presentation,I’m going to ask you some questions - which you can answer in the chat window.
  • 6.
    I'll be givingaway three SitePoint Premium annual memberships as prizes to the best/quickest answers.
  • 7.
    That gives youunrestricted access to over $20,000 worth of SitePoint books and courses! https://www.sitepoint.com/ premium/
  • 8.
    I want tostart with a couple of accessibility-related questions.
  • 9.
    And yes, theseare incredibly easy, “prize-winnable” questions.
  • 10.
    Question 1: What isthe easiest and most effective way of identifying common accessibility problems in your site/ app?
  • 11.
  • 12.
    Unplug the mouse Theeasiest and most effective way to check your site is using keyboard-only.
  • 13.
    A large numberof users rely on key-strokes (TAB, ARROW, ENTER, SPACE) or the equivalent of these keystrokes in order to navigate and interact with sites/apps.
  • 14.
    If you cannotnavigate or interact with your site/app using keystrokes only, then your site is potentially inaccessible to a large number of users.
  • 15.
    Question 2: Why isthis one of the most evil CSS rules you could ever write? *:focus  {  outline:  none;  }
  • 16.
  • 17.
    Because this rulemake it hard, if not impossible, for keyboard-only users to see which element is in focus and therefore very hard to navigate and interact with your site/app.
  • 18.
    Time to explorehow to style a simple radio button or checkbox!
  • 19.
  • 20.
    Web designers anddevelopers have always struggled with how to customise radio buttons and checkboxes.
  • 22.
    The main issueis that radio buttons and checkboxes are notoriously hard to style - especially across multiple browsers and devices.
  • 23.
    In the past,some developers resorted to JavaScript-based solutions to solve this problem.
  • 24.
    In some casesthis involved using JavaScript to remove the original radio or checkbox element making the end result inaccessible for a wide range of assistive technologies.
  • 25.
  • 26.
    It is possibleto style these elements without having to use JavaScript. And more importantly, we can make the end result accessible.
  • 27.
    Let’s take asimple example of an on/off switch that can be applied to either radio or checkbox elements:
  • 28.
  • 29.
    The solution I’mabout to demo, has five key accessibility features.
  • 30.
    Well… many ofthese are not really features, they are just default behaviours that should not be overridden.
  • 31.
    Feature 1: We willuse the appropriate semantic elements - input and label elements. We will explicitly associate these elements using matching “for" and "id" values.
  • 32.
    Feature 2: The labelcontent can be used to describe the purpose of each switch for screen readers. This content is hidden off-screen.
  • 33.
    Feature 3: We willmake the two different states (“on” and “off”) clearly distinguishable using a tick icon for the “on” state. This will aid colour- blind users and some types of cognitive-impaired users.
  • 34.
    (Keeping in mindthat we should never use “color alone” to signal important information.)
  • 35.
  • 36.
    Feature 4: Because weare using native elements, the default keyboard behaviour will still be available. (Users can select a radio button or checkbox using the SPACE bar).
  • 37.
    Feature 5: We willmake the focus and hover states clearly visible. The focus state is especially important for keyboard only users.
  • 38.
  • 39.
  • 40.
    <div  class="switch">      <input          class="switch__control"          type="radio"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> input label
  • 41.
    <div  class="switch">      <input          class="switch__control"          type="radio"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> radio
  • 42.
    <div  class="switch">      <input          class="switch__control"          type="checkbox"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> checkbox
  • 43.
    <div  class="switch">      <input          class="switch__control"          type="radio"          name="example01"          id="example01">      <label  class="switch__label"  for="example01">          <span  class="switch__content">Label  content</span>      </label>   </div> id for
  • 44.
  • 45.
    We will useBEM-like class names as these allow us to see the relationship between the parent element, descendant elements and modifiers.
  • 46.
    /*  parent  module */   .switch  {  }   /*  parent  modifiers  */   .switch-­‐-­‐xl  {  }   .switch-­‐-­‐lg  {  }   .switch-­‐-­‐md  {  }   .switch-­‐-­‐sm  {  }   .switch-­‐-­‐xs  {  }
  • 47.
    /*  parent  module */   .switch  {  }   /*  descendants  of  parent  module  */   .switch__control  {  }   .switch__label  {  }   .switch__content  {  }
  • 48.
  • 49.
    We can usethe parent container (“switch”) to create the overall dimensions of the switch.
  • 50.
  • 51.
    The radio buttonor checkbox control (“switch__control”) is then positioned on top of the parent. It will be given the same dimensions as the parent.
  • 52.
  • 53.
    The label (“switch__label”)is placed on top of the radio button and also given the same dimensions as the parent. We are hiding the control under the label.
  • 54.
    We will thenstyle the background of the label to look like a switch - including adding rounded corners and our background icon.
  • 55.
  • 56.
    And finally, thelabel content (“switch__content”) is hidden off screen so that it is available for screen readers, but does not clutter the visual appearance of the switch.
  • 57.
  • 58.
    Checkbox and radiobutton elements can be manually changed by users - from unchecked to checked etc.
  • 59.
    These elements canalso be given predefined boolean “checked” and “disabled” attributes.
  • 60.
    <!-­‐-­‐  no  additional attributes  -­‐-­‐>   <input  type="checkbox">   <!-­‐-­‐  boolean  checked  attribue  -­‐-­‐>   <input  type="checkbox"  checked>   <!-­‐-­‐  boolean  disabled  attribute  -­‐-­‐>   <input  type="checkbox"  disabled>
  • 61.
    However, for thissolution, most of the styling is applied to the label element, rather than the input.
  • 62.
    Unfortunately, the labelelement has no checked, unchecked or disabled state of its own.
  • 63.
    We can getaround this using adjacent sibling selectors, which target any label element that is adjacent to (comes directly after) the input.
  • 64.
    /*  unchecked  input */   .switch__control  +  label  {  }   /*  checked  input  */   .switch__control:checked  +  label  {  }   /*  disabled  input  */   .switch__control[disabled]  +  label  {  }
  • 65.
  • 66.
    We also wantto style the :focus and :hover states of the switch, which can also be done using adjacent-sibling selectors.
  • 67.
    /*  unchecked  input */   .switch__control:hover  +  label  {  }   .switch__control:focus  +  label  {  }   /*  checked  input  */   .switch__control:checked:hover  +  label  {  }   .switch__control:checked:focus  +  label  {  }
  • 68.
  • 69.
  • 70.
    Time for ourfinal “prize-winnable” question (and yes, this one is also super-easy to answer)…
  • 71.
    Question 3: Why wouldwe want to be able to control all of the dimensions of our switch using one master SASS variable?
  • 72.
  • 73.
    Because this makesit easier to maintain and to scale as needed.
  • 74.
    We can definethis one master variable by dividing our switch into scalable units.
  • 75.
  • 76.
    So, we havefour different variables for the dimensions: - switch width - switch height - toggle width/height - gutter (space) around the toggle
  • 77.
    $switch-­‐width:     3em;   $switch-­‐height:    ($switch-­‐width  /  2);          /*  1.5em  */   $toggle-­‐width:      ($switch-­‐width  /  3);            /*  1em  */   $toggle-­‐gutter:    ($switch-­‐width  /  12);        /*  .25em  */
  • 78.
    Now it becomeseasy to create a range of size variations, just by resetting the font-size.
  • 79.
    $switch-­‐xl:    1.6em;  $switch-­‐lg:    1.4em;   $switch-­‐md:    1.2em;   $switch-­‐sm:    1em;   $switch-­‐xs:    .8em;
  • 80.
    We can alsoset some quick variables for each of the background-colors used in different states.
  • 81.
    $color-­‐toggle:                     #fff;   $color-­‐unchecked-­‐static:  #aaa;   $color-­‐unchecked-­‐hover:    #777;   $color-­‐checked-­‐static:      #00a000;   $color-­‐checked-­‐hover:        #006e00;   $color-­‐disabled:                  #ddd;
  • 82.
  • 83.
    I’m generally nota fan of transitions or animations unless they are being used to help “tell the story” of a UI component - help users understand what is happening.
  • 84.
    Transitions should notdraw attention to themselves. Ideally they should be simple and subtle.
  • 85.
    For the checkbox,we could do a very simple transition to animate the switch from unchecked to checked - to help users understand what has happened.
  • 86.
    We can dothis by transitioning the “left” property as it changes from unchecked to checked.
  • 88.
    .switch__label:after  {   left: $toggle-­‐gutter;   transition:  left  .04s;   }   .switch__control:checked  +  label:after  {      left:  $switch-­‐height  +  $toggle-­‐gutter;   }
  • 89.
    We can alsosoftly animate the background-color to avoid a jarring change.
  • 90.
    .switch__label  {   background: $color-­‐unchecked-­‐static;   transition:  background  .2s;   }   .switch__control:hover  +  label,   .switch__control:focus  +  label  {      background:  $color-­‐unchecked-­‐hover;   }  
  • 91.
  • 92.
    Checkbox and radiobutton switch: https://russmaxdesign.github.io/switch-checkbox/ Github: https://github.com/russmaxdesign/switch- checkbox
  • 93.
    A simple, accessiblelanguage switcher module: https://russmaxdesign.github.io/language- switcher/ Github: https://github.com/russmaxdesign/language- switcher
  • 94.
    Upvote - downvotemodule: https://russmaxdesign.github.io/upvote-downvote/ Github: https://github.com/russmaxdesign/upvote- downvote
  • 95.
    Russ Weakley Max Design Site:maxdesign.com.au Twitter: twitter.com/russmaxdesign Slideshare: slideshare.net/maxdesign Linkedin: linkedin.com/in/russweakley