CSS Element Queries [Level 1]

A Collection of Interesting Ideas,

This version:
https://github.com/tomhodgins/element-queries-spec
Issue Tracking:
GitHub
Editor:

Abstract

Element Queries allow authors to test and query values or features of elements in an HTML document. They are used in the CSS @element rule to conditionally apply styles to a document, and in various other contexts and languages, such as HTML and JavaScript.

CSS Element Queries [Level 1] describes the mechanism and syntax of scoped stylesheets and element queries, the responsive conditions. It also describes the meta-selectors, functions, and units that make element queries powerful.

1. Introduction

By default all CSS is written from the global scope (:root, or the HTML element), and @media queries apply globally to all elements based on the conditions of the browser and media.

The idea of a scoped stylesheet is to allow CSS to view a rule, or multiple rules from the perspective of any element in the document as though it was :root.

Just like CSS already has @media queries which help define styles for different media conditions, this document describes functionality for an @element query syntax to define styles that target elements more specifically with conditions based on their own properties.

1.1. Values

Value types not defined in this specification, such as <integer>, <dimension>, <ratio>, and <ident> are defined in [CSS3VAL], and [MEDIAQUERIES-4]

1.2. Units

The units used in element queries are the same as in other parts of CSS, as defined in [CSS3VAL]. For example, the pixel unit represents CSS pixels and not physical pixels.

Additionally, new element-percentage units are defined in this document which relate to an element’s own width and height dimensions.

2. Element Queries

An element query is a method of testing certain aspects of an element and applying styles based on whether that test returns true or false.

The syntax of an element query consists of a <selector-list>, plus an optional list of zero or more responsive conditions, followed by a stylesheet containing one or more CSS rules:

@element selector list and responsive condition { stylesheet }

A scoped stylesheet will return true as long as at least one (1) element in the document matches a selector in the <selector-list>.

An element query is a logical expression that is either true or false. An element query is true if:

User agents must re-evaluate element queries in response to changes in the user environment that they’re aware of, for example resizing the browser, clicking, or scrolling, depending on which responsive conditions are being evaluated, and change the styles applied accordingly.

Note: This specification does not currently define a list of events which trigger a style recalculation, or a syntax (in CSS, HTML, or JS) through which scoped stylesheets could be limited to specific events.

2.1. Scoped Stylesheets

