Things you can do with CSS that used to need JS

Rhiana Heath

WebDirections Summit

Oct 2019

vs

A.K.A

Content

Style

Functionality

Why use CSS for functionality?

Users that Disable JS*

JS Enabled

JS Disabled

* Average result, numbers vary by country and device

Why Disable JS?

  1. Speed & Bandwidth
  2. Usability & Accessibility
  3. Platform Support
  4. Security
  5. By Accident

All your users are non-JS while they’re downloading your JS.

Jake Archibald, Google

No-JS Fallbacks

<noscript>
  <p>
    This can be added to your HTML and 
    only show if no JS is detected
  </p>
</noscript>

Easy to test

Have Everything show by default

Hide & Toggle with JS not CSS

Increase JS performance

Remove JS not being used

Progressive Enhancement

Use CSS for as much functionality as possible

>

:focus-Within

History

  • 1995
    • JS onclick 
  • 2006
    • jQuery
      • toggleClass()
  • 2009
    • jQuery UI
      • focus()

JS

CSS

Example

Pros

  1. Usable by keyboard and mouse users
  2. Add custom animations and transitions

Cons

  1. Can be a little fiddly to activate
&_submenu {
   &:hover {
    > .Nav_dropdown {
      display: block;
    }
  }
}
 &_toggle {
   &:focus, &:focus-within {
     + .Nav_dropdown {
       display: block;
     }
   }
 }

:target

History

OK

Example

.Modal {
  z-index: -1;
  opacity: 0;
  pointer-events: none;
  &:target {
    opacity: 1;
    pointer-events: auto;
    z-index: 999;
  }
}
<a class="btn" href="#open-modal">
  Open Modal
</a>
<div class="Modal" id="open-modal">
  ...
</div>

Pros

  1. Supported in all desktop browsers 
    1. Even IE9!
  2. No JS Library needed

Cons

  1. Modifies the URL and browser history
  2. Less support in mobile browsers

Future

<dialog open>
  ...
</dialog>
  1. Still requires some JS
  2. Isn't well supported yet
  3. Baked in a11y
    1. aria-model="true"

:checked

History

:checked css selector officially added to CSS 3​ spec

2018

2012

Bootstrap collapse accordions added to version 2

Accordions are in jQuery UI version 1.5

2008

Example

Pros

  1. Supported in all desktop browsers 
    1. Even IE9!
  2. Can use radio buttons as well for one open at a time

Cons

  1. Less support in mobile browsers
  2. Doesn't work for nested inputs
    1. Children or siblings only
<input type="checkbox"
       id="toggle-1"
       class="Accordion_input"
       name="accordion"
       value="0"/>

<label for="toggle-1"
       class="Accordion_label">
   Toggle 1
</label>
&_input {
  // Not display: none; for sr a11y
  @include hiddenInput;
  &:checked {
    ~ .Accordion_body {
      display: block;
    }
  }
}
<details>
  <summary>
    Accodion Title
  </summary>
  Accordion Body text
</details>

Future?

  1. New HTML element
  2. Not very well supported
  3. Can't really be styled yet

Bonus Round

Columns

History

2018

Multi column layout officially added to CSS 3​ spec

2016

Brick.js Masonry library

Example

.Masonry {
  column-count: 3;
  column-gap: 20px;
  &_object {
    // Otherwise will wrap like a newspaper
    break-inside: avoid;
    margin-bottom: 20px;
  }
}

Pros

  1. Supported in all browsers
    1. Just remember prefixes!
  2. Easy to make responsive, just adjust the number of columns

Cons

  1. Not much flexibility in how elements are positioned
    1. Order is up->down, left -> right

transitions

History

2019

transition is in CSS4 working draft

2006

.fadeIn() added in jQuery

2010

Scriptaculous animation library

Example

.Transition {
  background-color: #BF55EC;
  transition: background-color 0.3s;
  &:hover {
    background-color: #007A7C;
  }
}

Pros

  1. Supported in all browsers
    1. Background image bug for Safari
  2. In the same place as the styles

Cons

  1. Only works on certain CSS properties
  2. If not optimised can be very slow
    1. transition: all;

Can

  1. background
  2. color
  3. width | height: npx
  4. margin, padding
  5. opacity
  6. transform

Can't

  1. display
  2. position
  3. width | height: auto

Bonus Round!

What can't CSS do?

Won't work

<label>
  <input type="radio"/>
</label>

Accessibility

  • Pros:
    • Can make it more robust and quicker to load
  • Cons:
    • Can't update dynamic attributes

Won't Update

<div aria-expanded="false">
  ...
</div>

Accessibility with JS

$('input[type="checkbox"]').on('change', function() {
  var $content = $(this).siblings('.content')
  var $is_checked = $(this).prop('checked')
  
  $content.attr('aria-expanded', $is_checked)
})

Thanks!