CSS: après ne pas ajouter de contenu à certains éléments

100

J'ai du mal à comprendre le comportement de la :afterpropriété CSS . Selon les spécifications ( ici et ici ):

Comme leur nom l' indique, les :beforeet :afterpseudo-éléments spécifient l'emplacement du contenu avant et après le contenu de l' arbre de documents d'un élément.

Cela ne semble pas imposer de restrictions sur les éléments qui peuvent avoir une propriété :after(ou :before). Cependant, cela semble ne fonctionner qu'avec des éléments spécifiques ... <p>fonctionne, <img>ne fonctionne pas, <input>ne fonctionne pas <table>. Je pourrais tester plus, mais le point est fait. Notez que cela semble assez cohérent entre les navigateurs. Qu'est-ce qui détermine si un objet peut accepter une propriété :beforeand :after?

Eykanal
la source

Réponses:

156

imget inputsont tous deux des éléments remplacés .

Un élément remplacé est tout élément dont l'apparence et les dimensions sont définies par une ressource externe. Des exemples comprennent des images ( <img>tags), plug - ins ( <object>tags), et des éléments de forme ( <button>, <textarea>, <input>et <select>balises). Tous les autres types d'éléments peuvent être appelés éléments non remplacés.

:beforeet :afterne fonctionnent qu'avec des éléments non remplacés.

De la spécification :

Remarque. Cette spécification ne définit pas entièrement l'interaction des éléments remplacés :beforeet :afteravec ceux-ci (comme IMG en HTML). Cela sera défini plus en détail dans une future spécification.

Avec span:before, span:after, le DOM ressemble à ceci:

<span><before></before>Content of span<after></after></span>

Évidemment, cela ne fonctionnera pas avec <img src="" />.

trentenaire
la source
2
"Le contenu généré ne modifie pas l'arborescence du document." Je serais donc surpris si vous pouviez trouver quelque chose comme " <before></before>" dans la source.
Knu
4
@Knu: Vous avez raison, je l'ai mal expliqué. Vous ne trouverez jamais <before></before>. J'aurais dû dire "faire semblant de DOM" ou quelque chose comme ça. Le but était de montrer cela :beforeet d' :afterêtre à l'intérieur de l'élément, pas à l'extérieur.
thirtydot
Non, ils ne sont pas stockés dans le shadow DOM.
outil du
3
La spécification citée ne dit pas cela :beforeet :afterne fonctionne pas pour les éléments remplacés; il dit simplement qu'il ne «définit pas complètement» comment et que cela sera défini à l'avenir (ce qui ne s'est pas produit jusqu'à présent). Ce qui se passe dans DOM n'a pas d'importance ici. Bien que les navigateurs ne prennent pas en charge ces pseudo-éléments pour certains éléments, ce n'est pas dans les spécifications, juste ce que font les implémentations.
Jukka K. Korpela
Je considérions logique que l'explication ::beforeet ::afterne pas travailler pour vide élément (vide) qui n'ont un contenu réel, avant / après quoi ils pourraient appliquer. Mais étonnamment, ils fonctionnent pour hrélément dans presque tous les navigateurs.
Ilya Streltsyn
9

:beforeet :afterne sont pas obligés de fonctionner pour les éléments remplacés, et les spécifications CSS ne spécifient pas comment ils fonctionneraient pour eux, et le concept d'élément remplacé est quelque peu vague.

La spécification CSS 2.1 suggère clairement qu'ils peuvent fonctionner pour les éléments remplacés, en disant simplement qu'elle ne «définit pas complètement» comment. Cela concerne le problème selon lequel un élément remplacé doit avoir son propre rendu visuel, qui n'est pas contrôlé par CSS, alors que les pseudo-éléments devraient ajouter quelque chose au contenu de l'élément. La spécification ajoute que cela sera défini «plus en détail» dans une future spécification, mais cela n'a pas eu lieu jusqu'à présent.

Les fournisseurs de navigateurs ont simplement décidé d'éviter les problèmes en n'implémentant pas du tout ces pseudo-éléments pour certains éléments.

