Puis-je utiliser un pseudo-élément: avant ou: après sur un champ de saisie?

687

J'essaie d'utiliser le :afterpseudo-élément CSS sur un inputchamp, mais cela ne fonctionne pas. Si je l'utilise avec un span, cela fonctionne bien.

<style type="text/css">
.mystyle:after {content:url(smiley.gif);}
.mystyle {color:red;}
</style>

Cela fonctionne (met le smiley après "buu!" Et avant "un peu plus")

<span class="mystyle">buuu!</span>a some more

Cela ne fonctionne pas - il colore seulement une certaine valeur en rouge, mais il n'y a pas de smiley.

<input class="mystyle" type="text" value="someValue">

Qu'est-ce que je fais mal? dois-je utiliser un autre pseudo-sélecteur?

Remarque: je ne peux pas ajouter un spanautour de mon input, car il est généré par un contrôle tiers.

matra
la source
Si vous n'avez absolument aucun contrôle sur le HTML, essayez plutôt de changer le border-colorde input. Je trouve que c'est plus attirant l'attention.
Blazemonger

Réponses:

256

:afteret :beforene sont pas pris en charge dans Internet Explorer 7 et versions antérieures, sur aucun élément.

Il n'est pas non plus destiné à être utilisé sur des éléments remplacés tels que des éléments de formulaire (entrées) et des éléments d'image .

En d'autres termes, c'est impossible avec du CSS pur.

Cependant, si vous utilisez jquery, vous pouvez utiliser

$(".mystyle").after("add your smiley here");

Documents API sur .after

Pour ajouter votre contenu avec javascript. Cela fonctionnera sur tous les navigateurs.

Alex
la source
Alex, j'utilise IE8 et la dernière FF, donc IE7 n'est pas un problème. Je cherchais des documents sur la limitation de: après, mais je n'ai pas pu le trouver. w3.org/TR/CSS2/generate.html indique qu'il est inséré après le nœud actuel dans l'arborescence de documents, il devrait donc fonctionner dans les deux cas.
matra
3
Sauf si vous créez la page uniquement pour votre propre usage, un grand pourcentage d'Internet utilise toujours ces navigateurs. La spécification w3c dit oui; mais comme vous le savez, les navigateurs implémentent leur propre interprétation de la spécification. Utiliser: after sur une entrée ne fonctionnera que dans Opera 9+, mais n'est pas implémenté dans IE, FF, safari ou chrome en raison de la façon dont ils construisent en interne le DOM - encore une fois, cela ne peut pas être fait avec du CSS pur.
Alex
3
Je ne sais pas si c'était le cas en avril, mais Webkit prend en charge :afteren général, bien qu'il ne prenne en charge ni les entrées :beforeni :afterles entrées.
coreyward
258
Pour autant que je comprends le W3C :afteret les :beforepseudo-éléments, ils ne peuvent être placés que sur des éléments conteneurs. Pourquoi? Parce qu'ils sont ajoutés à l' intérieur de cet élément particulier. inputn'est pas un conteneur. buttonpar exemple, c'est pourquoi vous pouvez les mettre. Fonctionne comme prévu. La spécification dit en fait: avant et après le contenu de l'arborescence de documents d'un élément. Elle dit explicitement CONTENT . Un élément doit donc être un conteneur.
Robert Koritnik
29
La réponse suivante est bien meilleure .. Donne une raison réelle plutôt que de parler d'IE 7 (qui s'en soucie) et de jQuery (mauvaise idée)
Rowan
1305

:beforeet :afterrendre à l'intérieur d'un conteneur

et <input> ne peut pas contenir d'autres éléments.


Les pseudo-éléments ne peuvent être définis (ou mieux ne sont supportés que) sur les éléments conteneurs. Parce que la façon dont ils sont rendus est à l' intérieur le conteneur lui-même en tant qu'élément enfant. inputne peut pas contenir d'autres éléments, ils ne sont donc pas pris en charge. A buttond'autre part, c'est aussi un élément de formulaire qui les prend en charge, car c'est un conteneur d'autres sous-éléments.

Si vous me demandez, si un navigateur n'affiche ces deux pseudo-éléments sur des éléments non-conteneurs, il est un bug et une conformité non standard. La spécification parle directement du contenu de l'élément ...

Spécification W3C

