Posso usar um pseudoelemento a: before ou: after em um campo de entrada?

685

Estou tentando usar o :afterpseudoelemento CSS em um inputcampo, mas ele não funciona. Se eu usá-lo com um span, ele funciona bem.

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

Isso funciona (coloca o smiley depois de "buu!" E antes de "um pouco mais")

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

Isso não funciona - apenas cores algum valor em vermelho, mas não há smiley.

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

O que estou fazendo errado? devo usar outro pseudo-seletor?

Nota: Não consigo adicionar um spanao redor do meu input, porque ele está sendo gerado por um controle de terceiros.

matra
fonte
Se você não tem absolutamente nenhum controle sobre o HTML, tente alterar o border-colordo input. Acho que é mais atenção.
Blazemonger

Respostas:

254

:aftere :beforenão são suportados no Internet Explorer 7 e inferior, em nenhum elemento.

Também não deve ser usado em elementos substituídos, como elementos de formulário (entradas) e elementos de imagem .

Em outras palavras, é impossível com CSS puro.

No entanto, se você estiver usando jquery, poderá usar

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

Documentos da API em .after

Para anexar seu conteúdo com javascript. Isso funcionará em todos os navegadores.

Alex
fonte
Alex, estou usando o IE8 e o FF mais recente, portanto o IE7 não é um problema. Eu estava procurando por qualquer documentação sobre limitação de: after, mas não consegui encontrá-la. w3.org/TR/CSS2/generate.html afirma que ele é inserido após o nó atual na árvore de documentos, portanto, deve funcionar nos dois casos.
Matra
3
A menos que você esteja criando a página apenas para uso próprio, uma grande porcentagem da Internet ainda usa esses navegadores. A especificação do w3c diz que sim; mas como você sabe, os navegadores implementam sua própria interpretação das especificações. Usar: after em uma entrada só funcionará no Opera 9+, mas não é implementado no IE, FF, safari ou chrome devido à maneira como eles constroem internamente o DOM - novamente, isso não pode ser feito com CSS puro.
7288 Alex
3
Não tenho certeza se esse foi o caso em abril, mas o Webkit é compatível :afterem geral, embora não seja compatível com entradas :beforeou :afterentradas.
precisa saber é o seguinte
258
Tanto quanto eu entendo W3C :aftere :beforepseudo elementos, eles só podem ser colocados em elementos de contêiner. Por quê? Porque eles são anexados dentro desse elemento específico. inputnão é um contêiner. buttonpor exemplo, é por isso que você pode colocá-los. Funciona como esperado. A especificação realmente diz: antes e depois do conteúdo da árvore de documentos de um elemento Diz explicitamente CONTENT . Portanto, um elemento deve ser um contêiner.
Robert Koritnik
29
A próxima resposta é muito melhor .. dá razão real em vez de falar sobre o IE 7 (quem se importa) e jQuery (má idéia)
Rowan
1304

:beforee :afterrenderizar dentro de um contêiner

e <input> não pode conter outros elementos.


Os pseudoelementos só podem ser definidos (ou melhor, apenas são suportados) nos elementos do contêiner. Porque a maneira como eles são renderizados está dentro do próprio contêiner como um elemento filho. inputnão pode conter outros elementos, portanto, eles não são suportados. Por buttonoutro lado, também é um elemento de formulário que os suporta, porque é um contêiner de outros subelementos.

Se você me perguntar, se algum navegador faz exibir esses dois pseudo-elementos em elementos não-contêiner, que é um bug e uma conformidade não-padrão. A especificação fala diretamente sobre o conteúdo do elemento ...

Especificação W3C

Se lermos com atenção a especificação , na verdade, ela será inserida em um elemento que contém:

Os autores especificam o estilo e a localização do conteúdo gerado com os pseudoelementos: before e: after. Como seus nomes indicam, os pseudoelementos: before e: after especificam o local do conteúdo antes e depois do conteúdo da árvore de documentos de um elemento. A propriedade 'content', em conjunto com esses pseudoelementos, especifica o que é inserido.

Vejo? o conteúdo da árvore de documentos de um elemento . Pelo que entendi, isso significa dentro de um contêiner.

