# parse_selectors ## Selector names ### What constitutes a valid identifier? minify-selectors finds and encodes IDs and classes in selector rules. As long as the IDs and classes are valid as per https://www.w3.org/TR/selectors-3/#lex, minify-selectors will be able to pick them up to encode. 1. Starts with `#` or `.`. 2. Then optionally can be followed by a `-`. 3. Then a 'nmstart' character, which is any one of: - `[a-z]` — lowercase and uppercase Latin alphabet. - `[^\0-\177]` ('nonascii') — other characters that are not part of ASCII. - `{unicode}|\\[^\n\r\f0-9a-f]` ('escape') — escaping a character that is not a newline, return or unicode (which has it's own set of rules, see next point below). - `\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?` ('unicode') an unicode number (`\01F60E`) which is up to six hexadecimal characters long. Note: shorter unicode numbers can be terminated earlier by a space, newline, tab or form feed (`\265F `) rather than padding the leading digit(s) with zeros (`\00265F`) to reach the six character limit. 4. Finally none, one or multiple 'nmchar' characters, these are: - `[_a-z0-9-]` — lowercase and uppercase Latin alphabet, underscore and dash. - `[^\0-\177]` ('nonascii') — other characters that are not part of ASCII. - `{unicode}|\\[^\n\r\f0-9a-f]` ('escape') — escaping a character that is not a newline, return or unicode (which has it's own set of rules, see next point below). - `\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?` ('unicode') an unicode number (`\01F60E`) which is up to six hexadecimal characters long. Note: shorter unicode numbers can be terminated earlier by a space, newline, tab or form feed (`\265F `) rather than padding the leading digit(s) with zeros (`\00265F`) to reach the six character limit.
## CSS files and embedded styles support > **Please note:** > minify-selector currently does not properly support escaped or unicode characters in CSS selectors. See [#10](https://github.com/adamgian/minify-selectors/issues/10). > > ```scss > /* 😢 */ > .\265F -baz { … } > .🗿 { … } > ``` ### Selector naming CSS selector names are case-sensitive.

Source:

#foo { … }                                   ‎
.foo { … }
#FOO { … }
#FOO { … }
#FOOBAR { … }
.bar { … }
.FooBar { … }

Output:

#a { … }                                     ‎
.b { … }
#c { … }
#c { … }
#d { … }
.e { … }
.f { … }
As long as the selector name is valid (see above section: "What constitutes a valid identifier?"), minify-selectors will process it.

Source:

.foo-bar { … }                               ‎
.foo_bar { … }
.fooBar  { … }
.a { … }
.-foo { … }
._baz { … }

Output:

.g { … }                                     ‎
.h { … }
.i { … }
.j { … }
.k { … }
.l { … }
Naming conventions such as BEM are no problem for minify-selectors.

Source:

.foo__bar { … }                              ‎
.foo--bar { … }
.foo-bar--baz { … }
.foo__bar--baz { … }
.foo-bar__bar--baz { … }

Output:

.m { … }                                     ‎
.n { … }
.o { … }
.p { … }
.q { … }
### Chaining and combinations

Source:

div.foo { … }                                ‎
.foo.foo { … }
.foo.bar { … }
.foo * { … }
.foo .bar a { … }
.foo, .bar { … }
.foo > .bar { … }
.foo + .bar { … }
.foo ~ .bar { … }

Output:

div.b { … }                                  ‎
.b.b { … }
.b.e { … }
.b * { … }
.b .e a { … }
.b, .e { … }
.b > .e { … }
.b + .e { … }
.b ~ .e { … }
### Pseudo-classes and elements

Source:

.foo:link { … }                              ‎
.foo:visited { … }
.foo:hover { … }
.foo:active { … }
.foo:not(.bar) { … }
:is(.foo) .bar { … }
.foo:is(:not(.baz)) .bar { … }
:where(.foo, .baz) .bar { … }
.foo::after { … }
.foo::before { … }

Output:

.b:link { … }                                ‎
.b:visited { … }
.b:hover { … }
.b:active { … }
.b:not(.e) { … }
:is(.b) .e { … }
.b:is(:not(.r)) .e { … }
:where(.b, .r) .e { … }
.b::after { … }
.b::before { … }
### Attribute selectors > **Please note:** > Operators that do not match by string or word (`|=`, `^=`, `$=`, `*=`) and case-insensitive matches (`[class="Foo" i]`) are not supported. > > ```scss > /* 😢 */ > [class|="foo"] { … } > [class^="foo"] { … } > [class$="foo"] { … } > [class*="foo"] { … } > [class="foo" i] { … } > ``` > > As any non-valid flag in CSS rules are not valid and ignored by browsers, minify-selectors does not bother to process it. > > ```scss > /* 😢 */ > [class="foo" x] { … } > [class="foo" ?] { … } > ``` minify-selectors will work on attribute selectors with operators that guarantee a match — such as `=` (attribute value equals exactly) or `~=` (attribute value contains matching word).

Source:

.foo[disabled] { … }                         ‎
[id="foo"] { … }
[id='foo'] { … }
[id=foo] { … }
[class="bar"] { … }
[class='bar'] { … }
[class=bar] { … }
[class~="baz"] { … }
.foo[href$=".com.au"] { … }

Output:

.b[disabled] { … }                           ‎
[id="b"] { … }
[id='b'] { … }
[id=b] { … }
[class="e"] { … }
[class='e'] { … }
[class=e] { … }
[class~="r"] { … }
.b[href$=".com.au"] { … }