Si nous lisons attentivement la spécification, elle indique en fait qu'elle est insérée à l' intérieur un élément conteneur:

Les auteurs spécifient le style et l'emplacement du contenu généré avec les pseudo-éléments: avant et: après. Comme leurs noms l'indiquent, les pseudo-éléments: avant et: après spécifient l'emplacement du contenu avant et après le contenu de l'arborescence de documents d'un élément. La propriété 'content', en conjonction avec ces pseudo-éléments, spécifie ce qui est inséré.

Voir? le contenu de l' arborescence de documents d'un élément . Si je comprends bien, cela signifie dans un conteneur.

Robert Koritnik
la source
119
+1 Beaucoup mieux que la réponse acceptée. Merci pour l'explication claire de la norme elle-même. Voilà pour [required]::before { content "*"; color: red; }: P
Kevin Peno
93
Astuce: Si vous rencontrez le problème avec juste une entrée de soumission comme <input type="submit" value="Send"/>, utilisez <button type="submit">Send</button>plutôt. La présentation est identique mais <button>est un conteneur et prend donc en charge :beforeet :after.
grippe
15
Et alors <hr />? Je pensais que ce n'était pas un élément conteneur, mais il pouvait être rendu :afteret :before jsfiddle.net/Uf88j/1
deathlock
7
@deathlock: c'est effectivement intéressant. Je dirais que ce doit être une sorte d'anomalie et je ne m'appuierais pas sur le fait qu'il fonctionne sur plusieurs navigateurs ou versions croisées ... HR n'est pas un élément conteneur et ne devrait donc pas autoriser les pseudo-éléments. Même la norme W3C dit qu'elle n'autorise aucun contenu. Et si vous recherchez un élément void, vous pouvez voir que ces éléments ne doivent en aucun cas avoir de contenu. Les pseudo-éléments sont du contenu, alors attendez-vous à ce que la future version du navigateur ne les affiche pas.
Robert Koritnik
5
" : avant et: après le rendu à l'intérieur d'un conteneur " Les pseudo-éléments: avant et: après viennent " avant et après le contenu ". Pas "au début ou à la fin" du conteneur. La spécification ne mentionne pas de conteneur . Avec des balises comme pet h1, le contenu est à l'intérieur de la balise, donc avant / après apparaissent également à l'intérieur. Avec des éléments comme inputet hr,: avant et: après apparaîtrait toujours avant ou après le contenu, mais aucun conteneur n'est impliqué (en particulier pour input). entrée: vérifié: avant est largement utilisé pour indiquer les cases à cocher en cours de vérification via css.
Radley Sustaire
60

Curieusement, cela fonctionne avec certains types d'entrée. Au moins dans Chrome,

<input type="checkbox" />

fonctionne bien, comme

<input type="radio" />

C'est juste type=textet quelques autres qui ne fonctionnent pas.

vals
la source
1
@ANeves, cela a fonctionné dans Chromium pour moi, mais pas dans Firefox.
kcpr
45

Voici une autre approche (en supposant que vous avez le contrôle du HTML): ajoutez un vide <span></span>juste après l'entrée et ciblez-le en CSS en utilisantinput.mystyle + span:after

.field_with_errors {
  display: inline;
  color: red;
}
.field_with_errors input+span:after {
  content: "*"
}
<div class="field_with_errors">Label:</div>
<div class="field_with_errors">
  <input type="text" /><span></span> 
</div>

J'utilise cette approche dans AngularJS car elle ajoutera .ng-invalidautomatiquement des classes aux <input>éléments de formulaire et au formulaire, mais pas au <label>.

Blazemonger
la source
1
Il permet d'ajouter des actions de vol stationnaire, comme: input:hover+span:after{color: blue}. Upvote.
krassowski
2
Pourquoi cette réponse a-t-elle si peu de votes positifs? Je pense que les connaissances théoriques sont importantes, mais cela résout le problème.
jorgefpastor
Belle option pour résoudre le problème.
Jester
40

:beforeet :aftersont appliqués à l'intérieur d'un conteneur, ce qui signifie que vous pouvez l'utiliser pour des éléments avec une balise de fin.

Elle ne s'applique pas aux éléments à fermeture automatique.

En passant, les éléments à fermeture automatique (tels que img / hr / input) sont également appelés «éléments remplacés», car ils sont remplacés par leur contenu respectif. "Objets externes" pour l'absence d'un meilleur terme. Une meilleure lecture ici

