# 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 { … }
|
Source:
.foo-bar { … }
.foo_bar { … }
.fooBar { … }
.a { … }
.-foo { … }
._baz { … }
| Output:
.g { … }
.h { … }
.i { … }
.j { … }
.k { … }
.l { … }
|
Source:
.foo__bar { … }
.foo--bar { … }
.foo-bar--baz { … }
.foo__bar--baz { … }
.foo-bar__bar--baz { … }
| Output:
.m { … }
.n { … }
.o { … }
.p { … }
.q { … }
|
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 { … }
|
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 { … }
|
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"] { … }
|
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";
|
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');
|
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');
|
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>
|
Source:
<button
data-toggle="modal"
data-target="#__--modal-confirm-delete">
</button>
| Output:
<button
data-toggle="modal"
data-target="#t">
</button>
|
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>
|
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>
|
Source:
const ACTIVE_STATE = '__class--is_active';
component.classList.toggle(ACTIVE_STATE);
| Output:
const ACTIVE_STATE = 'a';
component.classList.toggle(ACTIVE_STATE);
|
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>
|