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
ORoperator. 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 classactiveorlink. - The CSS selector applies styles to
<a>elements with the classactiveorlink.
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
activeand IDnew-link. - Orange and have the class
linkand 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
Enhanced Nested Grouping
As of the latest version, the parser now supports nested grouping with parentheses, allowing for more complex logical expressions.
Double Nested Expressions
You can now use nested parentheses for complex conditions:
- SQL
- CSS
SELECT * FROM DOM WHERE
TAG = 'a' AND (CLASS = 'active' OR (CLASS = 'link' AND ID = 'new-link'))
a.active, a#new-link.link {
/* Styles */
}
Triple Nested Expressions
Even deeper nesting is now supported:
- SQL
- CSS
SELECT * FROM DOM WHERE
TAG = 'div' AND (CLASS = 'container' OR (CLASS = 'wrapper' AND (ID = 'main' OR ID = 'sidebar')))
div.container, div#main.wrapper, div#sidebar.wrapper {
/* Styles */
}
Real-world Examples
Navigation Menu Selectors:
SELECT * FROM DOM WHERE
TAG = 'nav' AND (CLASS = 'main-menu' OR (CLASS = 'mobile-menu' AND ATTR('data-mobile') = 'true'))
Result: nav.main-menu, nav.mobile-menu[data-mobile="true"]
Form Field Selectors:
SELECT * FROM DOM WHERE
TAG = 'input' AND (ATTR('type') = 'text' OR (ATTR('type') = 'email' AND CLASS = 'validated'))
Result: input[type="text"], input[type="email"].validated
Limitations
While nested grouping is now supported, some complex cross-product operations may still have limitations:
Complex Cross-Products
Very complex expressions involving multiple cross-products may not generate all possible combinations:
-- This may not produce all 4 combinations in some cases
SELECT * FROM DOM WHERE
(TAG = 'button' OR TAG = 'input') AND (CLASS = 'primary' OR CLASS = 'secondary')
In such cases, consider breaking the query into multiple simpler expressions.