CatalinBerta
la source
Cette réponse est correcte, concise et fournit un contexte important. Devrait être sur le dessus, imo.
Paul
32

J'ai utilisé le background-imagepour créer le point rouge pour les champs obligatoires.

input[type="text"][required] {
  background-image: radial-gradient(red 15%, transparent 16%);
  background-size: 1em 1em;
  background-position: top right;
  background-repeat: no-repeat
}

Vue sur Codepen

Veiko Jääger
la source
21

Vous ne pouvez pas mettre un pseudo-élément dans un élément d'entrée, mais vous pouvez mettre un élément fantôme, comme un espace réservé!

input[type="text"] {   
  &::-webkit-input-placeholder {
    &:before {
      // your code
    }
  }
}

Pour le faire fonctionner dans d' autres navigateurs, l' utilisation :-moz-placeholder, ::-moz-placeholderet :-ms-input-placeholder dans différents sélecteurs . Impossible de regrouper les sélecteurs, car si un navigateur ne reconnaît pas, le sélecteur invalide l'intégralité de l'instruction.

MISE À JOUR : Le code ci-dessus fonctionne uniquement avec les pré-processeurs CSS (SASS, LESS ...), sans pré-processeurs utiliser:

input[type="text"]::-webkit-input-placeholder:before { // your code }
Shankar Cabus
la source
3
Agréable! Notez que le pseudo-élément d'espace réservé a un support de propriété limité: couleur, arrière-plan, espacement des mots, espacement des lettres, décoration du texte, alignement vertical, transformation du texte, hauteur de ligne, retrait du texte, opacité. Voir css-tricks.com/almanac/selectors/p/placeholder
henry
Merci pour l'astuce. N'oubliez pas que tout ce qui se trouve à l'intérieur du pseudo-élément disparaîtra lorsque la zone de saisie sera remplie par l'utilisateur. C'est un problème UX si tout ce que vous vouliez, comme moi, était d'afficher un glyphicon-searchbalisage sans toucher.
Davi Lima
2
Contexte expliquant pourquoi cela ne fonctionne plus: bugs.chromium.org/p/chromium/issues/detail?id=582301
Oliver Joseph Ash
18

Les pseudo-éléments comme :after, :beforene sont destinés qu'aux éléments conteneurs. Les éléments commençant et se fermant en un seul endroit comme <input/>, <img>etc. ne sont pas des éléments conteneurs et donc les pseudo-éléments ne sont pas pris en charge. Une fois que vous avez appliqué un pseudo-élément à un élément conteneur comme <div>et si vous inspectez le code (voir l'image), vous pouvez comprendre ce que je veux dire. En fait, le pseudo-élément est créé à l'intérieur de l'élément conteneur. Ce n'est pas possible en cas de <input>ou<img>

entrez la description de l'image ici

Pons Purushothaman
la source
15

Une solution de travail en CSS pur:

L'astuce consiste à supposer qu'il y a un élément dom après le champ de texte.

/*
 * The trick is here:
 * this selector says "take the first dom element after
 * the input text (+) and set its before content to the
 * value (:before).
 */
input#myTextField + *:before {
  content: "👍";
} 
<input id="myTextField" class="mystyle" type="text" value="someValue" />
<!--
  There's maybe something after a input-text
  Does'nt matter what it is (*), I use it.
  -->
<span></span>

(*) Solution limitée, cependant:

  • vous devez espérer qu'il y a un élément dom suivant,
  • vous devez espérer qu'aucun autre champ de saisie ne suit votre champ de saisie.

Mais dans la plupart des cas, nous connaissons notre code donc cette solution semble efficace et 100% CSS et 0% jQuery.


la source
2
input#myTextField ~ span:before {beaucoup mieux, mais span devrait avoir une classe vraiment plus explicite comme .tickou.icon
Val
13

J'ai trouvé ce message car j'avais le même problème, c'était la solution qui fonctionnait pour moi. Au lieu de remplacer la valeur de l'entrée, supprimez-la et placez absolument une plage de taille identique derrière la plage, la plage peut avoir une :beforepseudo-classe appliquée avec la police d'icône de votre choix.

<style type="text/css">

