Have you ever found
yourself at the edge of what
CSS can do?
Slide 3
Slide 3 text
Signs you’re on the edge
• using polyfills for unsupported features
Slide 4
Slide 4 text
Signs you’re on the edge
• using polyfills for unsupported features
• generating unique IDs or classes for elements
Slide 5
Slide 5 text
Signs you’re on the edge
• using polyfills for unsupported features
• generating unique IDs or classes for elements
• duplicating code only to change breakpoints
Slide 6
Slide 6 text
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)
Slide 7
Slide 7 text
In situations where your only
option is writing custom JavaScript
to apply a style to an element…
Slide 8
Slide 8 text
Think how CSS could be
extended to reach that
situation instead
Slide 9
Slide 9 text
What if you could extend CSS
in the browser to add new
features and functionality?
Slide 10
Slide 10 text
What if instead of a CSS
preprocessor you had a
CSS reprocessor?
Slide 11
Slide 11 text
What is a CSS
reprocessor?
Slide 12
Slide 12 text
A CSS reprocessor is a tool to
recalculate your styles as often as
needed after the page has loaded,
and after user interaction
Slide 13
Slide 13 text
Thinking beyond the
edge of CSS
Slide 14
Slide 14 text
My journey beyond the
edge began in 2014 with
the EQCSS project
Slide 15
Slide 15 text
The goal of EQCSS was to add
the features I wanted to use
to CSS so I could use them
Slide 16
Slide 16 text
The hard question:
Slide 17
Slide 17 text
What’s the smallest set of ideas
that could be added to CSS to lead
to the functionality I wanted?
Slide 18
Slide 18 text
Our 4 What-ifs
Slide 19
Slide 19 text
What if CSS Could
• Set a scope for a selector like a @media query
but for individual elements
Slide 20
Slide 20 text
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
Slide 21
Slide 21 text
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
Slide 22
Slide 22 text
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
Slide 23
Slide 23 text
With those four ideas added on top
of what CSS already does many
new responsive techniques become
very simple to express
Slide 24
Slide 24 text
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
Slide 25
Slide 25 text
But there’s no end to the
amount of new responsive
techniques possible…
Slide 26
Slide 26 text
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
Slide 27
Slide 27 text
• 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+)
Slide 28
Slide 28 text
EQCSS has been used in
production for 2 years
Slide 29
Slide 29 text
EQCSS allows us to
• Build layout-independent design components
Slide 30
Slide 30 text
EQCSS allows us to
• Build layout-independent design components
• Scope, isolate, and transplant existing layout
parts from one project to another
Slide 31
Slide 31 text
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
Slide 32
Slide 32 text
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
Slide 33
Slide 33 text
Moving beyond
The edge of CSS
Slide 34
Slide 34 text
How EQCSS works
• If any @element queries are found, the
selector(s), condition(s), and styles are
extracted
Slide 35
Slide 35 text
How EQCSS works
• EQCSS recalculates on: DOM ready, scroll, resize,
input, click, mousedown, mousemove, mouseup
Slide 36
Slide 36 text
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
Slide 37
Slide 37 text
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
Slide 38
Slide 38 text
With @media queries the most common
responsive features are min/max width
and height, but with @element queries,
many new responsive features make sense
Slide 39
Slide 39 text
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
Slide 40
Slide 40 text
Inside the scope of the
@element query, new
selectors are possible
Slide 41
Slide 41 text
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
Slide 42
Slide 42 text
Evaluating the properties of the
elements as we style them adds
the possibility for new units
Slide 43
Slide 43 text
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
Slide 44
Slide 44 text
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
Slide 45
Slide 45 text
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
Slide 46
Slide 46 text
Some CSS+
Techniques
Slide 47
Slide 47 text
Imagine if CSS had more
dynamic values like
currentColor
Slide 48
Slide 48 text
What if you could use values
like currentWidth or
parentChildren in your CSS?
Slide 49
Slide 49 text
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
Slide 50
Slide 50 text
Imagine if an iframe had a way
to scale height responsively
based on its own aspect ratio
Here eval('width') is giving us the
same result in our CSS as el.width or
el.getAttribute('width') would
return in JavaScript
Slide 59
Slide 59 text
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
Slide 60
Slide 60 text
What about a parent
selector, or :has()?
Slide 61
Slide 61 text
Have you ever wanted to apply
a style to an element that
contains another element?
Slide 62
Slide 62 text
Suppose we want to make an
h2 red, but only if it contains
a strong element inside
Slide 63
Slide 63 text
This is possible with CSS using
h2:has(strong), but unfortunately
no web browsers support :has()
Slide 64
Slide 64 text
h2:has(strong) {
color: red;
}
Slide 65
Slide 65 text
This is equivalent to styling $this
inside an element query for
h2:has(strong) if it had support…
Slide 66
Slide 66 text
@element h2:has(strong) {
$this {
color: red;
}
}
Slide 67
Slide 67 text
Since we can’t use :has(), could we
use querySelector() inside
eval('') to check for strong tags?
Now our heading tags will have
hyphenation when any of them are
less than 35em wide, regardless of
the width of the browser
Slide 88
Slide 88 text
Think of how you might
accomplish some of the
the following ideas…
Slide 89
Slide 89 text
• change the background-position of a
background image based on an element’s
aspect-ratio
Slide 90
Slide 90 text
• 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)
Slide 91
Slide 91 text
• 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
Slide 92
Slide 92 text
• 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
Slide 93
Slide 93 text
To get started, add the
following line of code to
your project:
Slide 94
Slide 94 text
Slide 95
Slide 95 text
Reprocessing CSS
Slide 96
Slide 96 text
If you are going to try a
CSS reprocessor, here are
things to keep in mind
Slide 97
Slide 97 text
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?
Slide 98
Slide 98 text
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?
Slide 99
Slide 99 text
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?
Slide 100
Slide 100 text
THANKS!
Visit elementqueries.com for
demos, docs, & links