Атрибут placeholder подсказывает, что ждут от поля ввода, пока оно пустое. Когда-то его стилизация требовала четырёх вендорных префиксов, а сегодня хватает одного селектора ::placeholder. Разберём, как оформлять подсказку правильно, какой приём с ней делает форму удобнее и почему ею нельзя заменять подпись поля.
Самое важное: плейсхолдер — не подпись
Подсказка исчезает при первом введённом символе. Человек, которого отвлекли на середине формы, уже не узнает, что он заполняет; скринридер в части браузеров её не зачитывает вовсе; автозаполнение браузера срабатывает хуже. Поэтому у поля всегда должна быть настоящая подпись <label>, а плейсхолдер берёт на себя только формат или пример.
<!-- так не надо -->
<input type="tel" name="phone" placeholder="Телефон в формате +380…">
<!-- так надо -->
<label for="phone">Телефон</label>
<input type="tel" id="phone" name="phone"
placeholder="+380 __ ___ __ __" autocomplete="tel">
Как изменить цвет и шрифт подсказки
Сегодня достаточно одного правила — ::placeholder поддерживают все актуальные браузеры:
input::placeholder,
textarea::placeholder {
color: #8A8A8A;
font-style: italic;
opacity: 1; /* Firefox по умолчанию приглушает подсказку */
}
Строка с opacity не лишняя: Firefox исторически делает плейсхолдер полупрозрачным, и без неё заданный цвет выглядит бледнее, чем задумано.
Набор свойств, который реально применяется к подсказке, невелик: цвет, фон, всё семейство font-*, межбуквенный и межсловный интервал, text-decoration, text-transform, line-height, opacity и text-overflow. Отступы, рамки и позиционирование к ней не применяются — это оформление самого поля.
Старые префиксы и зачем о них помнить
В статьях пятилетней давности тот же эффект записывали так:
::-webkit-input-placeholder { color: #8A8A8A; }
::-moz-placeholder { color: #8A8A8A; }
:-moz-placeholder { color: #8A8A8A; }
:-ms-input-placeholder { color: #8A8A8A; }
Причина была в том, что стандарта не существовало и каждый движок реализовал стилизацию по-своему: в IE и Firefox до 19-й версии плейсхолдер считался псевдоклассом, в WebKit и Blink — псевдоэлементом. Сегодня эти строки нужны только проектам с поддержкой очень старых браузеров. Важная деталь: селекторы нельзя объединять через запятую — браузер, не знающий хотя бы один из них, отбросит правило целиком.
Длинная подсказка в узком поле
На телефоне поля сужаются, и длинный текст обрезается на полуслове. Многоточие в конце выглядит аккуратнее:
input::placeholder {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
Приём рабочий, но лечит следствие. Если подсказка не помещается — она слишком длинная: формат «+380 __ ___ __ __» читается лучше, чем предложение на всю ширину.
Прятать подсказку при фокусе
Браузеры ведут себя по-разному: одни убирают плейсхолдер при постановке курсора, другие держат до первого символа. Привести к единому поведению можно одной строкой:
input:focus::placeholder,
textarea:focus::placeholder {
color: transparent;
}
Красивее — с плавным уходом в сторону:
input::placeholder {
opacity: 1;
transition: opacity .2s ease, transform .2s ease;
}
input:focus::placeholder {
opacity: 0;
transform: translateX(6px);
}
Состояния поля и :placeholder-shown
Отдельный псевдокласс :placeholder-shown срабатывает, пока поле пустое и подсказка видна. На нём строятся приёмы, которые раньше делали скриптом.
Плавающая подпись — подпись лежит поверх пустого поля и поднимается наверх, как только появился текст. Весь эффект на CSS:
<div class="field">
<input type="text" id="name" placeholder=" ">
<label for="name">Ваше имя</label>
</div>
.field { position: relative; }
.field label {
position: absolute;
left: 12px;
top: 12px;
color: #8A8A8A;
pointer-events: none;
transition: transform .15s ease, font-size .15s ease;
}
/* поле заполнено или в фокусе — подпись уезжает наверх */
.field input:not(:placeholder-shown) + label,
.field input:focus + label {
transform: translateY(-22px);
font-size: 12px;
}
Пробел в placeholder=" " обязателен: без атрибута псевдокласс :placeholder-shown не сработает вовсе.
Тот же селектор подсвечивает незаполненные обязательные поля, причём только после того, как посетитель их тронул:
input:required:not(:placeholder-shown):invalid {
border-color: #C0392B;
}
Доступность и тёмная тема
- Контраст. Светло-серая подсказка на белом фоне — классическая ошибка. WCAG требует не меньше 4,5:1 для обычного текста; подсказку делают приглушённой, но читаемой.
- Не прячьте label визуально «чтобы было чисто». Если дизайн требует поля без видимой подписи, подпись всё равно нужна в разметке — хотя бы через
aria-label. - Тёмная тема. Цвет подсказки задавайте токеном и переопределяйте в медиазапросе:
input::placeholder { color: #8A8A8A; }
@media (prefers-color-scheme: dark) {
input::placeholder { color: #9B9B9B; }
}
- Не кладите в плейсхолдер важное. Требования к паролю, формат даты, обязательность поля — это текст рядом с полем, а не исчезающая подсказка.
Коротко о главном
Сегодня для оформления подсказки хватает ::placeholder, а вендорные префиксы нужны лишь при поддержке очень старых браузеров. Для состояний поля есть :placeholder-shown: на нём делаются плавающая подпись и подсветка незаполненного — без JavaScript. Главное правило остаётся прежним: плейсхолдер показывает формат, подпись объясняет, что за поле, и одно другим не заменяется.
Если форма на вашем сайте работает, но посетители бросают её на середине, напишите нам — посмотрим, где именно теряются заявки.




