¿Puedo usar un pseudo-elemento: before o: after en un campo de entrada?

685

Estoy tratando de usar el :afterpseudo-elemento CSS en un inputcampo, pero no funciona. Si lo uso con a span, funciona bien.

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

Esto funciona (pone el smiley después de "¡buu!" Y antes de "un poco más")

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

Esto no funciona: solo colorea algunos valores en rojo, pero no hay carita sonriente.

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

¿Qué estoy haciendo mal? ¿Debo usar otro pseudo-selector?

Nota: No puedo agregar un spanalrededor de mi input, porque está siendo generado por un control de terceros.

matra
fuente
Si no tiene absolutamente ningún control sobre el HTML, intente cambiar el border-colordel input. Me parece más llamativo.
Blazemonger

Respuestas:

254

:aftery :beforeno son compatibles con Internet Explorer 7 y versiones anteriores, en ningún elemento.

Tampoco debe usarse en elementos reemplazados, como elementos de formulario (entradas) y elementos de imagen .

En otras palabras, es imposible con CSS puro.

Sin embargo, si usa jquery puede usar

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

Documentos de API en .after

Para agregar su contenido con javascript. Esto funcionará en todos los navegadores.

Alex
fuente
Alex, estoy usando IE8 y el último FF, por lo que IE7 no es un problema. Estaba buscando cualquier documentación sobre la limiación de: después, pero no pude encontrarla. w3.org/TR/CSS2/generate.html afirma que se inserta después del nodo actual en el árbol de documentos, por lo que debería funcionar en ambos casos.
matra
3
A menos que esté creando la página solo para su propio uso, un gran porcentaje de Internet todavía usa esos navegadores. La especificación w3c dice que sí; pero como bien sabe, los navegadores implementan su propia interpretación de la especificación. Uso: después de una entrada solo funcionará en Opera 9+, pero no se implementa en IE, FF, safari o cromo debido a la forma en que construyen internamente el DOM; de nuevo, no se puede hacer con CSS puro.
Alex
3
No estoy seguro de si este era el caso en abril, pero Webkit hace de soporte :after, en general, a pesar de que no es compatible con cualquiera :beforeo :afteren las entradas.
coreyward
258
Hasta donde entiendo W3C :aftery :beforepseudo elementos, solo se pueden poner en elementos contenedores. ¿Por qué? Porque se agregan dentro de ese elemento en particular. inputNo es un contenedor. buttonpor ejemplo, es por eso que puedes ponértelos. Funciona como se esperaba. La especificación realmente dice: antes y después del contenido del árbol de documentos de un elemento Dice explícitamente CONTENT . Entonces un elemento debe ser un contenedor.
Robert Koritnik el
29
La siguiente respuesta es mucho mejor ... Da una razón real en lugar de hablar sobre IE 7 (a quién le importa) y jQuery (mala idea)
Rowan
1304

:beforey :afterrenderizar dentro de un contenedor

y <input> no puede contener otros elementos.


Los pseudoelementos solo se pueden definir (o mejor dicho, solo se admiten) en los elementos del contenedor. Porque la forma en que se representan está dentro del contenedor como un elemento hijo. inputno puede contener otros elementos, por lo tanto, no son compatibles. A, buttonpor otro lado, también es un elemento de formulario que los admite, porque es un contenedor de otros subelementos.

Si me preguntas, si un navegador hace mostrar estos dos pseudo-elementos en elementos no contenedores, que es un error y una conformidad no estándar. La especificación habla directamente sobre el contenido del elemento ...

Especificación W3C

Si leemos cuidadosamente la especificación, en realidad dice que se insertan dentro de un elemento contenedor:

Los autores especifican el estilo y la ubicación del contenido generado con los pseudoelementos: before y: after. Como indican sus nombres, los pseudoelementos: before y: after especifican la ubicación del contenido antes y después del contenido del árbol de documentos de un elemento. La propiedad 'contenido', junto con estos pseudo-elementos, especifica lo que se inserta.

¿Ver? El contenido del árbol de documentos de un elemento . Según tengo entendido, esto significa dentro de un contenedor.

