Могу ли я использовать псевдоэлемент: before или: after в поле ввода?

687

Я пытаюсь использовать :afterпсевдоэлемент CSS на inputполе, но он не работает. Если я использую это с span, это работает хорошо.

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

Это работает (ставит смайлик после "buu!" И перед "еще немного")

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

Это не работает - он только окрашивает someValue в красный, но смайлика нет.

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

Что я делаю неправильно? я должен использовать другой псевдо-селектор?

Примечание: я не могу добавить spanвокруг моего input, потому что он создается сторонним элементом управления.

матра
источник
Если вы абсолютно никакого контроля над HTML, попробуйте изменяя border-colorиз inputвместо. Я считаю, что это привлекает больше внимания.
Blazemonger

Ответы:

256

:afterи :beforeне поддерживаются ни в Internet Explorer 7, ни в каких-либо элементах.

Он также не предназначен для использования на заменяемых элементах, таких как элементы формы (входы) и элементы изображения .

Другими словами, это невозможно с чистым CSS.

Однако, если вы используете jquery, вы можете использовать

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

API документы на .after

Чтобы добавить свой контент с помощью JavaScript. Это будет работать во всех браузерах.

Alex
источник
Алекс, я использую IE8 и последнюю версию FF, поэтому IE7 не проблема. Я искал любую документацию об ограничении: после, но не смог ее найти. w3.org/TR/CSS2/generate.html утверждает, что он вставляется после текущего узла в дерево документов, поэтому он должен работать в обоих случаях.
матра
3
Если вы не создаете страницу только для своего собственного использования, большой процент интернета все еще использует эти браузеры. Спецификация w3c говорит это да; но, как вы хорошо знаете, браузеры реализуют свою интерпретацию спецификации. Использование: after on вход будет работать только в Opera 9+, но не реализован в IE, FF, safari или chrome из-за способа, которым они внутренне конструируют DOM - опять же это не может быть сделано с помощью чистого CSS.
Алекс
3
Я не уверен , если это было в апреле, но Webkit делает поддержку :afterв целом, хотя он не поддерживает ни :beforeили :afterна входах.
Coreyward
258
Насколько я понимаю, W3C :afterи :beforeпсевдоэлементы, они могут быть размещены только на элементах контейнера. Почему? Потому что они добавлены внутри этого конкретного элемента. inputэто не контейнер. buttonнапример, следовательно, вы можете надеть их. Работает как положено. Спецификация на самом деле говорит: до и после содержимого дерева задокументировать элемент Это явно говорит CONTENT . Таким образом, элемент должен быть контейнером.
Роберт Коритник
29
Следующий ответ гораздо лучше. Дает реальную причину, а не говорит о IE 7 (кому это нужно) и jQuery (плохая идея)
Rowan
1305

:beforeи :afterвизуализировать внутри контейнера

и <input> не может содержать другие элементы.


Псевдоэлементы могут быть определены (или, точнее, поддерживаются) только для элементов контейнера. Потому что способ их визуализации находится внутри самого контейнера как дочерний элемент. inputне может содержать другие элементы, следовательно, они не поддерживаются. А buttonс другой стороны, это также элемент формы, который поддерживает их, потому что это контейнер других подэлементов.

Если вы спросите меня, если какой - то браузер делает отображать эти два псевдо-элементы, не имеющие отношения элементов контейнера, это ошибка и нестандартным соответствие. Спецификация напрямую говорит о содержании элемента ...

Спецификация W3C

Если мы внимательно прочитаем спецификацию он на самом деле говорит , что они вставляются внутри вмещающего элемента:

Авторы определяют стиль и расположение сгенерированного контента с помощью псевдоэлементов: before и: after. Как указывают их имена, псевдоэлементы: before и: after указывают местоположение содержимого до и после содержимого дерева документа элемента. Свойство content в сочетании с этими псевдоэлементами определяет, что вставляется.

Видеть? содержимое дерева документа элемента . Насколько я понимаю, это означает, что внутри контейнера.