On ne sait pas du tout ce que signifie «élément remplacé», et le sens semble avoir quelque peu changé. Il est souvent interprété comme signifiant la même chose qu'un élément vide (un élément avec un EMPTYcontenu déclaré, c'est-à-dire un élément qui ne peut pas avoir de contenu), mais CSS 2.1 lui-même montre un exemple de feuille de style avec le sélecteur br:before(bien que les navigateurs l'aient ignoré, implémentant brleur propre façon). On peut affirmer que de plus en plus d'éléments sont passés dans le champ d'application du rendu CSS, au moins en partie. Par exemple, un inputélément (y compris sa police, ses couleurs, etc.) est largement contrôlable avec CSS dans les navigateurs modernes.

Les navigateurs actuels (Firefox, IE, Chrome) ne semblent pas soutenir les :afteret :beforepseudo-éléments pour les éléments vides autres que hr. Pour hr, IE et Chrome placent le contenu généré dans une zone encadrée, qui est la mise en œuvre de hr; le contenu rend la boîte plus haute. Firefox place le contenu des deux (!) Pseudo-éléments après la règle horizontale qui est son implémentation hr. Cette variation illustre les types de problèmes d '«interaction» auxquels se réfère CSS 2.1.

On prétend souvent que ces pseudo-éléments ne peuvent pas être utilisés pour des éléments vides car leurs définitions HTML ne permettent aucun contenu. Ceci est une erreur de catégorie. Les règles de syntaxe d'un langage de balisage ne restreignent pas ce que vous pouvez faire en CSS

Pour conclure, :afteret ne :beforesont actuellement pas utilisables pour les éléments vides (sauf marginalement pour hr), mais cela est principalement dû aux implémentations et peut changer dans le futur.

Jukka K. Korpela
la source
-1

Les éléments qui n'ont pas de balise de fermeture sont des éléments vides et ils ne peuvent pas afficher de contenu à l'intérieur:

https://www.w3.org/TR/html5/syntax.html#void-elements

Tous les navigateurs Blink, Webkit et Quantum vous permettent de créer des pseudo éléments uniquement sur des cases à cocher, mais cela est controversé car aucune spécification ne permet ce comportement.

Voici un exemple: https://codepen.io/equinusocio/pen/BOBaEM/

input[type="checkbox"] {
  appearance: none;
  color: #000;
  width: 42px;
  height: 24px;
  border: 1px solid currentColor;
  border-radius: 100px;
  cursor: pointer;
  transition: all 100ms;
  background-size: 30%;
  outline: none;
  position: relative;
  box-sizing: border-box;
  background-color: #eee;
  transition: background-color 200ms;

  &::before {
    content: '';
    position: absolute;
    left: 2px;
    top: 2px;
    bottom: 2px;
    height: 18px;
    width: 18px;
    border-radius: 50%;
    background-color: currentColor;
    will-change: transform;
    transition: transform 200ms cubic-bezier(.01,.65,.23,1);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  }

  &:checked {
    background-color: aquamarine;

    &::before {
      transform: translateX(100%);
    }
  }
}
Mattia Astorino
la source
cela ne fonctionnera pas dans tous les navigateurs ... et il n'y a aucune spécification qui dit maintenant que nous pouvons ... si vous en avez un, veuillez le partager car il n'est pas sûr de considérer un pseudo élément avec une entrée
Temani Afif
Cela fonctionne dans tous les navigateurs sauf IE. Même flexbox n'est pas pris en charge par IE 9, alors où est le problème. Cette solution fonctionne sur tous les navigateurs Blink, Webkit et Quantum et peut être très utile pour les personnes qui travaillent sur un environnement uniquement Webkit comme Electron.
Mattia Astorino
Comme vous l'avez dit dans votre réponse, il n'y a pas de spécifications pour cela, donc un jour, il peut cesser de fonctionner. Ce n'est pas la seule chose qui se comporte et fonctionne sans aucune spécification définie, mais nous ne devrions jamais nous fier à eux et dire qu'ils fonctionnent. c'est comme des balises obsolètes, elles fonctionnent toujours mais il faut arrêter de les utiliser car un jour elles ne le seront plus. Alors oui, cela peut être utile aux gens et mes commentaires sont également utiles pour avertir les gens qu'ils doivent être conscients que ce n'est pas officiel.
Temani Afif