form {position: relative; }
.mystyle:before {content:url(smiley.gif); width: 30px; height: 30px; position: absolute; }
.mystyle {color:red; width: 30px; height: 30px; z-index: 1; position: absolute; }
</style>

<form>
<input class="mystyle" type="text" value=""><span class="mystyle"></span>
</form>
Morgan Feeney
la source
1
+1 - Cette solution fonctionne bien si vous utilisez un plugin ou un framework qui ajoute automatiquement des classes de validation à l'élément lui-même, mais pas à l'étiquette parent.
Blazemonger
9

Le plus grand malentendu ici est le sens des mots beforeet after. Ils ne se réfèrent pas à l'élément lui-même, mais au contenu de l'élément. Il en element:beforeest de même avant le contenu et element:afteraprès le contenu, mais les deux sont toujours à l'intérieur de l'élément d'origine.

L' inputélément n'a pas de contenu dans la vue CSS et n'a donc pas de contenu :beforeou un :afterpseudo-contenu. Cela est vrai pour de nombreux autres éléments vides ou remplacés.

Il n'y a pas de pseudo-élément faisant référence à l' extérieur de l'élément.

Dans un univers différent, ces pseudo-éléments auraient pu être appelés autrement pour rendre cette distinction plus claire. Et quelqu'un aurait même pu proposer un pseudo-élément qui est véritablement en dehors de l'élément. Jusqu'à présent, ce n'est pas le cas dans cet univers.

Manngo
la source
Je ne comprends peut-être pas ce que vous voulez dire, mais si je le fais, les pseudo-éléments fonctionnent sur h? jsfiddle.net/demetriad/o49yn5hq
Chris
1
@Chris C'est une surprise pour moi, et en cherchant, pour d'autres. Je pense que c'est une bizarrerie. hra toujours été ambigu du point de vue CSS, même si vous en voyez davantage dans la discussion sur la couleur.
Manngo
5

Selon une note de la spécification CSS 2.1, la spécification «ne définit pas entièrement l'interaction de: avant et: après avec les éléments remplacés (comme IMG en HTML). Cela sera défini plus en détail dans une future spécification. » Bien que ce inputne soit plus vraiment un élément remplacé, la situation de base n'a pas changé: l'effet de :beforeet :aftersur lui de manière non spécifiée et n'a généralement aucun effet.

La solution consiste à trouver une approche différente du problème que vous essayez de résoudre de cette façon. Placer le contenu généré dans un contrôle de saisie de texte serait très trompeur: pour l'utilisateur, il semblerait qu'il fasse partie de la valeur initiale du contrôle, mais il ne peut pas être modifié - il semblerait donc que ce soit quelque chose de forcé au début de la mais il ne serait pas soumis dans le cadre des données du formulaire.

Jukka K. Korpela
la source
3
Ceci est un commentaire, pas une réponse - un commentaire assez long, mais un commentaire néanmoins.
Blazemonger
@Blazemonger, ce n'est pas tout à fait clair quelle était la question, mais en tout cas, cette réponse aborde le même problème que la réponse acceptée, mais d'une manière plus correcte. Il n'est pas impossible d'utiliser du contenu généré pour des inputéléments, simplement non spécifié et en fonction du navigateur.
Jukka K. Korpela
5

Comme d'autres l'ont expliqué, les inputs sont des éléments vides un peu remplacés, donc la plupart des navigateurs ne vous permettent pas de générer ::beforeni de ::afterpseudo-éléments en eux.

Cependant, le groupe de travail CSS envisage d'autoriser explicitement ::beforeet ::afterdans le cas inputcontraire appearance: none.

Depuis https://lists.w3.org/Archives/Public/www-style/2016Mar/0190.html ,

Safari et Chrome autorisent tous les deux des pseudo-éléments sur leurs entrées de formulaire. Les autres navigateurs ne le font pas. Nous avons cherché à supprimer cela, mais le compteur d'utilisation enregistre ~ 0,07% des pages l'utilisant, ce qui correspond à 20 fois notre seuil de suppression maximal.

En fait, la spécification de pseudo-éléments sur les entrées nécessiterait de spécifier la structure interne des entrées au moins quelque peu, ce que nous n'avons pas encore réussi à faire (et je ne suis pas sûr que nous * pouvons * faire). Mais Boris a suggéré, dans l'une des bandes de bogues, de l'autoriser à l'apparence: aucune entrée - simplement les transformer en <div> s, plutôt qu'en éléments "un peu remplacés".