Роберт Коритник
источник
119
+1 Гораздо лучше, чем принятый ответ. Спасибо за четкое объяснение самого стандарта. Так много для [required]::before { content "*"; color: red; }: P
Кевин Пено
93
Подсказка: Если у вас возникла проблема только с отправкой ввода <input type="submit" value="Send"/>, используйте <button type="submit">Send</button>вместо этого. Презентация идентична, но <button>является контейнером и, следовательно, поддерживает :beforeи :after.
грипп
15
Как насчет <hr />? Я думал, что это не элемент контейнера, но он мог отрендериться :afterи :before jsfiddle.net/Uf88j/1
deathlock
7
@deathlock: это действительно интересно. Я бы сказал, что это какая-то аномалия, и я бы не стал полагаться на то, что она работает в кросс-браузерной или кросс-версии ... HR не является контейнерным элементом, поэтому не должен допускать псевдоэлементов. Даже стандарт W3C гласит, что он не допускает никакого контента. И если вы проверите для пустого элемента, вы увидите, что эти элементы не должны иметь никакого содержимого ни при каких обстоятельствах. Псевдоэлементы - это контент, поэтому ожидайте, что будущая версия браузера не сможет их отобразить.
Роберт Коритник
5
" : before и: after render внутри контейнера " Псевдоэлементы:: before и: after идут " до и после содержимого ". Не «в начале или в конце» контейнера. В спецификации не упоминается контейнер . С такими тегами, как pи h1, содержимое находится внутри тега, поэтому до и после также отображаются внутри. С такими элементами, как inputи hr,: before и: after все равно будет отображаться до или после содержимого, но контейнер не задействован (особенно для input). input: checked: before широко используется для обозначения флажков, проверяемых с помощью css.
Рэдли Сустер
60

Как ни странно, он работает с некоторыми типами ввода. По крайней мере, в Chrome,

<input type="checkbox" />

работает нормально, так же, как

<input type="radio" />

Просто type=textи некоторые другие не работают.

Vals
источник
1
@ ANeves, у меня это работало в Chromium, но не в Firefox.
kcpr
45

Вот еще один подход (при условии, что у вас есть контроль над HTML): добавьте пустое <span></span>сразу после ввода и укажите его в CSS, используяinput.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>

Я использую этот подход в AngularJS, потому что он будет добавлять .ng-invalidклассы автоматически для <input>элементов формы и формы, но не для <label>.

Blazemonger
источник
1
Это позволяет добавлять при наведении курсора мыши действия, как: input:hover+span:after{color: blue}. Upvote.
Крассовски
2
Почему в этом ответе так мало голосов? Я думаю, что теоретические знания важны, но это решает проблему.
jorgefpastor
Хороший вариант, чтобы решить проблему.
Шут
40

:beforeи :afterприменяются внутри контейнера, что означает, что вы можете использовать его для элементов с конечным тегом.

Это не относится к самозакрывающимся элементам.

На заметку о том, что элементы, которые являются самозакрывающимися (например, img / hr / input), также известны как «Замененные элементы», так как они заменены соответствующим содержимым. «Внешние объекты» из-за отсутствия лучшего термина. А лучше почитайте здесь

CatalinBerta
источник
Этот ответ является правильным, кратким и предоставляет важный контекст. Должно быть на вершине, имо.
Пол
32

Я использовал background-imageдля создания красной точки для обязательных полей.

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

Посмотреть на Codepen

Вейко Яэгер
источник
21

Вы не можете поместить псевдоэлемент в элемент ввода, но можете вставить теневой элемент, как заполнитель!

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

Для того, чтобы заставить его работать в других браузерах, использование :-moz-placeholder, ::-moz-placeholderи :-ms-input-placeholder в разных селекторов . Невозможно сгруппировать селекторы, потому что, если браузер не распознает селектор, он делает недействительным весь оператор.

ОБНОВЛЕНИЕ : приведенный выше код работает только с препроцессором CSS (SASS, LESS ...), без использования препроцессоров:

input[type="text"]::-webkit-input-placeholder:before { // your code }
Шанкар Кабус
источник
3
Ницца! Обратите внимание, что псевдоэлемент заполнителя имеет ограниченную поддержку свойств: цвет, фон, межсловный интервал, межбуквенный интервал, текстовое оформление, вертикальное выравнивание, преобразование текста, высоту строки, отступ текста, непрозрачность. См. Css-tricks.com/almanac/selectors/p/placeholder
Генри,
Спасибо за подсказку. Просто помните, что все, что находится внутри псевдоэлемента, исчезнет, ​​когда поле ввода заполнится пользователем. Это проблема UX, если все, что вы хотели, как я, отображать glyphicon-searchбез касания разметки.
Дави Лима
2
Некоторый контекст о том, почему это больше не работает: bugs.chromium.org/p/chromium/issues/detail?id=582301
Оливер Джозеф Эш
18

Псевдоэлементы, подобные :after, :beforeпредназначены только для контейнерных элементов. Элементы, начинающиеся и закрывающиеся в одном месте, например <input/>, и <img>т. Д., Не являются контейнерными элементами и, следовательно, псевдоэлементы не поддерживаются. Как только вы примените псевдоэлемент к элементу контейнера, например, <div>и если вы посмотрите код (см. Изображение), вы поймете, что я имею в виду. На самом деле псевдоэлемент создается внутри элемента контейнера. Это невозможно в случае <input>или<img>

введите описание изображения здесь

Понс Пурушотаман
источник
15

Рабочее решение в чистом CSS:

Хитрость заключается в том, чтобы предположить, что после текстового поля есть элемент dom.

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

(*) Ограниченное решение, хотя:

  • Вы должны надеяться, что есть следующий элемент DOM,
  • Вы должны надеяться, что никакое другое поле ввода не следует за вашим полем ввода.

Но в большинстве случаев мы знаем наш код, поэтому это решение кажется эффективным и на 100% CSS и на 0% jQuery.


источник
2
input#myTextField ~ span:before {намного лучше, но у span должен быть класс, чтобы он был более явным, как .tickили.icon
Val
13

Я нашел этот пост, так как у меня была та же проблема, это было решение, которое работало для меня. В отличие от замены значения ввода, просто удалите его и разместите за ним промежуток такого же размера, к нему можно :beforeприменить псевдокласс с выбранным шрифтом значка.

<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>
Морган Фини
источник
1
+1 - Это решение хорошо работает, если вы используете плагин или фреймворк, который автоматически добавляет классы проверки к самому элементу, но не к родительской метке.
Blazemonger
9

Самое большое недоразумение здесь - это значение слов beforeи after. Они относятся не к самому элементу, а к содержимому элемента. Так element:beforeже и до содержимого, и element:afterпосле содержимого, но оба они все еще находятся внутри исходного элемента.

inputЭлемент не имеет содержимого в представлении CSS, и так не имеет :beforeили :afterсодержание псевдо. Это верно для многих других пустых или замененных элементов.

За пределами этого элемента нет псевдоэлемента.

В другой вселенной эти псевдоэлементы можно было бы назвать чем-то еще, чтобы сделать это различие более ясным. И кто-то, возможно, даже предложил псевдоэлемент, который действительно находится вне элемента. Пока что это не так в этой вселенной.

Manngo
источник
Возможно, я не понимаю, что вы имеете в виду, но если я это сделаю, псевдоэлементы работают на час? jsfiddle.net/demetriad/o49yn5hq
Крис,
1
@Chris Это стало неожиданностью для меня и для некоторых других. Я думаю, что это странно. hrс точки зрения CSS всегда был неоднозначным, хотя вы видите это больше при обсуждении цвета.
Манго
5

Согласно примечанию в спецификации CSS 2.1, спецификация «не полностью определяет взаимодействие: before и: after с замененными элементами (такими как IMG в HTML). Это будет определено более подробно в будущей спецификации ». Хотя на inputсамом деле уже не заменяемый элемент, базовая ситуация не изменилась: влияние :beforeи :afterна него не определено и, как правило, не оказывает влияния.

Решение состоит в том, чтобы найти другой подход к проблеме, которую вы пытаетесь решить таким образом. Помещение сгенерированного содержимого в элемент управления вводом текста будет очень вводящим в заблуждение: пользователю это может показаться частью начального значения в элементе управления, но его нельзя будет изменить - так что оно будет выглядеть как принудительное в начале контроль, но все же он не будет представлен как часть данных формы.

Юкка К. Корпела
источник
3
Это комментарий, а не ответ - довольно длинный комментарий, но, тем не менее, комментарий.
Blazemonger
@Blazemonger, не совсем понятно, в чем заключался вопрос, но в любом случае этот ответ касается той же проблемы, что и принятый ответ, но более корректно. Не исключено использование сгенерированного контента для inputэлементов, просто неопределенного и зависящего от браузера.
Юкка К. Корпела
5

Как объяснили другие, inputs - это своего рода замененные пустые элементы, поэтому большинство браузеров не позволяют генерировать в них ::beforeни ::afterпсевдоэлементы.

Тем не менее, Рабочая группа CSS рассматривает в явном виде позволяет ::beforeи ::afterв случае inputимеет appearance: none.

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

Safari и Chrome позволяют использовать псевдоэлементы на входах своих форм. Другие браузеры этого не делают. Мы пытались удалить это, но счетчик использования записывает ~ .07% страниц, используя его, что в 20 раз превышает наш максимальный порог удаления.

Фактическое определение псевдоэлементов на входах потребовало бы, по крайней мере, некоторого указания внутренней структуры входов, что нам пока не удалось сделать (и я не уверен, что мы * можем * сделать). Но Борис предложил, в одной из ошибок, разрешить это по внешнему виду: ничего не вводить - в основном, просто превращая их в элементы <div>, а не в «своего рода замененные» элементы.

Ориоль
источник
4

попробуйте следующее:

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>

Алекс Овчинкин
источник
3

Вы должны иметь какую-то оболочку для ввода, чтобы использовать псевдоэлемент до или после. Вот скрипка, которая имеет значение before в div-обёртке ввода, а затем помещает before перед входом - или, по крайней мере, выглядит так. Очевидно, что это обходной путь, но эффективный в крайнем случае и поддающийся реагированию. Вы можете легко сделать это после, если вам нужно поместить какой-то другой контент.

Рабочая скрипка

Знак доллара внутри входа в виде псевдоэлемента: http://jsfiddle.net/kapunahele/ose4r8uj/1/

HTML:

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

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;
}
Капунахеле Вонг
источник
Хороший трюк, но вы можете сделать div стилизованным, чтобы «продолжить» ввод. Смотрите эту скрипку jsfiddle.net/ose4r8uj/31 Но вы также можете сделать это проще, используя bootstrap: getbootstrap.com/css/#forms-control-validation ищите часть «С дополнительными значками». Хотя это не имеет ничего общего с первоначальным вопросом.
Виктор Ивенс
1
К вашему сведению, ничего не подходит для: focus
,:
2

