Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Extending CSS with Event-Driven Virtual Stylesheets

Tommy Hodgins
January 24, 2018

Extending CSS with Event-Driven Virtual Stylesheets

A talk explaining the places and way that CSS can be extended using JavaScript by populating virtual stylesheets

Tommy Hodgins

January 24, 2018
Tweet

More Decks by Tommy Hodgins

Other Decks in Design

Transcript

  1. “Extending CSS” • Adding new styling abilities • Doing things

    CSS can’t ‘polyfill’ using existing features • Leveraging JavaScript and built-in DOM APIs for styling • Styling beyond the scope of what CSS is designed to do
  2. “Extending CSS” is NOT • Not replacing or reimplementing what

    CSS already does • Not just adding syntactic sugar to CSS (pre-processing) • Not necessarily violating the “Separation of Concerns”
  3. “Event-Driven” • CSS is already event-driven (:hover, :focus, etc) •

    Style changes often mirror events happening in the browser (@media) • Style changes are often driven by events in Javascript
  4. “Virtual Stylesheets” • Dynamic stylesheet that can change over time

    • Leverage JavaScript logic for templating • Leverage JavaScript for interpolating values • Can be located in DOM or CSSOM
  5. Types of Virtual Stylesheet • <style> tag in HTML •

    <script> or <template> in HTML • External <script> or <link> file • Any string in JavaScript
  6. Places Where You Can
 Add Logic to Styles • HTML:

    using custom attributes (for selector, test, event) • CSS: using custom attribute selectors or CSS variables • JS: using strings, variables, and functions
  7. Useful Events for Styling • Global events: load, resize, input,

    click • Element-based events: scroll, mutation observer, resize observer • App-based events: JS framework updates, plugin callbacks, state-based styling logic in apps
  8. Useful Tests for Styling • el => el.offsetWidth < 500

    // less than • el => el.offsetWidth <= 500 // less or equal (max) • el => el.offsetWidth == 500 // equal • el => el.offsetWidth >= 500 // greater or equal (min) • el => el.offsetWidth > 500 // greater than
  9. Useful Properties for Testing • offsetWidth • offsetHeight • textContent.length

    || value.length • children.length • scrollTop • scrollLeft
  10. Style Scoping • Exists at 3 levels: stylesheet, selector, and

    property • 1 scoped stylesheets: @media & container queries • 2 scoped selectors: :has(), :hover, element queries • 3 scoped properties: CSS variables, JS interpolation
  11. Scoped Style Proposals • CSS first proposed in 1994 •

    JavaScript Style Sheets (JSSS) by Netscape in 1996 • Dynamic Properties in IE5-8 by Microsoft in 1999 • CSS @media queries proposed in 2001
 (standardized in 2012 after eleven years of drafting) • :scope proposed in CSS Selectors Level 4 in 2011 (still in draft) • Houdini specs proposed in 2016 (still active WIP)
  12. EDVS Plugins • Load stylesheets • Are aware of JavaScript

    logic and events • Populate virtual stylesheets • Interact with helper functions (mixins) to extend CSS
  13. function JSinCSS() { var tag = document.querySelector('#JSinCSS') if (!tag) {

    tag = document.createElement('style') tag.id = 'JSinCSS' document.head.appendChild(tag) } tag.innerHTML = ` body:before {
 content: '${innerWidth} x ${innerHeight}'; 
 } ` } window.addEventListener('load', JSinCSS) window.addEventListener('resize', JSinCSS) window.addEventListener('input', JSinCSS) window.addEventListener('click', JSinCSS)
  14. What It's Doing • Find (or create and attach) a

    <style> tag to populate • Hold CSS as a template string to be interpolated • Add event listeners to trigger stylesheet reprocessing
  15. EDVS Mixins • Can be used interchangeably with most EDVS

    plugins • Can search and modify the DOM • Return a string of CSS to the EDVS plugin • Borrow from Unix Philosophy (text-based, act as filter)
  16. function mixin(selector, rule) { var tag = document.querySelectorAll(selector) var style

    = '' var count = 0 for (var i=0; i<tag.length; i ++) { var attr = selector.replace(/\W+/g, '') tag[i].setAttribute(`data-mixin-${attr}`, count) style += `[data-mixin-${attr}="${count}"] { ${rule} }` count ++ } return style }
  17. What It's Doing • Find all tags in document matching

    a selector • Assign a unique attribute to matching tags • Generate CSS targeting these unique attributes • Return CSS as a string • Extend by adding JS logic to decide which tags to style
  18. It Doesn't Take Much Code • To conceive of new

    ways of thinking about design • To define a comfortable syntax for describing styles • To implement your desired workflow and tooling • To support a wide range of web browsers