## JS files and embedded scripts support > **Please note:** > minify-selectors will not be able to detect selectors that are in variables. Selector names will need to be prefixed (see: [Marking selectors](#marking-selectors)). > > ```js > // 😢 > let foo = "foo"; > document.getElementById(foo); > > // 😢 > bar.innerHtml = ``; > ``` > > minify-selectors currently does not support parsing of selector names in expressions and logic within the function arguments. Selector names will need to be prefixed (see: [Marking selectors](#marking-selectors)). [#15](https://github.com/adamgian/minify-selectors/issues/15) aims to resolve this a certain extent. > > ```js > // 😢 > foo.classList.add(foo > bar ? "foo" : "bar"); > foo.classList.add(isFoo() ?? "foo"); > foo.classList.add(isFoo && "foo"); > ``` ### Classes

Source:

document.getElementsByClassName('foo');      ‎
bar.setAttribute('class', 'bar');
baz.classList.add('foo', 'bar', 'baz');
baz.classList.remove('foo', 'bar');
baz.classList.contains('baz');
baz.classList.replace('baz', 'foo');
baz.classList.toggle('baz', foo > bar);
baz.className += "foo";
baz.className = "bar";

Output:

document.getElementsByClassName('b');        ‎
bar.setAttribute('class', 'e');
baz.classList.add('b', 'e', 'r');
baz.classList.remove('b', 'e');
baz.classList.contains('r');
baz.classList.replace('r', 'b');
baz.classList.toggle('r', foo > bar);
baz.className += "b";
baz.className = "e";
### IDs

Source:

document.getElementById('foo');              ‎
bar.setAttribute('id', 'bar');
baz.setAttribute('for', 'foo');
baz.setAttribute('form', 'foo');
baz.setAttribute('list', 'foo');
baz.setAttribute('headers', 'foo');

Output:

document.getElementById('a');                ‎
bar.setAttribute('id', 'e');
baz.setAttribute('for', 'a');
baz.setAttribute('form', 'a');
baz.setAttribute('list', 'a');
baz.setAttribute('headers', 'a');
### Selector strings

Source:

document.querySelector('#foo');              ‎
document.querySelector('.foo > .bar');
document.querySelectorAll('.foo');
document.querySelector('p.baz:disabled');

Output:

document.querySelector('#a');                ‎
document.querySelector('.b > .e');
document.querySelectorAll('.b');
document.querySelector('p.r:disabled');

## HTML support ### Standard attributes minify-selectors supports all the standard HTML attibutes that contain selector classes and IDs — `aria-describedby`, `aria-labelledby`, `class`, `for`, `form`, `headers`, `id`, `itemref` and `list`.

Source:

<input id="foo" type="text">                 ‎
<div class="foo bar"></div>
<label for="foo"></label>
<a href="#" aria-labelledby="foo"></a>
<a href="#" aria-describedby="foo"></a>
<input form="foo">
<input list="foo">
<td headers="foo"></td>
<div itemref="foo bar"></div>

Output:

<input id="a" type="text">                   ‎
<div class="b e"></div>
<label for="a"></label>
<a href="#" aria-labelledby="a"></a>
<a href="#" aria-describedby="a"></a>
<input form="a">
<input list="a">
<td headers="a"></td>
<div itemref="a e"></div>
### Custom attributes Selectors in custom attribute values need to be prefixed (see: [Marking selectors](#marking-selectors)). In future, [#12](https://github.com/adamgian/minify-selectors/issues/12) will be another method to support custom attributes.

Source:

<button                                      ‎
  data-toggle="modal"
  data-target="#__--modal-confirm-delete">
</button>

Output:

<button                                      ‎
  data-toggle="modal"
  data-target="#t">
</button>
### URLs Target IDs in relative anchor links are also handled.

Source:

<a href="#foo"></a>                          ‎
<a href="/#bar"></a>
<a href="faq/#baz"></a>
<a href="https://example.com/foo/#bar"></a>

Output:

<a href="#a"></a>                            ‎
<a href="/#e"></a>
<a href="faq/#s"></a>
<a href="https://example.com/foo/#bar"></a>

## Marking selectors New feature in v1.0.0 You can instruct minify-selectors to either encode or ignore certain selectors by setting the appropriate prefix. ### CSS selectors Using `.__--` instead of `.` or `#__--` instead of `#` before the selector name will instruct minify-selectors to encode a class or ID respectively.

Source:

<button                                         ‎
  class="btn btn-default"
  data-toggle="modal"
  data-target="#__--confirm-prompt">
</button>
<div class="modal" id="confirm-prompt"></div>

Output:

<button                                         ‎
  class="a b"
  data-toggle="modal"
  data-target="#c">
</button>
<div class="d" id="c"></div>
### Selector names only Adding a `__class--` or `__id--` before a selector name will instruct minify-selectors to encode a selector as a class and ID respectively.

Source:

const ACTIVE_STATE = '__class--is_active';         ‎
component.classList.toggle(ACTIVE_STATE);

Output:

const ACTIVE_STATE = 'a';                          ‎
component.classList.toggle(ACTIVE_STATE);
### Ignoring selectors Adding a `__ignore--` before a selector name will instruct minify-selectors not to encode the selector.

Source:

<nav class="site-nav">
  <a href="about/#__ignore--contact"></a>
</nav>
<script>
  ctx = document.getElementByID('__ignore--canvas');
</script>

Output:

<nav class="a">                                 ‎
  <a href="about/#contact"></a>
</nav>
<script>
  ctx = document.getElementByID('canvas');
</script>