Если вы пытаетесь стилизовать входной элемент с помощью: before и: after, есть вероятность, что вы пытаетесь имитировать эффекты других span, div или даже элементов в вашем стеке CSS.

Как указывает ответ Роберта Коритника,: before и: after можно применять только к элементам контейнера, а элементы ввода не являются контейнерами.

ОДНАКО HTML 5 представил элемент button, который является контейнером и ведет себя как элемент 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>
Кевин Конрой
источник
HTML 4 фактически ввел элемент <button>.
Мистер Листер
1

Резюме

Не работает <input type="button">, но работает нормально <input type="checkbox">.

Скрипка : 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;
}

источник
1

:beforeи :afterработает только для узлов, которые могут иметь дочерние узлы, поскольку они вставляют новый узел в качестве первого или последнего узла.

Хуан Мендес
источник
0

Я обнаружил, что вы можете сделать это так:

Вам нужно иметь родителя div, который принимает padding и: after. Первый родитель должен быть относительным, а второй div должен быть абсолютным, чтобы вы могли установить позицию после.

Патрик
источник
-1

У меня есть другая идея использовать это вместо:

<div>
<input type="text"></input>text can be entered here</div>
Дима Дулин
источник
Автор вопроса прямо заявил, что не может изменить разметку HTML. Этот ответ не имеет смысла. Вероятно, это должно было быть отклонено вместо редактирования, @Morpheus.
Палек