It's easy to extend CSS to include new features and functionality. One of the concepts people want to add to CSS to work with is the ability to scope styles to an element in a way that prevents it from applying to other elements on the page. Many other desired CSS features depend on this ability in order to work, including element queries - the ability to set responsive breakpoints on an element and its own rendered width/height, or other properties on the page.

In this short post we'll show an element query that demonstrates scoped styling at the same time.

In JavaScript

One way we can accomplish scoped styling and element queries will be to use a little bit of JavaScript to add the ability for us to template stylesheets on-the-fly in the browser, and we'll also need a plugin for element queries that defines tests for our responsive breakpoint conditions.

  import jsincss from 'https://unpkg.com/jsincss/index.vanilla.js'
import element from 'https://unpkg.com/jsincss-element-query/index.vanilla.js'

For this demo let's add a few <input> elements onto the page to demonstrate. When we write an element query for any <input> tag and the condition is true, we'll need a way to apply it to only those tags which pass the test.

  <input placeholder="Type 5+ characters…">
<input placeholder="Type 5+ characters…">
<input placeholder="Type 5+ characters…">

To demonstate how these plugins would work we can use the element() function provided by our element query plugin and give it a CSS selector, a repsonsive breakpoint condition, and some styles it should apply, and it should apply only to those <input> tags matching the condition.

In the CSS styles we want to apply to this element we've used the invented [--self] selector to represent each matching tag. When any of these tags passes the conditions that [--self] selector will be replaced with a selector that uniquely targets that element and all of the styles will be 'scoped' to that tag.

  jsincss(() =>
  element(
    'input',
    {minCharacters: 5},
    '[--self] { background-color: lime }'
  )
)

Try typing five or more characters of text into the <input> tags in the demo below, or experiment with changing the JavaScript - just be sure to hit the 'rerun' button after each update!

In CSS

But the end goal isn't to write Javascript for element queries, it's to control these plugins by writing CSS in our stylesheets. We can take this one step further.

It's possible to express this same logic in valid CSS syntax in a way that the browser will parse and safely ignore, but JavaScript plugins can find and read, and use to run the element query plugin and stylesheet templating plugin plugin without us having to write JavaScript for each element query we want to write.

Here's an example of using @supports to write an element query in CSS as a custom at-rule, with all of the rules we want to apply to matching elements inside.

  @supports (--element("input", {"minCharacters": 5})) {
  [--self] {
    background-color: lime;
  }
}

And in this case to make this work we'll use a different plugin that will read this element query from CSS and run it through the other plugin for us.

  import deqaf from 'https://unpkg.com/deqaf'
import element from 'https://unpkg.com/jsincss-element-query/index.vanilla.js'

deqaf({stylesheet:{element}})

To learn more about how you can write CSS stylesheets like this, check out the caffeinated style sheets readme on Github