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

The Edge of CSS

Tommy Hodgins
April 20, 2017

The Edge of CSS

Have you ever felt limited by CSS and found yourself needing to apply styles to an element CSS can't quite select, or based on a breakpoint CSS isn't quite aware of? Follow along as Tommy shares a CSS extension that adds a few new abilities to how you can write CSS, and learn how you can begin using concepts like style scoping, element and container queries, and much more in your own projects right away!

Tommy Hodgins

April 20, 2017
Tweet

More Decks by Tommy Hodgins

Other Decks in Design

Transcript

  1. Signs you’re on the edge • using polyfills for unsupported

    features • generating unique IDs or classes for elements
  2. Signs you’re on the edge • using polyfills for unsupported

    features • generating unique IDs or classes for elements • duplicating code only to change breakpoints
  3. Signs you’re on the edge • using polyfills for unsupported

    features • generating unique IDs or classes for elements • duplicating code only to change breakpoints • so many more (see Sisyphus)
  4. What if you could extend CSS in the browser to

    add new features and functionality?
  5. A CSS reprocessor is a tool to recalculate your styles

    as often as needed after the page has loaded, and after user interaction
  6. The goal of EQCSS was to add the features I

    wanted to use to CSS so I could use them
  7. What’s the smallest set of ideas that could be added

    to CSS to lead to the functionality I wanted?
  8. What if CSS Could • Set a scope for a

    selector like a @media query but for individual elements
  9. What if CSS Could • Set a scope for a

    selector like a @media query but for individual elements • Add a block of CSS styles to the page when that selector is true
  10. What if CSS Could • Set a scope for a

    selector like a @media query but for individual elements • Add a block of CSS styles to the page when that selector is true • Add responsive conditions to that selector
  11. What if CSS Could • Set a scope for a

    selector like a @media query but for individual elements • Add a block of CSS styles to the page when that selector is true • Add responsive conditions to that selector • Evaluate JavaScript from the context of the element you are styling and use those values in the CSS you're applying to the page
  12. With those four ideas added on top of what CSS

    already does many new responsive techniques become very simple to express
  13. The amount of JavaScript required to add support for these

    four ideas is about 3000 lines of code, or about 3kb when minified and gzipped
  14. New techniques possible • scoped styles • element queries &

    container queries • breakpoints based on element properties • variables scoped to individual elements • self-responsive HTML components • parent selector, previous element selector, etc
  15. • element-based units • scroll-based responsive styles • smarter attribute

    selectors (number comparison) • make any element scalable • work easily with aspect ratios • polyfill and emulate unsupported CSS features • many more… (search ‘EQCSS’ on CodePen for 100+)
  16. EQCSS allows us to • Build layout-independent design components •

    Scope, isolate, and transplant existing layout parts from one project to another
  17. EQCSS allows us to • Build layout-independent design components •

    Scope, isolate, and transplant existing layout parts from one project to another • Support modern responsive layouts in older browsers
  18. EQCSS allows us to • Build layout-independent design components •

    Scope, isolate, and transplant existing layout parts from one project to another • Support modern responsive layouts in older browsers • Keep our CSS short and our workflow simple
  19. How EQCSS works • If any @element queries are found,

    the selector(s), condition(s), and styles are extracted
  20. How EQCSS works • EQCSS recalculates on: DOM ready, scroll,

    resize, input, click, mousedown, mousemove, mouseup
  21. How EQCSS works • Any time there is at least

    1 element in the DOM matching a selector in the selector list of an @element query • And all conditions are true (if any included) • Add the block of styles to the page
  22. How EQCSS works • And while we’re applying CSS to

    the page: provide a way to evaluate JavaScript from the context of each element we’re styling
  23. With @media queries the most common responsive features are min/max

    width and height, but with @element queries, many new responsive features make sense
  24. Responsive conditions • width • height • characters (number of

    characters of text content) • lines (number of lines of text) • children (number child elements) • scroll-x (horizontal scroll position) • scroll-y (vertical scroll position) • aspect-ratio • orientation
  25. Meta-Selectors • $this is the scoped element • $parent is

    the parent of the scoped element • $prev is the element before the scoped element • $next is the element after the scoped element
  26. Similar to how viewport units (VW, VH, VMIN and VMAX)

    refer to viewport-based percentages, what if element-based units referred to dimensions of individual elements
  27. Element-based units • EW is 1% element width • EH

    is 1% element height • EMIN is 1% element minimum length • EMAX is 1% element maximum length
  28. Eval • eval('') uses the output of JavaScript evaluated from

    the context of each element the query applies to anywhere inside the styles being added to the page
  29. Many values like this, while out of reach of CSS,

    are simple to measure with JavaScript if you could evaluate from the context of each element you are styling
  30. Imagine if an iframe had a way to scale height

    responsively based on its own aspect ratio
  31. What if CSS could access each iframe’s own width and

    height attributes, something kind of like attr(width) or attr(height)
  32. Here eval('width') is giving us the same result in our

    CSS as el.width or el.getAttribute('width') would return in JavaScript
  33. No matter what the current width, we can always scale

    the height of each iframe based on its own aspect ratio, determined by its own width and height attributes
  34. Have you ever wanted to apply a style to an

    element that contains another element?
  35. Suppose we want to make an h2 red, but only

    if it contains a strong element inside
  36. This is equivalent to styling $this inside an element query

    for h2:has(strong) if it had support…
  37. …Or maybe you could apply a style to the parent

    of every strong tag if the $parent is also an h2
  38. Or another way to do the same thing would be

    to apply a style to the $parent of any h2 strong
  39. We can use [value=0] and match the number 0 as

    a string, but not compare as a number with >, <, >=, or <=
  40. Imagine you want to set hyphens for heading elements when

    they are less than 35em wide, you may use a @media query like this
  41. We can use an @element query to make the breakpoint

    relative to the width of each heading tag rather than the width of the browser’s viewport
  42. Now our heading tags will have hyphenation when any of

    them are less than 35em wide, regardless of the width of the browser
  43. • change the background-position of a background image based on

    an element’s aspect-ratio • style an input that's empty (input:empty doesn't work in CSS)
  44. • change the background-position of a background image based on

    an element’s aspect-ratio • style an input that's empty (input:empty doesn't work in CSS) • create scalable/responsive CSS border art
  45. • change the background-position of a background image based on

    an element’s aspect-ratio • style an input that's empty
 (input:empty doesn't work in CSS) • create scalable/responsive CSS border art • style a textarea or input so it expands to fit as many characters or lines of text as are inside
  46. Which events should trigger recalculations? • things like: load, resize,

    input and keyboard, clicks and touch events, scroll on elements, etc. • can you only listen to events that make sense to the styles you are recalculating? • can you use resize observers for width/height? • do mutation observers help?
  47. Is your reprocessor integrated inside a specific tech stack or

    tool, or does it exist as a plugin that runs in the browser like a shim or polyfill?
  48. What’s your exit strategy or migration path for porting code

    away from the reprocessor if you need to at some point in the future?