To write a scoped stylesheet write @element, followed by any amount of whitespace. Wrap one or more comma-separated CSS <selector> (optionally wrapped in single (') or double (") quotes), followed by any amount of whitespace, and wrap one or more CSS rules in a pair of curly brackets ({,}).

Example scoped stylesheet
@element html { ... }

2.1.1. Multiple Selectors

You can include multiple CSS selectors in your scoped stylesheet by separating them with a comma and any amount of whitespace.

Comma-separated selector list
@element ul, ol { ... }

2.1.2. Understanding the Scope

Any element on the page that matches a selector will apply the rules contained inside its scope to the page. The following examples will illustrate how the scope applies.

If we have two div elements in our HTML:

<div></div>
<div class=demo></div>
@element div {
  div {
    background: lime;
  }
}

In this example, because there are two div elements, both will match our scope and apply a rule saying all div elements have a green background.

@element .demo {
  div {
    background: lime;
  }
}

In this example we have one element in our HTML with a class of .demo. Because of this, the rule applying to all div elements applies to both of the div elements in our HTML turning their background green.

@element .demo {
  .demo {
    background: lime;
  }
}

In this example we have one element in our HTML with a class of .demo. Because of this, the rule applying to any elements with a class of .demo applies and turns the background of our .demo element green, leaving the other div untouched.

@element div {
  .demo {
    background: lime;
  }
}

In this example, because there are two div elements, both will match our scope and apply a rule saying any element with a class of .demo will have a green background. This makes one of our div elements green and leaves the other untouched.

@element select {
  .demo {
    background: lime;
  }
}

In this example we did not have any select elements in our HTML, so nothing will match our scope and no styles will be applied, leaving both of our div elements untouched.

It is possible for an element to match more than one @element query.

2.2. Scoped Styles with Responsive Conditions

An element query is a scoped stylesheet with one or more responsive conditions added.

The following global CSS and scoped stylesheet are equivalent.

Example of global CSS
body {
  background: lime;
}
Example scoped stylesheet
@element html {
  body {
    background: lime;
  }
}

In both cases, as long as there is a body element inside of our html, it will have a green background.

We can also add a responsive conditions to our scoped stylesheets. To do this, write and followed by a responsive condition and value, separated by a colon (:) and wrapped in brackets ((,)).

Example Element Query with Responsive Condition
@element html and (min-width: 500px) {
  body {
    background: lime;
  }
}

In this case, our element query is equivalent to the following media query, but not every element query will be able to be expressed as a media query.

Example media query with responsive condition
@media (min-width: 500px) {
  body {
    background: lime;
  }
}

2.2.1. Multiple Conditions

You can add more than one responsive conditions to your element query. For this, include another and, followed by another responsive condition as before.

Element query with multiple responsive conditions
@element html and (min-width: 500px) and (max-width: 1000px) {
  body {
    background: lime;
  }
}

Which in this case can be compared to the equivalent media query.

Media query with multiple responsive conditions
@media (min-width: 500px) and (max-width: 1000px) {
  body {
    background: lime;
  }
}

In both cases when our html is between the sizes of 500px and 1000px, our body will have a green background.

2.2.2. Combining @element and @media queries

It’s possible to combine the use of scoped stylesheets or element queries with media queries. Most of the time we combine them we want to include the media query on the inside of the element query. This will mean any time the element query is true, that media query will be visible to the browser and apply.

Nesting a media query inside an element query
@element #headline and (min-characters: 20) {
  @media print {
    #headline {
      border: 1px solid black;
    }
  }
}

In this example, if the element with an ID of #headline has over 20 characters, it will display in print media with a thin black border.

2.2.3. Self-Referential @element queries

With element queries comes the new possibility that the rules you are applying when your responsive conditions are met will conflict with the responsive condition in your element query. In this situation we should not attempt to detect or handle these cases by ignoring certain styles, or checking whether any of the rules affect the validity of the responsive condition. It is best to apply the rule naïvely and allow the conflict to occur.

Note: The responsibility lies with the author to write @element queries which can be interpreted logically.

@element .widget and (min‐width: 300px) {
  :self {
    width: 200px;
  }
}

In this example the query will only apply to elements with a class of .widget that are equal or wider than 300px, and the rule sets a width on the same element which would make the rule no longer apply. Rather than trying to detect or intercept this behaviour and prevent it from happening, when the @element query applies to the document it will set the width to 200px.

2.2.4. Circular Referential @element queries

Another new possibility with element queries is having two or more queries that apply styles that match each others responsive condition. Just as with a self-referential @element query, we should not try to detect or ignore styles in this situation, and instead should compute the @element queries in the order they appear and apply the rules using normal CSS specificity.

@element .widget and (min‐width: 400px) {
  :self {
    width: 200px;
  }
}
@element .widget and (max‐width: 300px) {
  :self {
    width: 500px;
  }
}

In this example any element with a class of .widget that is equal to 400px or wider will apply a rule setting the width of the same element to 200px, which makes the following @element query valid. The second query sets a width of 500px on the same element. In this case, even though the element now matches the responsive condition of the first query again, rather than get stuck in an infinite loop, we consider evaluation complete.

3. Syntax

Informal descriptions of the element query syntax appear in the prose and railroad diagrams of the previous sections. The formal element query syntax is described in this section, with the rule/property grammar syntax defined in [CSS3SYN] and [CSS3VAL].

@element = @element <eq-prelude> { <stylesheet> }

<eq-prelude> = <selector-list> | <selector-list> <eq-condition>*

<eq-condition> = and ( <eq-name> : <eq-value> )

<eq-name> = min-width | max-width | min-height
  | max-height | min-characters | max-characters
  | min-lines | max-lines | min-children
  | max-children | min-scroll-y | max-scroll-y
  | min-scroll-x | max-scroll-x | orientation
  | min-aspect-ratio | max-aspect-ratio

