Selectors Level 4

Bon, vivement CSS4 hein…

Je veux faire un truc assez tordu : l’indentation des titres et des contenus.
Par exemple ça :

=======================
h1
-- p texte
-- h2
-- -- p texte
-- -- p em textgras
h1
-- h2
-- -- p texte
-- -- h3
-- -- -- p texte
-- h2
-- -- h3
=======================

Où le « -- » représente une marge.
Le truc doit marcher en 100% de CSS (pas de HTML ni de blocs imbriqués, ni de JS).

J’utilise les sélecteurs « foo~bar » pour ça (il cibles les éléments bar arrivant après un foo — pas forcément juste après)

h2~* { margin-left: 50px; }
h3~* { margin-left: 100px; }
h4~* { margin-left: 150px; }


Ok, mais non… car… le h2 suivant un h3 aura également son indentation à 100px, alors qu’il doit être à 0 (car le h2 hérite uniquement du h1)

Bien, je fais donc ça :

h2~* { margin-left: 50px; }
h3~:not(h2) { margin-left: 100px; }


Les éléments qui auront 100px de marge sera tout ce qui suit un h3, sauf si c’est un autre h2.

Et pour compléter, je fais aussi ça :

h2~:not(h2):not(h1) { margin-left: 50px; }
h3~:not(h3):not(h2):not(h1) { margin-left: 100px; }
h4~:not(h4):not(h3):not(h2):not(h1) { margin-left: 150px; }

Voilà, ça marche ? Les titres sont maintenant parfaitement indentés, c’est très bien… Mais il reste un problème.

Considérez ça :
h1
-- h2
-- -- h3
-- -- -- p texte
-- h2
-- -- p texte2

De combien est indenté le texte2 ? De 100px au lieu de 50px bien-sûr, car ce paragraphe est bien après un h2… mais aussi après un h3 (plus haut dans la page) et le CSS du h3 est prioritaire.
Merde.

Ok, je fais ça :

h4~:not(h4):not(h3):not(h2):not(h1) { margin-left: 150px; }
h3~:not(h3):not(h2):not(h1) { margin-left: 100px; }
h2~:not(h2):not(h1) { margin-left: 50px; }


Ça marche ? Non plus…
Car ici c’est le nombre de sélecteurs et les spécificités/priorités qui entrent en jeu.

Ok, vu que le h2~… a moins de sélecteurs, ajoutons un sélecteur juste pour sa spécificité : not(body). Celui-ci ne sera jamais rencontré, mais rendra tous les sélecteurs également spécifique :

h4~:not(h4):not(h3):not(h2):not(h1) { margin-left: 150px; }
h3~:not(h3):not(h2):not(h1):not(body) { margin-left: 100px; }
h2~:not(h2):not(h1):not(body):not(body) { margin-left: 50px; }


Ça marche ? Non !
Car maintenant ce qui vient après un h4 est annulé par le code venant après le h3 (lui même annulé par ce qui vient après un h2).

Bon bon, remettons les sélecteurs dans l’ordre 2,3,4 :

h2~:not(h2):not(h1):not(body):not(body) { margin-left: 50px; }
h3~:not(h3):not(h2):not(h1):not(body) { margin-left: 100px; }
h4~:not(h4):not(h3):not(h2):not(h1) { margin-left: 150px; }


Et… ça ne marche pas : on se retrouve avec le texte suivant un h2 suivant un h3 trop indenté (à cause de l’ordre d’écriture du CSS, non plus la spécificité).

Pas grave, je dois juste cibler des éléments suivant un h3, mais ne suivant pas un h2 (à moins qu’ils suivent un h3 après) :

h2~:not(h1):not(h2) { margin-left: 50px; }
h3~:not(h1):not(h2):not(h3):not(h2~*) { margin-left: 100px; }
h4~:not(h1):not(h2):not(h3):not(h4):not(h3~*):not(h2~*) { margin-left: 150px; }


Ah oui, mais non : un sélecteur « h2~* » dans un not() n’est pas autorisé : le :not() ne prend que les sélecteurs dits « simples ».

Ça ne viendra probablement qu’en CSS4.
(j’aurais le temps de passer mon doctorat en css-brain-fuck, je sais)

#cries.