Robert Koritnik
fonte
119
+1 Muito melhor que a resposta aceita. Obrigado pela explicação clara do próprio padrão. Tanto por [required]::before { content "*"; color: red; }: P
Kevin Peno
93
Dica: se você estiver tendo problemas apenas com uma entrada de envio <input type="submit" value="Send"/>, use <button type="submit">Send</button>. A apresentação é idêntica, mas <button>é um contêiner e, portanto, suporta :beforee :after.
gripe
15
Que tal <hr />? Eu pensei que não era um elemento de recipiente, mas poderia tornar :aftere :before jsfiddle.net/Uf88j/1
Deathlock
7
@ deadlock: isso é realmente interessante. Eu diria que deve ser algum tipo de anomalia e não confiaria nele trabalhando entre navegadores ou versões cruzadas ... O RH não é um elemento de contêiner, portanto, não deve permitir pseudo-elementos. Mesmo padrão W3C diz que ele permite que qualquer conteúdo. E se você buscar por elemento vazio você pode ver que estes elementos não devem ter qualquer conteúdo em qualquer circunstância. Pseudoelementos são conteúdo, portanto, espere que a versão futura do navegador falhe ao exibi-los.
Robert Koritnik
5
" : before e: after são renderizados dentro de um contêiner " Os pseudo-elementos: before e: after vêm " before and after the content ". Não "no início ou no final" do contêiner. A especificação não menciona um contêiner . Com tags como pe h1, o conteúdo está dentro da tag, portanto, antes / depois também aparecem dentro. Com elementos como inpute hr,: antes e: depois ainda apareceria antes ou depois do conteúdo, mas não há contêiner envolvido (especialmente para input). entrada: marcada: antes é amplamente usada para indicar caixas de seleção sendo checadas via css.
Radley Sustaire
60

Estranhamente, ele funciona com alguns tipos de entrada. Pelo menos no Chrome,

<input type="checkbox" />

funciona bem, igual a

<input type="radio" />

É apenas type=texte alguns outros que não funcionam.

vals
fonte
1
@ ANeves, funcionou no Chromium para mim, mas não no Firefox.
Kcpr 07/04/19
45

Aqui está outra abordagem (supondo que você tenha controle do HTML): adicione um vazio <span></span>logo após a entrada e direcione-o para 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>

Estou usando essa abordagem no AngularJS porque ele adicionará .ng-invalidclasses automaticamente para <input>formar elementos e para o formulário, mas não para o <label>.

Blazemonger
fonte
1
Permite adicionar ações em foco, como: input:hover+span:after{color: blue}. Voto a favor.
Krassowski
2
Por que essa resposta tem tão poucos votos positivos? Eu acho que o conhecimento teórico é importante, mas isso resolve o problema.
Jorgefpastor 14/05/19
Ótima opção para resolver, a fim de resolver o problema.
Jester
39

:beforee :aftersão aplicados dentro de um contêiner, o que significa que você pode usá-lo para elementos com uma tag final.

Não se aplica a elementos de fechamento automático.

Em uma nota lateral, os elementos que se fecham automaticamente (como img / hr / input) também são conhecidos como 'Elementos Substituídos', pois são substituídos pelo respectivo conteúdo. "Objetos externos" pela falta de um termo melhor. Uma leitura melhor aqui

CatalinBerta
fonte
Esta resposta é correta, concisa e fornece um contexto importante. Deve estar no topo, imo.
Paul
31

Usei o background-imagepara criar o ponto vermelho para os campos obrigatórios.

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 no Codepen

Veiko Jääger
fonte
20

Você não pode colocar um pseudo-elemento em um elemento de entrada, mas pode colocar no elemento de sombra, como um espaço reservado!

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

Para fazê-lo funcionar em outros navegadores, utilização :-moz-placeholder, ::-moz-placeholdere :-ms-input-placeholder em diferentes seletores . Não é possível agrupar os seletores, porque se um navegador não reconhecer, o seletor invalidará toda a instrução.

UPDATE : O código acima funciona apenas com o pré-processador CSS (SASS, LESS ...), sem o uso de pré-processadores:

