f81b1ec Jul 25, 2018
1 contributor

Users who have contributed to this file

115 lines (83 sloc) 4.5 KB

Range-Context Media Features: Draft 3

(Issue, Changelog)

This proposal defines how Sass handles media queries with features written in a range context.

Table of Contents


This section is non-normative.

Media features written in a range context will be parsed by Sass, with full SassScript expressions allowed for the values except in cases where Sass's operators would be ambiguous with range operators. Range-context media features will be merged as all media features have been up to this point, by adding each feature to the media query's "and"-separated list.

Design Decisions

While it would be possible to merge features more intelligently—for example, (width > 200px) and (width < 600px) could be merged into (200px > width > 600px)—doing so in general would add a great deal of complexity to media merging, for very limited benefits in terms of output size and readability.

The values of media features with the "range" type are heterogeneous, including a <ratio> type value type that Sass has no existing knowledge of. If Sass were to support intelligent merging of these features, it would need to keep abreast of any new value types supported by "range"-type media features. This would violate Sass's general design principle of knowing as little about CSS as possible.


Sass parses media queries twice. The first time is part of parsing the Sass stylesheet, at which point the queries may contain SassScript expressions and interpolation. The second parses the result of evaluating the SassScript as plain CSS.


This proposal defines a new syntax for media queries in Sass stylesheets. It is intended to replace the existing syntax.

Other than support for the range context syntax, this syntax is designed to represent the current behavior of all Sass implementations.

MediaQueryList ::= MediaQuery (',' MediaQuery)*
MediaQuery     ::= MediaType | (MediaType 'and')? MediaFeature ('and' MediaFeature)*
MediaType      ::= InterpolatedIdentifier InterpolatedIdentifier¹?
MediaFeature   ::= Interpolation
                 | '(' Expression² ')'
                 | '(' Expression² ':' Expression ')'
                 | '(' Expression² <mf-comparison> Expression² ')'
                 | '(' Expression² <mf-lt> Expression² <mf-lt> Expression² ')'
                 | '(' Expression² <mf-gt> Expression² <mf-gt> Expression² ')'

1: This InterpolatedIdentifier may not be the identifier "and".

2: These Expressions may not contain binary operator expressions with the operators =, >, >=, <, or <=, except within parentheses (including function calls and map literals) and square brackets.

The <mf-comparison>, <mf-lt>, and <mf-gt> productions are defined in Media Queries Level 4.

Note that Sass currently doesn't support parsing full media conditions according to the level 4 specification, since no browsers support it yet. See sass/sass#2538 for details.


Plain CSS media queries are parsed using the following syntax:

CssMediaQueryList ::= CssMediaQuery (',' CssMediaQuery)*
CssMediaQuery     ::= CssMediaType
                    | (CssMediaType 'and')? CssMediaFeature ('and' CssMediaFeature)*
CssMediaType      ::= <ident-token> <ident-token>¹?
CssMediaFeature   ::= '(' <declaration-value> ')'

1: This Identifier may not be the identifier "and".

The <ident-token> production matches the railroad diagram listed in CSS Syntax Level 3. The <declaration-value> production uses the definition from CSS Syntax Level 3, consuming tokens only as needed until the production terminates.

This is the existing syntax Sass uses to reparse plain CSS media queries. Since they're already parsed using <declaration-value>, no change in behavior is necessary to support range-form queries.