Jak se v Tracy čaruje se specificitou selektorů

David Grudl
Nette Core | 8136
+
+4
-

Tracy se odjakživa potýká s velkým problémem: její CSS styly kolidují se styly stránky, ve které se zobrazuje.

Obrazovka Bluescreen fungovala tak, že při zobrazení vypnula všechny styly krom svých, takže tam ke kolizi nedocházelo (od verze 2.9 to zkušebně nedělá). Ale Debug bar a Dumper tuhle možnost nemají, musí fungovat současně s jinými styly a nějak kolize řešit.

Zkoušel jsem všechny možné techniky a najít spolehlivé řešení, jak se odstínit od ostatních stylů, jsem nenašel. Tak jsem se je snažil přebíjet resetem s vysokou specificitou a samotné styly pro Debug bar ještě přebíjely reset.

Vedle toho se objevil návrh, aby naopak Tracy styly nepotlačovala a bylo tak cíleně možné je využívat v panelech…


Odbočka: A selector's specificity is calculated as follows: (calculator)

  • count the number of ID selectors in the selector (= a)
  • count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= b)
  • count the number of type selectors and pseudo-elements in the selector (= c)
  • ignore the universal selector

Selectors inside the negation pseudo-class are counted like any other, but the negation itself does not count as a pseudo-class.

Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity.

*               /* a=0 b=0 c=0 -> specificity =   0 */
LI              /* a=0 b=0 c=1 -> specificity =   1 */
UL LI           /* a=0 b=0 c=2 -> specificity =   2 */
UL OL+LI        /* a=0 b=0 c=3 -> specificity =   3 */
H1 + *[REL=up]  /* a=0 b=1 c=1 -> specificity =  11 */
UL OL LI.red    /* a=0 b=1 c=3 -> specificity =  13 */
LI.red.level    /* a=0 b=2 c=1 -> specificity =  21 */
#x34y           /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO)   /* a=1 b=0 c=1 -> specificity = 101 */

Konec odbočky.


Přemýšlel jsem, jak zkombinovat CSS reset s možností, aby jakýkoliv užitečný styl probublal do Tracy. Vypadá to jako protimluv. Ale napadlo mě tohle: nechám, ať každé CSS pravidlo obsahující v selektoru #id nebo .class probublá do Debug baru. Aby se v něm projevilo, musela by třída nebo ID být v něm použitá taky, jinak prostě pravidlo nebude mířit na něj.

Ačkoliv, není to úplně pravda – Debug bar je přímým potomkem <body>, takže toto řešení nebude immuní vůči třídám nastaveným přímo na <body> nebo <html>, což nevím, jak obejít. A zasáhnou jej taky negativní selektory jako div:not(.class).

Co je ale potřeba uvnitř Debug baru vyresetovat, tak jsou CSS pravidla mající v selektoru jen HTML elementy, ty by totiž Tracy ovlivňovaly. Podle tabulky výše potřebuju mít co nejvyšší c, abych přebil jakékoliv c z jiného stylu, ale zároveň držet a a b na nule.

Jak zaměřit Debug bar bez použítí ID nebo třídy? Vytvořil jsem pro něj novou značku <tracy-div>. Takže původní reset s vysokou specificitou #tracy-debug, #tracy-debug * { ... } jsem nahradil za tracy-div, tracy-div * { ... }.

Ale tohle pravidlo má zase moc nízkou specificitu (specificity = 1), takže třeba pre code {...} jej přebije (specificity = 2). Napadl mě trik, jak ji zvýšit, a to zdánlivě nesmyslným zápisem tracy-div:not(a b) (specificity = 3). Tak funguje současný reset.css.

A ono zdá se, že to funguje (po nějakém ladění v setinkových verzích).

evromalarkey
Nette Blogger | 20
+
+7
-

Co zkusit shadow dom? Styly v shadowdomu v custom elementu jsou komplet odstíněný od ostatních stylů na stránce.

Marek Bartoš
Nette Blogger | 1171
+
0
-

@DavidGrudl Teoreticky bys mohl vytvořit v <body> nějaký prázdný custom element a zjistit které styly podědil z html/body přes getComputedStyle a ty pak v Tracy vyrušit. I když spíš čekám, že se tím něco jiného šeredně rozbije.

David Grudl
Nette Core | 8136
+
+2
-

@evromalarkey tyjo, na shadow dom jsem si vůbec nevzpomněl, to je super nápad na odstínění!

Umístit Tracy do shadow dom a přidat API, pomocí kterého by se daly dovnitř posílat styly, mi připadá jako nejlepší cesta, protože je to hlavně bez hacků.