CSS extensions / custom selectors

Thinking more about the CSS extensions draft and custom selectors...

I think we need to be very careful about allowing any turing-complete language to have its hooks in CSS rules -- most of what the spec already shows can already be done using DOM mutation observers and temporary classes. If someone wants to prototype selectors in JS, I believe that it can be done through that channel.

I spent some time thinking/searching for some use cases for selectors not covered. My conclusion is that for these to be useful, the :has() selector *really* needs to be made fast, or included in the spec with the caveat that overuse will cause perf issues.
 

1) Selecting a label by input type
----------------------------------

http://stackoverflow.com/questions/13031926/select-label-by-input-type

/* A selector that bolds the label for the associated focused input */
form input:focused /label-for/ label {
 font-weight: bold;
}

/* I’m inventing an “attribute capturing” := syntax here, bike-shedding welcome */

@custom-selector $a /--label-for/ $b
 $a[$id := “id”] /--root/ $b[for=$id];

@custom-selector $a /--root/ $b
 :root:has($a) $b;

Output equivalent:

form input:focused[$id := “id”] /--root/ label[for=$id]
:root:has(form input:focused[$id := “id”]) label[for=$id] { … }


2) Selecting a parent node of a subject
---------------------------------------

/* If a div has more than 10 siblings, show an overflow */
div.container:--n-children-of(10,.item) .overflow {
 display: block !important;
}

/* Shrink the font size when there are 5 or more items */
div.container .item:--n-siblings-of(5,.item) {
 font-size: smaller;
}

@custom-selector $subject:--n-siblings-of($n,$s)
 $subject:nth-child(1 of $s):nth-last-child($n of $s),
 $subject:nth-child(1 of $s):nth-last-child($n of $s) ~ $subject:nth-child(n of $s)

@custom-selector $subject:--n-children-of($n,$s)
 $subject:has(> :nth-child(1 of $s):nth-last-child($n of $s));

Output expansions:

div.container:--n-children-of(10,.item) .overflow
div.container:has(> :nth-child(1 of .item):nth-last-child(10 of .item)) .overflow { … }

div.container .item:--n-siblings-of(5,.item)
div.container .item:nth-child(1 of .item):nth-last-child(10 of .item):—self-of-sibling()
div.container :matches(.item:nth-child(1 of .item):nth-last-child(10 of .item), .item:nth-child(1 of .item):nth-last-child(10 of .item) ~ .item:nth-child(n of .item)) { … }


3) Previous/any sibling combinators
-----------------------------------

input /any-sibling/ label {
 float: left;
}

@custom-selector $a /--parent/ $b
 $b:has(> $a);

@custom-selector $a /--previous-sibling/ $b
 $a /--parent/ * > $b:has(+ $a);

@custom-selector $a /--any-sibling/ $b
 $a + $b, $a /--previous-sibling/ $b

Output expansion:

input + label, input /--previous-sibling/ label
input + label, input /--parent/ * > label:has(+ input)
input + label, *:has(> input) > label:has(+ input)

(OR)

@custom-selector $a /--any-sibling/ $b
 $a /--parent/ * > $b

Output expansion:

*:has(input) > label


4) Self or sibling
------------------

/* Make all columns a checkmark until the end of the row */
.row .col:hover:—self-or-sibling-matching(.col) .check-img {
 background-image: url(checked.png)
}

@custom-selector $subject:-—self-or-sibling-matching($s)
 $subject, $subject ~ $s


Output expansion:

.row .col:hover:—self-or-sibling-matching(.col) .check-img
.row :matches(.col:hover, .col:hover ~ .col) .check-img


Matt.

Received on Wednesday, 4 February 2015 16:59:18 UTC