Oriol
la source
4

essayez ensuite:

label[for="userName"] {
  position: relative;
}

label[for="userName"]::after {
  content: '[after]';
  width: 22px;
  height: 22px;
  display: inline-block;
  position: absolute;
  right: -30px;
}
<label for="userName">
	Name: 
	<input type="text" name="userName" id="userName">
	</label>

Alex Ovchinkin
la source
3

Vous devez avoir une sorte de wrapper autour de l'entrée pour utiliser un pseudo-élément avant ou après. Voici un violon qui a un avant sur la div wrapper d'une entrée, puis place l'avant avant à l'intérieur de l'entrée - ou du moins il y ressemble. Évidemment, c'est un travail autour mais efficace dans un pincement et se prête à être réactif. Vous pouvez facilement en faire un après si vous avez besoin de mettre un autre contenu.

Violon de travail

Signe dollar à l'intérieur d'une entrée en tant que pseudo-élément: http://jsfiddle.net/kapunahele/ose4r8uj/1/

Le HTML:

<div class="test">
    <input type="text"></input>
</div>

Le CSS:

input {
    margin: 3em;
    padding-left: 2em;
    padding-top: 1em;
    padding-bottom: 1em;
    width:20%; 
}


.test {
    position: relative;
    background-color: #dedede;
    display: inline;
}

.test:before {
    content: '$';
    position: absolute;
    top: 0;
    left: 40px;
    z-index: 1;
}
Kapunahele Wong
la source
Belle astuce, mais vous pourriez faire un div stylisé pour "continuer" l'entrée. Voir ce violon jsfiddle.net/ose4r8uj/31 Mais vous pourriez aussi le faire plus facilement en utilisant bootstrap: getbootstrap.com/css/#forms-control-validation recherchez la partie "Avec des icônes optionnelles". Même si cela n'a rien à voir avec la question d'origine.
Victor Ivens
1
FYI pas bon pour: focus
,:
2

Si vous essayez de styliser un élément d'entrée avec: avant et: après, les chances sont que vous essayez d' imiter les effets d'autres span, div ou même des éléments de votre pile CSS.

Comme le souligne la réponse de Robert Koritnik,: avant et: après ne peuvent être appliqués qu'aux éléments de conteneur et les éléments d'entrée ne sont pas des conteneurs.

TOUTEFOIS, HTML 5 a introduit l' élément button qui est un conteneur et se comporte comme un élément d'entrée [type = "submit | reset"].

    <style>
    .happy:after { content:url(smiley.gif); }
    </style>

    <form>
    <!-- won't work -->
    <input class="happy" type="submit" value="Submit" />

    <!-- works -->
    <button class="happy">Submit</button>
    </form>
Kevin Conroy
la source
HTML 4 a en fait introduit l'élément <button>.
M. Lister
1

Sommaire

Cela ne fonctionne pas avec <input type="button">, mais cela fonctionne très bien avec <input type="checkbox">.

Violon : http://jsfiddle.net/gb2wY/50/

HTML :

<p class="submit">
    <input id="submit-button" type="submit" value="Post">
    <br><br>
    <input id="submit-cb" type="checkbox" checked>
</p>

CSS :

#submit-button::before,
#submit-cb::before {
    content: ' ';
    background: transparent;
    border: 3px solid crimson;
    display: inline-block;
    width: 100%;
    height: 100%;
    padding: 0;
    margin: -3px -3px;
}

la source
1

:beforeet :afterne fonctionne que pour les nœuds pouvant avoir des nœuds enfants car ils insèrent un nouveau nœud comme premier ou dernier nœud.

Juan Mendes
la source
0

J'ai trouvé que vous pouvez le faire comme ceci:

Vous devez avoir un parent div qui prend le padding et le: after. Le premier parent doit être relatif et le deuxième div doit être absolu afin que vous puissiez définir la position de l'after.

Patrick
la source
-1

J'ai une autre idée à utiliser à la place:

<div>
<input type="text"></input>text can be entered here</div>
Dima Dulin
la source
L'auteur de la question a explicitement déclaré qu'il ne pouvait pas modifier le balisage HTML. Cette réponse n'a pas de sens. Il aurait probablement dû être voté au lieu d'être modifié, @Morpheus.
Palec