<eq-value> = <integer> | <dimension> | <ratio> | <ident>

meta-selectors = :self | :parent | :prev | :next

eq-unit = ew | eh | emin | emax

3.1. Evaluating Element Queries

Each <eq-condition> is associated with a boolean result, the same as the result of evaluating the specified responsive condition.

If the result of any responsive condition is used in any context that expects a two-valued boolean, "unknown" must be converted to "false".

Note: This means that, for example, when an element query is used in an @element rule, if it resolves to "unknown" it is treated as "false" and fails to match.

4. Meta-Selectors

With element queries comes the need to target elements based on the scope we have defined. There are a number of new selectors that help target elements relative to the scope we have defined. These new selectors only work inside a scoped stylesheet and are called meta-selectors.

4.1. Diagram of meta-selectors

Here is a diagram showing the relationship between the meta-selectors. The :parent is the parent element of :self, and :prev and :next represent the adjacent siblings to :self.

:parent:prev:self:next
:self
The :self meta-selector refers each element in the document that matches the root of our scoped stylesheet and any element query conditions it has.
Example of :self meta-selector
@element .widget and (min-width: 200px) {
  :self {
    background: lime;
  }
}

In this case, any element with a class of .widget that is 200px or wider will have a green background.

:parent
The :parent meta-selector refers to the element containing the element(s) in the root of our scoped stylesheet.
Example of :parent meta-selector
@element .widget and (min-width: 200px) {
  :parent {
    background: lime;
  }
}

In this case, any element containing an element with a class of .widget that is equal or wider than 200px will have a green background.

:prev
The :prev meta-selector refers to the sibling directly preceding the element at the root of our scoped stylesheet in the document.
Example of :prev meta-selector
@element .widget {
  :prev {
    background: lime;
  }
}

In this case, any sibling coming directly before any element with a class of .widget will have a green background.

:next
The :next meta-selector refers to the sibling directly following the element at the root of our scoped stylesheet in the document.
Example of :next meta-selector
@element .widget {
  :next {
    background: lime;
  }
}

In this case, any sibling coming directly after any element with a class of .widget will have a green background.

Note: the :next is similar to the selector: :self + *

5. Responsive Conditions

All responsive conditions for @element queries are formatted as a condition name and value, separated by a colon (:) character, surrounded by brackets (()).

and ( condition name : value )

The following examples are all valid as <eq-condition>:

(min-width: 500px)
(min-aspect-ratio: 16/9)
(orientation: landscape)

5.1. Width

Name: width
For: @element
Value: <dimension>
Type: range

The min-width responsive condition applies to any scoped element that has greater or equal (>=) width to the specified value.