input[type="text"]::-webkit-input-placeholder:before { // your code }
Shankar Cabus
fonte
3
Agradável! Observe que o pseudo-elemento do espaço reservado possui suporte limitado à propriedade: cor, plano de fundo, espaçamento entre palavras, espaçamento entre letras, decoração de texto, alinhamento vertical, transformação de texto, transformação de texto, altura da linha, recuo do texto, opacidade. Veja css-tricks.com/almanac/selectors/p/placeholder
henry
Obrigado pela dica. Lembre-se de que tudo dentro do pseudo-elemento desaparecerá quando a caixa de entrada for preenchida pelo usuário. Esse é um problema de UX se tudo o que você queria, como eu, estava exibindo uma glyphicon-searchmarcação sem tocar.
Davi Lima
2
Algum contexto sobre por que isso não funciona mais: bugs.chromium.org/p/chromium/issues/detail?id=582301
Oliver Joseph Ash
17

Pseudo-elementos como :after, :beforesão apenas para elementos de contêiner. Elementos iniciando e fechando em um único local como <input/>, <img>etc , não são elementos de contêiner e, portanto, pseudo-elementos não são suportados. Depois de aplicar um pseudo elemento ao elemento container, <div>e se você inspecionar o código (veja a imagem), poderá entender o que quero dizer. Na verdade, o pseudo elemento é criado dentro do elemento container. Isso não é possível no caso de <input>ou<img>

insira a descrição da imagem aqui

Pons Purushothaman
fonte
15

Uma solução funcional em CSS puro:

O truque é supor que exista um elemento dom após o 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>

(*) Solução limitada, no entanto:

  • você tem que esperar que haja um elemento dom a seguir,
  • você precisa esperar que nenhum outro campo de entrada siga seu campo de entrada.

Mas, na maioria dos casos, conhecemos o nosso código, portanto essa solução parece eficiente e 100% CSS e 0% jQuery.


fonte
2
input#myTextField ~ span:before {muito melhor, mas vão deve ter uma classe realmente ser mais explícito como .tickou.icon
Val
13

Encontrei este post porque estava tendo o mesmo problema, esta foi a solução que funcionou para mim. Em vez de substituir o valor da entrada, basta removê-lo e posicionar absolutamente uma extensão atrás dela que é do mesmo tamanho, a extensão pode ter uma :beforepseudo classe aplicada a ela com a fonte do ícone de sua escolha.

<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
fonte
1
+1 - Esta solução funciona bem se você estiver usando um plug-in ou estrutura que adiciona automaticamente classes de validação ao próprio elemento, mas não ao rótulo pai.
Blazemonger
9

O maior mal-entendido aqui é o significado das palavras beforee after. Eles não se referem ao próprio elemento, mas ao conteúdo do elemento. O mesmo element:beforeacontece antes do conteúdo eelement:after depois do conteúdo, mas ambos ainda estão dentro do elemento original.

O inputelemento não possui conteúdo na visualização CSS e, portanto, não possui :beforeou:after pseudo conteúdo. Isso vale para muitos outros elementos nulos ou substituídos.

Não há pseudo-elemento referente a fora do elemento.

Em um universo diferente, esses pseudo-elementos poderiam ter sido chamados de outra coisa para tornar essa distinção mais clara. E alguém pode até ter proposto um pseudo-elemento que está genuinamente fora do elemento. Até agora, este não é o caso neste universo.

Manngo
fonte
Talvez eu não entenda o que você quer dizer, mas se eu entender, os pseudoelementos funcionarão em hr? jsfiddle.net/demetriad/o49yn5hq #
Chris
1
@ Chris Isso é uma surpresa para mim, e na busca, para alguns outros. Eu acho que é uma peculiaridade. hrsempre foi ambíguo do ponto de vista do CSS, embora você veja isso mais ao discutir cores.
Manngo 10/07/19
5

De acordo com uma nota na especificação do CSS 2.1, a especificação “não define completamente a interação de: before e: after com elementos substituídos (como IMG em HTML). Isso será definido em mais detalhes em uma especificação futura. ” Embora inputnão seja mais um elemento substituído, a situação básica não mudou: o efeito de :beforee :aftersobre ele não é especificado e geralmente não tem efeito.

A solução é encontrar uma abordagem diferente para o problema que você está tentando resolver dessa maneira. Colocar o conteúdo gerado em um controle de entrada de texto seria muito enganador: para o usuário, isso pareceria fazer parte do valor inicial no controle, mas não poderá ser modificado - portanto, pareceria algo forçado no início do controle, mas ainda assim não seria enviado como parte dos dados do formulário.

Jukka K. Korpela
fonte
3
Este é um comentário, não uma resposta - um comentário bastante longo, mas um comentário mesmo assim.
Blazemonger
@ Blazemonger, não está claro qual era a pergunta, mas, em qualquer caso, esta resposta aborda o mesmo problema que a resposta aceita, mas de uma maneira mais correta. Não é impossível usar o conteúdo gerado para inputelementos, apenas não especificado e dependendo do navegador.
Jukka K. Korpela
5

Como outros explicaram, inputs são elementos vazios substituídos, portanto a maioria dos navegadores não permite gerar ::beforenem ::afterpseudo-elementos neles.

No entanto, o Grupo de Trabalho CSS está considerando permitir explicitamente ::beforee ::afterno caso de inputter appearance: none.

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

O Safari e o Chrome permitem pseudoelementos em suas entradas de formulário. Outros navegadores não. Procuramos remover isso, mas o contador de uso está gravando ~ 0,07% das páginas que o utilizam, o que é 20x o nosso limite máximo de remoção.

Na verdade, especificar pseudoelementos nas entradas exigiria especificar a estrutura interna das entradas pelo menos um pouco, o que ainda não conseguimos fazer (e não tenho certeza de que podemos fazer). Mas Boris sugeriu, em um dos tópicos, permitir que apareça: nenhuma entrada - basicamente apenas transformá-las em <div> s, em vez de elementos "meio que substituídos".

Oriol
fonte
4

tente a seguir:

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

Você precisa ter algum tipo de wrapper ao redor da entrada para usar um pseudoelemento antes ou depois. Aqui está um violino que tem um antes na div wrapper de uma entrada e, em seguida, coloca o antes dentro da entrada - ou pelo menos parece. Obviamente, isso é uma solução alternativa, mas eficaz em um beliscão e se presta a responder. Você pode facilmente fazer isso depois, se precisar colocar algum outro conteúdo.

Violino de trabalho

Cifrão dentro de uma entrada como um pseudo-elemento: http://jsfiddle.net/kapunahele/ose4r8uj/1/

O HTML:

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

O 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
fonte
Bom truque, mas você pode fazer uma div estilizada para "continuar" a entrada. Veja este violão jsfiddle.net/ose4r8uj/31 Mas você também pode facilitar o uso do bootstrap: getbootstrap.com/css/#forms-control-validation procure a parte "Com ícones opcionais". Mesmo assim, isso não tem nada a ver com a pergunta original.
Victor Ivens
1
FYI não é bom para: foco,: hover, etc. da entrada porque você não pode direcionar o elemento pai
jordanb
2

Se você estiver tentando estilizar um elemento de entrada com: before e: after, é provável que você esteja tentando imitar os efeitos de outro span, div ou mesmo de um elemento em sua pilha CSS.

Como aponta a resposta de Robert Koritnik,: antes e: depois só podem ser aplicados a elementos de contêiner e os elementos de entrada não são contêineres.

NO ENTANTO, o HTML 5 introduziu o elemento button , que é um contêiner e se comporta como um elemento input [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
fonte
O HTML 4 realmente introduziu o elemento <button>.
Sr. Lister
1

Sumário

Não funciona <input type="button">, mas funciona bem <input type="checkbox">.

Violino : 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;
}

fonte
1

:beforee :afterfunciona apenas para nós que podem ter nós filhos, pois inserem um novo nó como o primeiro ou o último nó.

Juan Mendes
fonte
0

Descobri que você pode fazer assim:

Você precisa ter um pai div que aceite o preenchimento e o: depois. O primeiro pai precisa ser relativo e o segundo div deve ser absoluto para que você possa definir a posição do depois.

Patrick
fonte
-1

Eu tenho outra idéia, use isso:

<div>
<input type="text"></input>text can be entered here</div>
Dima Dulin
fonte
O autor da pergunta afirmou explicitamente que eles não podem alterar a marcação HTML. Esta resposta não faz sentido. Provavelmente deveria ter sido votado em vez de editado, @Morpheus.
Palec 15/01