Logical Psuedo Selectors: A Proposal

When you get right down to it, CSS rules select matching sets of elements.  Sets and logic gates are two of the most fundamental and powerful concepts in computer science – at some level it is upon their backs that just about everything else builds.  Despite this, until pretty recently CSS has never had features that hinted at the concept of a set and that seems a shame because integrating the language of logic/sets could be a powerful combination.

What’s changing?

After many years during “the great stagnation” HTML and CSS are moving along quickly again. HTML has increased our ability to express semantics and CSS is adding new selector powers.  Selectors Level 3  is a done deal, work is well underway on Selectors Level 4 and we’ve already got a wiki of features for Selectors Level 5.  Likewise, we are adding long-needed features like Regions, scoped stylesheets, Shadow DOM and Generated Content.  All of these things combine to create a really positive future where CSS can really begin to live up to its potential and the visuals pertaining to good structures can managed via CSS without requiring changes to markup.

Two pseudo-classes in particular – in a group called Logical Combinators – currently :matches (some implemenations call it :any) and :not begin to bring with them some interesting possibilities.  Currently they are very limited and can only accept simple (or compound – depending on the level) selectors, but eventually they could accept complex selectors.  When that day comes we could begin talking about things in terms of sets.

A Proposal

4 Logical Combinators which can take complex selectors:

  • :anyof (:matches?) Filters elements based on whether they match ANY of the provided selector(s) (that is, selectors are OR’ed together) which may express different paths in the same tree.
  • :allof
    Filters elements based on whether they match ALL of the provided selector(s) (that is, selectors are AND’ed together) which may express different paths in the same tree.
  • :noneof (:not ?) Filter elements based on whether they match NONE of the provided selector(s) (that is, selectors are NOR’ed together) which may express different paths in the same tree.
  • :oneof
    Filters elements based on whether they match EXACTLY ONE of the provided selector(s) (that is, selectors are XOR’ed together) which may express different paths in the same tree.

An Example:
Given some rich markup that describes a structure in some local semantic terms (semantics important to my domain)…


<div class="cars">
<div class="domestic">
<div class="new" id="a">
<div class="cheap small efficient"><p class="car">2012 Ford Fiesta</p></div>
<div class="quality efficient"><p class="car">2012 Chrysler 300</p></div>
<div class="quality fast performance"><p class="car">2012 Dodge Charger</p></div>
</div>
<div class="used" id="b">
<div class="cheap small efficient"><p class="car">2009 Ford Fiesta</p></div>
<div class="cheap"><p class="car">2004 Chevy Malibu</p></div>
<div class="quality fast"><p class="car">2010 Dodge Charger</p></div>
</div>
</div>
<div class="foreign">
<div class="new" id="c">
<div class="cheap"><p class="car">2012 Kia Forte</p></div>
<div class="quality"><p class="car">2012 BMW 525i</p></div>
</div>
<div class="used" id="d">
<div class="cheap"><p class="car">2009 Kia Forte</p></div>
<div class="cheap efficient"><p class="car">2005 Toyota Camry</p></div>
<div class="quality"><p class="car">2009 Audi R5</p></div>
</div>
</div>
</div>

view raw

cars.html

hosted with ❤ by GitHub

I can use logical sets to add styles…


/* Style the cars that are new and have quality as well as domestic and peformance */
.cars div:allof(.new .quality, .domestic .performance) p {
color: red;
}
/* Style the cars that are foreign and used or domestic, new and effiecient. */
.cars div:anyof(.foreign .used, .domestic .new .efficient) p {
color: blue;
}
/* Style the efficient cars that are neither domestic and used nor foreign and new. */
.efficient:noneof(.domestic .used, .foreign .new) p {
color: green;
}
/* Style the cars that are only one of quality or fast (but not both). */
.cars div:oneof(.quality, .fast) p {
font-weight: bold;
}

view raw

cars.css

hosted with ❤ by GitHub

And they would style up as…
logical-combinators-in-action

Prollyfilling…

All of the above are prollyfilled currently and come “out of the box” with hitchjs (works in IE9 and all evergreen browsers) – they are all prefixed with -hitch-*.  If you’d like to play around with it, simply add the following script include:

<script type="text/javascript" src="http://www.hitchjs.com/dist/hitch-0.6.1.min.js"></script>

and add a data attribute to any <style> or <link> tag which contains hitch prollyfilled rules, for example:


<style type="text/css" data-hitch-interpret>
/* Style the cars that are foreign and used or domestic, new and effiecient. */
.cars div:-hitch-anyof(.foreign .used, .domestic .new .efficient) p {
color: blue;
}
</style>

Read the original docs we wrote for this.

1 thought on “Logical Psuedo Selectors: A Proposal

Leave a comment