Logical Grouping & Precedence
Logical grouping is a way to group multiple conditions together to form a single condition. This is useful when you want to apply the same logical operator to multiple conditions. For example, you can group two conditions together and apply the AND
operator to them.
Self Grouping
Self grouping expressions is the process of automatically grouping expressions based on their logical operator, or keyword.
The parser will always group AND
expressions together. Thus OR
operators will determine the split between groups. As described in the combinators section, the parser will also group and treat them as AND
operators. Hence why the AND
operator is not required when chaining combinators.
Here's an example to illustrate self grouping:
- SQL
- CSS
SELECT * FROM DOM WHERE
TAG = 'a' AND CLASS = 'active'
OR CLASS = 'link'
OR TAG = 'button' AND ID = 'to-top-link'
a.active, .link, button#to-top-link {
/* Styles */
}
In this example:
- The SQL query selects elements that are:
<a>
elements with the classactive
.- Elements with the class
link
. <button>
elements with the IDto-top-link
.
- The parser groups the conditions based on the
OR
operator. Similarly, the above query can also be written as:
SELECT * FROM DOM WHERE
(TAG = 'a' AND CLASS = 'active')
OR CLASS = 'link'
OR (TAG = 'button' AND ID = 'to-top-link')
For readability sake, manually define groupings - with parentheses ()
- where possible.
Manual Grouping with Parentheses
Manual grouping is the process of explicitly grouping expressions together using parentheses ()
. This is useful when you want to apply a specific logical operator to multiple conditions.
Here's an example to illustrate manual grouping:
- SQL
- CSS
SELECT * FROM DOM WHERE
(TAG = 'a' AND CLASS = 'active')
OR (CLASS = 'link' AND TAG = 'button')
a.active, button.link {
/* Styles */
}
In this example:
- The SQL query selects elements that are:
<a>
elements with the classactive
.<button>
elements with the classlink
.
Parser Intervention
CSS Selectors are quite basic in nature, and thus attempting 'unique' AND
/OR
combinations purely based on logical principles driven by the user, may not always work as expected. The parser will intervene and group expressions based on the logical operator precedence. In a way, the parser will always try to ensure that the query is valid and can be parsed correctly in accordance with W3C standards.
Extending from the above example, here's an example to illustrate parser intervention:
- SQL
- CSS
SELECT * FROM DOM WHERE
(
TAG = 'a' AND CLASS = 'active' -- Removed manual parentheses that closed off the 'AND' grouping
OR CLASS = 'link' AND TAG = 'button'
)
a.active, button.link { /* Result remains the same */
/* Styles */
}
Cross-Apply
Cross-apply is a way to apply a single selector to multiple conditions. This is useful to shorthand most queries and reduce redundancy.
Cross-apply expressions can be achieved by grouping multiple OR
expressions, and preceding them with a single AND
selector. This will apply the AND
selector to each OR
expression.
Here's an example to illustrate cross-apply:
- SQL
- CSS
- SQL Alternative
SELECT * FROM DOM WHERE
TAG = 'a' AND (CLASS = 'active' OR CLASS = 'link')
a.active, a.link {
/* Styles */
}
SELECT * FROM DOM WHERE
TAG = 'a' AND CLASS = 'active'
OR TAG = 'a' AND CLASS = 'link'
In this example:
- The SQL query selects
<a>
elements that have either the classactive
orlink
. - The CSS selector applies styles to
<a>
elements with the classactive
orlink
.
Advanced Cross-Apply Grouping
Cross-apply can also be used to apply multiple selectors to multiple conditions. This is useful when you have multiple conditions that overlap with each other.
Here's an example to illustrate advanced cross-apply grouping:
- SQL
- CSS
- SQL Alternative
SELECT * FROM DOM WHERE
CLASS = 'orange' AND TAG = 'a'
AND (
CLASS = 'active' AND ID = 'new-link'
OR CLASS = 'link' AND ID = 'old-link'
)
a#new-link.orange.active, a#old-link.orange.link {
/* Styles */
}
SELECT * FROM DOM WHERE
CLASS = 'orange' AND TAG = 'a' AND CLASS = 'active' AND ID = 'new-link'
OR CLASS = 'orange' AND TAG = 'a' AND CLASS = 'link' AND ID = 'old-link'
In this example:
- The SQL query selects
<a>
elements that are:- Orange and have the class
active
and IDnew-link
. - Orange and have the class
link
and IDold-link
.
- Orange and have the class
As of V1.0
, cross-apply selectors must always precede the OR
expressions. Appending them after an OR
expression will result in unexpected behavior.
- SQL Invalid
- SQL Valid
SELECT * FROM DOM WHERE
(CLASS = 'active' OR CLASS = 'link') AND TAG = 'a' -- Cross-apply selector is placed after the OR expression
SELECT * FROM DOM WHERE
TAG = 'a' AND (CLASS = 'active' OR CLASS = 'link') -- Cross-apply selector is placed before the OR expression
Limitations
The parser currently only supports shallow grouping. Meaning, you can not nest multiple groups within each other.
For example, the following query is invalid and will likely throw a parsing error, or generate invalid CSS selectors:
SELECT * FROM DOM WHERE
TAG = 'a' AND (CLASS = 'active' OR (CLASS = 'link' AND ID = 'new-link'))