Example min-width element query
@element .widget and (min-width: 200px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that is at least 200px or wider will have a green background.

The max-width responsive condition applies to any scoped element that has lesser or equal (<=) width to the specified value.

Example max-width element query
@element .widget and (max-width: 200) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that 200px or narrower will have a green background.

5.2. Height

Name: height
For: @element
Value: <dimension>
Type: range

The min-height responsive condition applies to any scoped element that has greater or equal (>=) height to the specified value.

Example min-height element query
@element .widget and (min-height: 50px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that is at least 50px or taller will have a green background.

The max-height responsive condition applies to any scoped element that has lesser or equal (<=) height to the specified value.

Example max-height element query
@element .widget and (max-height: 50px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that is at least 50px or shorter will have a green background.

5.3. Characters

Name: characters
For: @element
Value: <integer>
Type: range

The min-characters responsive condition applies to any scoped element that contains a greater or equal (>=) number of characters.

Example min-characters element query
@element input and (min-characters: 5) {
  :self {
    background: lime;
  }
}

In this case any input with 5 or more characters will have a green background.

The max-characters responsive condition applies to any scoped element that contains lesser or equal (<=) number of characters specified.

Example max-characters element query
@element input and (max-characters: 5) {
  :self {
    background: lime;
  }
}

In this case any input with 5 or fewer characters will have a green background.

5.4. Lines

Name: lines
For: @element
Value: <integer>
Type: range

The min-lines responsive condition applies to any scoped element that contains greater or equal (>=) number of specified lines of text.

Example min-lines element query
@element textarea and (min-lines: 3) {
  :self {
    background: lime;
  }
}

In this case any textarea with 3 or more lines will have a green background.

The max-lines responsive condition applies to any scoped element that contains lesser or equal (<=) number of specified lines of text.

Example max-lines element query
@element textarea and (max-lines: 3) {
  :self {
    background: lime;
  }
}

In this case any textarea with 3 or fewer lines will have a green background.

5.5. Children

Name: children
For: @element
Value: <integer>
Type: range

The min-children responsive condition applies to any scoped element that contains greater or equal (>=) number of child elements specified.

Example min-children element query
@element .social-icons and (min-children: 5) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .social-icons that contains more 5 or more direct descendants will have a green background.

The max-children responsive condition applies to any scoped element that contains lesser or equal (<=) number of child elements specified.

Example max-children element query
@element .social-icons and (max-children: 5) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .social-icons that contains more 5 or fewer direct descendants will have a green background.

5.6. Scroll-Y

Name: scroll-y
For: @element
Value: <dimension>
Type: range

The min-scroll-y responsive condition applies to any scoped element that has scrolled a greater or equal (>=) amount to the value specified in a vertical direction.

Example min-scroll-y element query
@element .feed and (min-scroll-y: 100px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .feed that has scrolled 100px or more vertical will have a green background.

The max-scroll-y responsive condition applies to any scoped element that has scrolled a lesser or equal (<=) amount to the value specified in a vertical direction.

Example max-scroll-y element query
@element .feed and (max-scroll-y: 100px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .feed that has scrolled 100px or less vertically will have a green background.

5.7. Scroll-X

Name: scroll-x
For: @element
Value: <dimension>
Type: range

The min-scroll-x responsive condition applies to any scoped element that has scrolled a greater or equal (>=) amount to the value specified in a horizontal direction.

Example min-scroll-x element query
@element .feed and (min-scroll-x: 100px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .feed that has scrolled 100px or more horizontally will have a green background.

The max-scroll-x responsive condition applies to any scoped element that has scrolled a lesser or equal (<=) amount to the value specified in a horizontal direction.

Example max-scroll-x element query
@element .feed and (max-scroll-x: 100px) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .feed that has scrolled 100px or less horizontally will have a green background.

5.8. Aspect-Ratio

Name: aspect-ratio
For: @element
Value: <ratio>
Type: range

The min-aspect-ratio responsive condition applies to any scoped element with a greater or equal (>=) aspect ratio, specified as a width and height pair, separated by a slash (/).

Example min-aspect-ratio element query
@element .widget and (min-aspect-ratio: 16/9) {
  :self {
    background: lime;
  }
}

In this case any element that had an aspect ratio of 16/9 or greater would have a green background.

The max-aspect-ratio responsive condition applies to any scoped element with a lesser or equal (<=) aspect ratio, specified as a width and height pair, separated by a slash (/).

Example max-aspect-ratio element query
@element .widget and (max-aspect-ratio: 16/9) {
  :self {
    background: lime;
  }
}

In this case any element that had an aspect ratio of 16/9 or lesser would have a green background.

5.9. Orientation

Name: orientation
For: @element
Value: portrait | square | landscape
Type: discrete

The orientation responsive condition applies to any scoped element that matches the orientation specified. The following orientations are included: landscape, square, portrait

5.9.1. Portrait Orientation

portrait
The orientation is portrait if the scoped element has a greater (>) height than width
Element query for portrait orientation
@element .widget and (orientation: portrait) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that is narrower than it is tall will have a green background.

5.9.2. Square Orientation

square
The orientation is square if the scoped element has an equal (=) height and width
Element query for square orientation
@element .widget and (orientation: square) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that has an equal width and height will have a green background.

5.9.3. Landscape Orientation

landscape
The orientation is landscape if the scoped element has a greater (>) width than height
Element query for landscape orientation
@element .widget and (orientation: landscape) {
  :self {
    background: lime;
  }
}

In this case any element with a class of .widget that is wider than it is tall will have a green background.

6. Element-percentage Units

Just as CSS has viewport-percentage units: vw, vh, vmin, and vmax which represent a distance equal to 1% of the viewport width, height, shortest edge, and longest edge, in a similar way the following element-percentage units ew, eh, emin, and emax represent a distance equal to 1% of the element’s own width, height, shortest edge, and longest edge. When the width of height of the element changes, the value of these units scale accordingly.

Note: These new eq-unit units always refer to the dimensions of the element in the scope, and can be used inside of a scoped stylesheet to style other elements.

ew unit
Equal to 1% of the width of the scoped element
Example of ew Units Inside a Scoped Style
@element .widget {
  :self {
    font-size: 10ew;
  }
}

In this case the font size of any element with a class of .widget is equal to 10% of the scoped element’s width.

Note: This unit is similar to the vw viewport unit, but based on the scoped element’s dimensions.

eh unit
Equal to 1% of the height of the scoped element
Example of eh Units Inside a Scoped Style
@element .widget {
  :self {
    font-size: 10eh;
  }
}

In this case the font size of any element with a class of .widget is equal to 10% of the scoped element’s height.

Note: This unit is similar to the vh viewport unit, but based on the scoped element’s dimensions.

emin unit
Equal to the smaller of 1ew or 1eh
Example of emin Units Inside a Scoped Style
@element .widget {
  :self {
    font-size: 10emin;
  }
}

In this case the font size of any element with a class of .widget is equal to 10% of the scoped element’s shortest edge.

Note: This unit is similar to the vmin viewport unit, but based on the scoped element’s dimensions.

emax unit
Equal to the larger of 1ew or 1eh
Example of emax Units Inside a Scoped Style
@element .widget {
  :self {
    font-size: 10emax;
  }
}

In this case the font size of any element with a class of .widget is equal to 10% of the scoped element’s longest edge.

Note: This unit is similar to the vmax viewport unit, but based on the scoped element’s dimensions.

7. Examples of Scoped Styles & Element Queries

7.1. Examples of valid scoped stylesheets

@element div {}
@element div, span {}
@element div and (min-width: 500px) {}
@element div and (min-width: 500px) and (min-lines: 3) {}

7.2. Faking input:empty

<input>
<style>
  /* input:empty */
  @element input and (max-characters: 0) {
    :self {
      background: red;
    }
  }
  /* input:not(:empty) */
  @element input and (min-characters: 1) {
    :self {
      background: lime;
    }
  }
</style>

In this example we are able to apply styles based on whether there are zero or at least one characters inside any input element. CSS has the pseudo-class :empty, however it doesn’t apply to all elements (like input elements) so by using max-characters and min-characters with element queries we are able to express and style a similar idea.

7.3. Self-responsive Grid

<h2>Responsive Grid</h2>
<p>Small = full width, Medium = thirds, Large = sixths.</p>
<section data-grid>
  <div class="col-10 medium-split-3 large-split-6"></div>
  <div class="col-10 medium-split-3 large-split-6"></div>
  <div class="col-10 medium-split-3 large-split-6"></div>
  <div class="col-10 medium-split-3 large-split-6"></div>
  <div class="col-10 medium-split-3 large-split-6"></div>
  <div class="col-10 medium-split-3 large-split-6"></div>
</section>
<h2>Split Grid</h2>
<p>Small = half width, Medium = 1, 2, 3, 4 split, Large = 4, 3, 2, 1 split.</p>
<section data-grid>
  <div class="col-5 medium-split-1 large-split-4"></div>
  <div class="col-5 medium-split-2 large-split-4"></div>
  <div class="col-5 medium-split-2 large-split-4"></div>
  <div class="col-5 medium-split-3 large-split-4"></div>
  <div class="col-5 medium-split-3 large-split-3"></div>
  <div class="col-5 medium-split-3 large-split-3"></div>
  <div class="col-5 medium-split-4 large-split-3"></div>
  <div class="col-5 medium-split-4 large-split-2"></div>
  <div class="col-5 medium-split-4 large-split-2"></div>
  <div class="col-5 medium-split-4 large-split-1"></div>
</section>
<h2>Hidden Elements</h2>
<p>Small = Hide Small, Medium = Hide Medium, Large = Hide Large.</p>
<section data-grid>
  <div class="col-10 hide-small">Small</div>
  <div class="col-10 hide-medium">Medium</div>
  <div class="col-10 hide-large">Large</div>
</section>
<style>
  * {
    box-sizing: border-box;
  }
  [data-grid] div {
    min-height: 50px;
    background: lime;
    border: 5px solid white;
  }
  /* Element Query Grid */
  @element [data-grid] {
    :self,
    :self * {
      box-sizing: border-box;
    }
    :self:after,
    :self [data-row]:after {
      content: '';
      display: block;
      clear: both;
    }
    :self [class*=-col-],
    :self [class*=-split-] { float: left; }
    :self [class^=col-1] { width: 10%; }
    :self [class^=col-2] { width: 20%; }
    :self [class^=col-3] { width: 30%; }
    :self [class^=col-4] { width: 40%; }
    :self [class^=col-5] { width: 50%; }
    :self [class^=col-6] { width: 60%; }
    :self [class^=col-7] { width: 70%; }
    :self [class^=col-8] { width: 80%; }
    :self [class^=col-9] { width: 90%; }
    :self [class^=col-10] { width: 100%; }
    :self [class^=split-1] { width: calc(100%/1); }
    :self [class^=split-2] { width: calc(100%/2); }
    :self [class^=split-3] { width: calc(100%/3); }
    :self [class^=split-4] { width: calc(100%/4); }
    :self [class^=split-5] { width: calc(100%/5); }
    :self [class^=split-6] { width: calc(100%/6); }
    :self [class^=split-7] { width: calc(100%/7); }
    :self [class^=split-8] { width: calc(100%/8); }
    :self [class^=split-9] { width: calc(100%/9); }
    :self [class^=split-10] { width: calc(100%/10); }
  }
  @element [data-grid] and (max-width: 400px) {
    :self [class*=small-col-1] { width: 10%; }
    :self [class*=small-col-2] { width: 20%; }
    :self [class*=small-col-3] { width: 30%; }
    :self [class*=small-col-4] { width: 40%; }
    :self [class*=small-col-5] { width: 50%; }
    :self [class*=small-col-6] { width: 60%; }
    :self [class*=small-col-7] { width: 70%; }
    :self [class*=small-col-8] { width: 80%; }
    :self [class*=small-col-9] { width: 90%; }
    :self [class*=small-col-10] { width: 100%; }
    :self [class*=small-split-1] { width: calc(100%/1); }
    :self [class*=small-split-2] { width: calc(100%/2); }
    :self [class*=small-split-3] { width: calc(100%/3); }
    :self [class*=small-split-4] { width: calc(100%/4); }
    :self [class*=small-split-5] { width: calc(100%/5); }
    :self [class*=small-split-6] { width: calc(100%/6); }
    :self [class*=small-split-7] { width: calc(100%/7); }
    :self [class*=small-split-8] { width: calc(100%/8); }
    :self [class*=small-split-9] { width: calc(100%/9); }
    :self [class*=small-split-10] { width: calc(100%/10); }
    :self [class*=hide-small] { display: none; }
  }
  @element [data-grid] and (min-width: 400px) and (max-width: 800px) {
    :self [class*=medium-col-1] { width: 10%; }
    :self [class*=medium-col-2] { width: 20%; }
    :self [class*=medium-col-3] { width: 30%; }
    :self [class*=medium-col-4] { width: 40%; }
    :self [class*=medium-col-5] { width: 50%; }
    :self [class*=medium-col-6] { width: 60%; }
    :self [class*=medium-col-7] { width: 70%; }
    :self [class*=medium-col-8] { width: 80%; }
    :self [class*=medium-col-9] { width: 90%; }
    :self [class*=medium-col-10] { width: 100%; }
    :self [class*=medium-split-1] { width: calc(100%/1); }
    :self [class*=medium-split-2] { width: calc(100%/2); }
    :self [class*=medium-split-3] { width: calc(100%/3); }
    :self [class*=medium-split-4] { width: calc(100%/4); }
    :self [class*=medium-split-5] { width: calc(100%/5); }
    :self [class*=medium-split-6] { width: calc(100%/6); }
    :self [class*=medium-split-7] { width: calc(100%/7); }
    :self [class*=medium-split-8] { width: calc(100%/8); }
    :self [class*=medium-split-9] { width: calc(100%/9); }
    :self [class*=medium-split-10] { width: calc(100%/10); }
    :self [class*=hide-medium] { display: none; }
  }
  @element [data-grid] and (min-width: 800px) {
    :self [class*=large-col-1] { width: 10%; }
    :self [class*=large-col-2] { width: 20%; }
    :self [class*=large-col-3] { width: 30%; }
    :self [class*=large-col-4] { width: 40%; }
    :self [class*=large-col-5] { width: 50%; }
    :self [class*=large-col-6] { width: 60%; }
    :self [class*=large-col-7] { width: 70%; }
    :self [class*=large-col-8] { width: 80%; }
    :self [class*=large-col-9] { width: 90%; }
    :self [class*=large-col-10] { width: 100%; }
    :self [class*=large-split-1] { width: calc(100%/1); }
    :self [class*=large-split-2] { width: calc(100%/2); }
    :self [class*=large-split-3] { width: calc(100%/3); }
    :self [class*=large-split-4] { width: calc(100%/4); }
    :self [class*=large-split-5] { width: calc(100%/5); }
    :self [class*=large-split-6] { width: calc(100%/6); }
    :self [class*=large-split-7] { width: calc(100%/7); }
    :self [class*=large-split-8] { width: calc(100%/8); }
    :self [class*=large-split-9] { width: calc(100%/9); }
    :self [class*=large-split-10] { width: calc(100%/10); }
    :self [class*=hide-large] { display: none; }
  }
</style>

This example uses @element queries to apply the different responsive styles to our grid when the grid element itself reaches certain breakpoints. Because the styles are scoped to each grid using :self, we can use these same styles to power many grids in the same layout all using the same styles.

8. Requirements

Scoped Styles + Element/Container Queries

Element-Based Units

Conformance

Conformance requirements are expressed with a combination of descriptive assertions and RFC 2119 terminology. The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative parts of this document are to be interpreted as described in RFC 2119. However, for readability, these words do not appear in all uppercase letters in this specification.

All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes. [RFC2119]

Examples in this specification are introduced with the words “for example” or are set apart from the normative text with class="example", like this:

This is an example of an informative example.

Informative notes begin with the word “Note” and are set apart from the normative text with class="note", like this:

Note, this is an informative note.

Index

Terms defined by this specification

Terms defined by reference

References

Normative References

[CSS-CONDITIONAL-3]
CSS Conditional Rules Module Level 3 URL: https://drafts.csswg.org/css-conditional-3/
[CSS3SYN]
Tab Atkins Jr.; Simon Sapin. CSS Syntax Module Level 3. URL: http://dev.w3.org/csswg/css-syntax/
[CSS3VAL]
Tab Atkins Jr.; Elika Etemad. CSS Values and Units Module Level 3. 29 September 2016. CR. URL: https://www.w3.org/TR/css-values-3/
[MEDIAQUERIES-4]
Florian Rivoal; Tab Atkins Jr.. Media Queries Level 4. URL: https://drafts.csswg.org/mediaqueries-4/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SELECTORS-4]
Selectors Level 4 URL: https://drafts.csswg.org/selectors-4/

Property Index

No properties defined.

@element Descriptors

Name Value Initial Type
width <dimension> range
height <dimension> range
characters <integer> range
lines <integer> range
children <integer> range
scroll-y <dimension> range
scroll-x <dimension> range
aspect-ratio <ratio> range
orientation portrait | square | landscape discrete