Robert Koritnik
fuente
119
+1 Mucho mejor que la respuesta aceptada. Gracias por la clara explicación del estándar en sí. Demasiado para [required]::before { content "*"; color: red; }: P
Kevin Peno
93
Consejo: Si tiene el problema con solo una entrada de envío <input type="submit" value="Send"/>, use <button type="submit">Send</button>en su lugar. La presentación es idéntica pero <button>es un contenedor y, por lo tanto, admite :beforey :after.
gripe
15
¿Qué hay de <hr />? Pensé que no era un elemento contenedor, pero podría renderizar :aftery :before jsfiddle.net/Uf88j/1
deathlock
77
@deathlock: eso es realmente interesante. Diría que debe ser algún tipo de anomalía y no confiaría en que funcionara entre navegadores o versiones cruzadas ... HR no es un elemento contenedor, por lo tanto, no debería permitir pseudo elementos. Incluso estándar W3C dice que permite sin contenido. Y si marca el elemento vacío , puede ver que estos elementos no deben tener ningún contenido bajo ninguna circunstancia. Los pseudo elementos son contenido, así que espere que la futura versión del navegador no los muestre.
Robert Koritnik
55
" : antes y: después de renderizar dentro de un contenedor " El: antes y: después de los pseudo elementos vienen " antes y después del contenido ". No "al principio o al final del" contenedor. La especificación no menciona un contenedor . Con etiquetas como py h1, el contenido está dentro de la etiqueta, por lo que antes / después también aparecen dentro. Con elementos como inputy hr, before y: after aún aparecerían antes o después del contenido, pero no hay ningún contenedor involucrado (especialmente para input). input: check: before se usa ampliamente para indicar que las casillas de verificación se verifican mediante css.
Radley Sustaire
60

Curiosamente, funciona con algunos tipos de entrada. Al menos en Chrome,

<input type="checkbox" />

funciona bien, igual que

<input type="radio" />

Es justo type=texty algunos otros que no funcionan.

vals
fuente
1
@ANeves, funcionó en Chromium para mí, pero no en Firefox.
kcpr
45

Aquí hay otro enfoque (suponiendo que tenga control del HTML): agregue un vacío <span></span>justo después de la entrada y apunte eso en CSS usandoinput.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>

Estoy usando este enfoque en AngularJS porque agregará .ng-invalidclases automáticamente a los <input>elementos del formulario y al formulario, pero no al <label>.

Blazemonger
fuente
1
Permite añadir acciones libración, como: input:hover+span:after{color: blue}. Voto a favor.
krassowski
2
¿Por qué esta respuesta tiene tan pocos votos positivos? Creo que el conocimiento teórico es importante, pero esto resuelve el problema.
jorgefpastor
Buena opción para resolver el problema.
Bufón
39

:beforey :afterse aplican dentro de un contenedor, lo que significa que puede usarlo para elementos con una etiqueta final.

No aplica para elementos de cierre automático.

En una nota al margen, los elementos que se cierran automáticamente (como img / hr / input) también se conocen como 'Elementos reemplazados', ya que se reemplazan con su contenido respectivo. "Objetos externos" por la falta de un término mejor. Una mejor lectura aquí

CatalinBerta
fuente
Esta respuesta es correcta, concisa y proporciona un contexto importante. Debería estar en la cima, imo.
Paul
31

Usé background-imagepara crear el punto rojo para los campos obligatorios.

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

Ver en Codepen

Veiko Jääger
fuente
20

¡No puede poner un pseudo elemento en un elemento de entrada, pero puede poner un elemento de sombra, como un marcador de posición!

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

Para hacer que funcione en otros navegadores, uso :-moz-placeholder, ::-moz-placeholdery :-ms-input-placeholder en diferentes selectores . No se pueden agrupar los selectores, porque si un navegador no reconoce el selector invalida toda la declaración.

ACTUALIZACIÓN : El código anterior funciona solo con preprocesador CSS (SASS, LESS ...), sin el uso de preprocesadores:

input[type="text"]::-webkit-input-placeholder:before { // your code }
Shankar Cabus
fuente
3
¡Agradable! Tenga en cuenta que el pseudo elemento de marcador de posición tiene un soporte de propiedad limitado: color, fondo, espacio entre palabras, espacio entre letras, decoración de texto, alineación vertical, transformación de texto, altura de línea, sangría de texto, opacidad. Ver css-tricks.com/almanac/selectors/p/placeholder
henry
Gracias por la pista. Solo recuerde que todo dentro del pseudo-elemento desaparecerá cuando el usuario complete el cuadro de entrada. Ese es un problema de UX si todo lo que querías, como yo, era mostrar un glyphicon-searchmarcado sin tocar.
Davi Lima
2
Algún contexto sobre por qué esto ya no funciona: bugs.chromium.org/p/chromium/issues/detail?id=582301
Oliver Joseph Ash
17

Los pseudo elementos como :after, :beforeson solo para elementos contenedores. Los elementos que comienzan y cierran en un solo lugar como <input/>, <img>etc., no son elementos contenedores y, por lo tanto, no se admiten pseudoelementos. Una vez que aplique un pseudo elemento al elemento contenedor como <div>y si inspecciona el código (vea la imagen), puede entender lo que quiero decir. En realidad, el pseudo elemento se crea dentro del elemento contenedor. Esto no es posible en caso de <input>o<img>

ingrese la descripción de la imagen aquí

Pons Purushothaman
fuente
15

Una solución de trabajo en CSS puro:

El truco es suponer que hay un elemento dom después del campo de texto.

/*
 * 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>

(*) Solución limitada, sin embargo:

  • tienes que esperar que haya un siguiente elemento dom,
  • tiene que esperar que ningún otro campo de entrada siga a su campo de entrada.

Pero en la mayoría de los casos, conocemos nuestro código, por lo que esta solución parece eficiente y 100% CSS y 0% jQuery.


fuente
2
input#myTextField ~ span:before {mucho mejor, pero span debería tener una clase realmente para ser más explícita como .ticko.icon
Val
13

Encontré esta publicación porque tenía el mismo problema, esta fue la solución que funcionó para mí. A diferencia de reemplazar el valor de la entrada, simplemente elimínelo y coloque absolutamente un tramo detrás del mismo que sea del mismo tamaño, el tramo puede tener una :beforepseudo clase aplicada con la fuente de icono que elija.

<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
fuente
1
+1: esta solución funciona bien si está utilizando un complemento o marco que agrega automáticamente clases de validación al elemento en sí, pero no a la etiqueta principal.
Blazemonger
9

El mayor malentendido aquí es el significado de las palabras beforey after. No se refieren al elemento en sí, sino al contenido del elemento. Entonces, element:beforeestá antes del contenido, y element:afterestá después del contenido, pero ambos todavía están dentro del elemento original.

El inputelemento no tiene contenido en la vista CSS y, por lo tanto, no tiene :beforeo tiene :afterpseudo contenido. Esto es cierto para muchos otros elementos vacíos o reemplazados.

No hay un pseudo elemento que se refiera al exterior del elemento.

En un universo diferente, estos pseudo elementos podrían haberse llamado de otra manera para aclarar esta distinción. Y alguien podría incluso haber propuesto un pseudo elemento que está realmente fuera del elemento. Hasta ahora, este no es el caso en este universo.

Manngo
fuente
Puede que no entienda lo que quieres decir, pero si lo hago, ¿los pseudo elementos funcionan en hr? jsfiddle.net/demetriad/o49yn5hq
Chris
1
@ Chris Eso es una sorpresa para mí, y al buscar, para algunos otros. Creo que es una peculiaridad. hrsiempre ha sido ambiguo desde el punto de vista de CSS, aunque lo ve más al hablar del color.
Manngo
5

Según una nota en la especificación CSS 2.1, la especificación "no define completamente la interacción de: before y: after con elementos reemplazados (como IMG en HTML). Esto se definirá con más detalle en una especificación futura ". Aunque inputya no es realmente un elemento reemplazado, la situación básica no ha cambiado: el efecto de :beforey :aftersobre él no está especificado y generalmente no tiene ningún efecto.

La solución es encontrar un enfoque diferente para el problema que está tratando de abordar de esta manera. Poner contenido generado en un control de entrada de texto sería muy engañoso: para el usuario, parecería ser parte del valor inicial en el control, pero no se puede modificar, por lo que parecería ser algo forzado al comienzo del control, pero aún así no se enviaría como parte de los datos del formulario.

Jukka K. Korpela
fuente
3
Este es un comentario, no una respuesta, un comentario bastante largo, pero no obstante un comentario.
Blazemonger
@Blazemonger, no está del todo claro cuál era la pregunta, pero en cualquier caso, esta respuesta aborda el mismo problema que la respuesta aceptada, pero de una manera más correcta. No es imposible usar contenido generado para inputelementos, solo no especificado y dependiendo del navegador.
Jukka K. Korpela
5

Como otros explicaron, los inputs son elementos vacíos reemplazados, por lo que la mayoría de los navegadores no le permitirán generar ::beforeni ::afterpseudoelementos en ellos.

Sin embargo, el Grupo de Trabajo CSS está considerando permitir explícitamente ::beforey ::afteren caso de que lo inputhaya hecho appearance: none.

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

Safari y Chrome permiten seudoelementos en sus entradas de formulario. Otros navegadores no lo hacen. Buscamos eliminar esto, pero el contador de uso está grabando ~ .07% de las páginas que lo usan, que es 20 veces nuestro umbral máximo de eliminación.

En realidad, la especificación de pseudoelementos en las entradas requeriría especificar la estructura interna de las entradas al menos un poco, lo que aún no hemos logrado hacer (y no estoy seguro de que * podamos * hacer). Pero Boris sugirió, en uno de los subprocesos de errores, permitirlo en apariencia: ninguna entrada, básicamente solo convertirlos en <div> s, en lugar de elementos "reemplazados".

Oriol
fuente
4

prueba a continuación:

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
fuente
3

Debe tener algún tipo de envoltorio alrededor de la entrada para usar un pseudo-elemento anterior o posterior. Aquí hay un violín que tiene un antes en el contenedor contenedor de una entrada y luego coloca el antes dentro de la entrada, o al menos así lo parece. Obviamente, este es un trabajo alternativo pero efectivo en caso de apuro y se presta para ser receptivo. Puedes hacer esto fácilmente después si necesitas poner algún otro contenido.

Violín de trabajo

Signo de dólar dentro de una entrada como un pseudo-elemento: http://jsfiddle.net/kapunahele/ose4r8uj/1/

El HTML:

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

El 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
fuente
Buen truco, pero puedes hacer un div estilizado para "continuar" la entrada. Vea este violín jsfiddle.net/ose4r8uj/31 Pero también podría hacerlo más fácilmente usando bootstrap: getbootstrap.com/css/#forms-control-validation busque la parte "Con iconos opcionales". Aunque, esto no tiene nada que ver con la pregunta original.
Victor Ivens
1
Para su información, no es bueno para: foco
,: pasar el mouse
2

Si está tratando de diseñar un elemento de entrada con: before y: after, es probable que esté tratando de imitar los efectos de otros span, div o incluso elementos en su pila CSS.

Como señala la respuesta de Robert Koritnik,: before y: after solo pueden aplicarse a elementos de contenedor y los elementos de entrada no son contenedores.

SIN EMBARGO, HTML 5 introdujo el elemento de botón que es un contenedor y se comporta como un elemento de entrada [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
fuente
HTML 4 en realidad introdujo el elemento <button>.
Sr. Lister el
1

Resumen

No funciona con <input type="button">, pero funciona bien con <input type="checkbox">.

Violín : 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;
}

fuente
1

:beforey :aftersolo funciona para nodos que pueden tener nodos secundarios ya que insertan un nuevo nodo como el primer o el último nodo.

Juan mendes
fuente
0

Descubrí que puedes hacerlo así:

Debe tener un padre div que tome el relleno y el: después. El primer padre debe ser relativo y el segundo div debe ser absoluto para que pueda establecer la posición del after.

Patricio
fuente
-1

Tengo otra idea, use esto en su lugar:

<div>
<input type="text"></input>text can be entered here</div>
Dima Dulin
fuente
El autor de la pregunta declaró explícitamente que no pueden cambiar el marcado HTML. Esta respuesta no tiene sentido. Probablemente debería haber sido rechazado en lugar de editado, @Morpheus.
Palec