Стилізація placeholder за допомогою CSS

Атрибут placeholder підказує, чого чекають від поля введення, поки воно порожнє. Колись його стилізація вимагала чотирьох вендорних префіксів, а сьогодні вистачає одного селектора ::placeholder. Розберемо, як оформлювати підказку правильно, який прийом із нею робить форму зручнішою й чому нею не можна замінювати підпис поля.

Найважливіше: плейсхолдер — не підпис

Підказка зникає з першим уведеним символом. Людина, яку відволікли посеред форми, вже не дізнається, що вона заповнює; скрінрідер у частині браузерів її не зачитує зовсім; автозаповнення браузера спрацьовує гірше. Тому в поля завжди має бути справжній підпис <label>, а плейсхолдер бере на себе лише формат або приклад.

ТАК НЕ ТРЕБА: ПІДПИС ЖИВЕ ЛИШЕ В ПЛЕЙСХОЛДЕРІТелефон у форматі +380…поле порожнє — підказку видно+380 67 502 45 84почали вводити — підказка зниклаі що це за поле, вже не дізнатисяТАК ТРЕБА: ПІДПИС ОКРЕМО, ПЛЕЙСХОЛДЕР ПОКАЗУЄ ФОРМАТТелефон+380 __ ___ __ __підпис на місці завждиТелефон+380 67 502 45 84підпис читає і людина, і скрінрідер
Підпис лише в плейсхолдері та правильний варіант із 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 спрацьовує, поки поле порожнє й підказка видима. На ньому будуються прийоми, які раніше робили скриптом.

ТРИ СТАНИ ПОЛЯ Й СЕЛЕКТОРИ ДЛЯ НИХВаше ім’япорожньо, підказку видно::placeholder:placeholder-shownВаше ім’якурсор у полі:focus::placeholderтут підказку зазвичай гасятьМаксимє значення:not(:placeholder-shown)підпис піднімають угоруСелектор :placeholder-shown спрацьовує, поки поле порожнє, — на ньому тримається прийом із плавним підписомі підсвічування незаповнених полів без жодного рядка JavaScript.
Три стани поля й відповідні їм селектори

Плавний підпис — підпис лежить поверх порожнього поля й підіймається нагору, щойно з’явився текст. Увесь ефект на 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. Головне правило лишається тим самим: плейсхолдер показує формат, підпис пояснює, що за поле, і одне одним не замінюється.

Якщо форма на вашому сайті працює, але відвідувачі кидають її на середині, напишіть нам — подивимося, де саме губляться заявки.