Понадобилось сделать многострочный placeholder в textarea. Выяснилось, что Firefox, в отличие от всех других современных браузеров, не поддерживает перенос строки в элементе placeholder. Хотя делает он это в соответствии с W3C спецификацией — радости это не добавляет.
Все нагугленные решения не понравились. Ставить JQuery-плагины только ради переноса строк в Firefox не хотелось. Решил попробовать сделать свой placeholder во вспомогательном блоке. В итоге получилось вот такое простое решение, которое работает во всех браузерах и предоставляет широкие возможности для кастомизации placeholder.
Стандартное поведение реализуется с помощью jQuery (используется у меня в проекте, при необходимости легко заменяется чистым JS). Если вам нравится скрывать placeholder, когда поле попадает в фокус, то можно обойтись только CSS.
Посмотреть пример на jsfiddle.
Обновленный пример
UPD
Спасибо gwer за подсказки.
Изменения и уточнения:
- на чистом CSS работать не будет, без JS не обойтись
- в JS нужно использовать событие 'input'. Тогда placeholder исчезает и при вставке из буфера обмена через контекстное меню.
<div id="textAreaWrap">
<textarea id="textArea"></textarea>
<!-- Check here. If textarea has content - set for this div attribute style="display: none;" -->
<div id="placeholderDiv">Multiline textarea<br> placeholder<br><br>that works in Firefox</div>
</div>
#textAreaWrap {
position: relative;
background-color: white;
}
#textArea {
position: relative;
z-index: 1;
width: 350px;
height: 100px;
min-height: 100px;
padding: 6px 12px;
resize: vertical;
background-color: transparent;
/* When set background-color: transparent - Firefox displays
unpleasant textarea border. Set border style to fix it.*/
border: 1px solid #a5a5a5;
}
#placeholderDiv {
position: absolute;
top: 0;
padding: 6px 13px;
color: #a5a5a5;
}
$(document).on('input', '#textArea', function () {
if ($('#textArea').val()) {
$('#placeholderDiv').hide();
} else {
$('#placeholderDiv').show();
}
});
Комментарии (15)
gwer
16.10.2015 15:23Надо вешаться на другое событие. С keydown некорректно будет работать при вставке из буфера обмена через контекстное меню. Используйте событие input.
Непонятны причины использования setTimeout. Он зачем вдруг понадобился?
Для обертки не помешает overflow: hidden на случай, когда плейсхолдер вдруг окажется больше, чем textarea.
Еще можно обойтись без background-color: transparent и сопутствующих проблем, если обертку сделать label'ом и не шаманить с z-index'ами.
А решение на чистом CSS не будет работать. Плейсхолдер убирается только пока есть фокус на поле. Когда фокус пропадет, плейсхолдер вернется, несмотря на наличие текста.everythingispossible
16.10.2015 16:23setTimeout был нужен при использовании keydown — без таймаута (даже нулевого) проверка поля происходит до того как как там появится символ.
С использованием события input все стало работать и при вставке через контекстное меню + setTimeout стал не нужен.
попробовал overflow: hidden – не получается, т.к. у блока placeholder стоит position: absolute
Но я считаю это некритичным, т.к. при верстке такого специфического поля несложно учесть его размер,
зная текст для placeholder и задать min-height: XXXpx;
попробовал с label и без background-color: transparent и z-index
тоже не получилось без них, т.к. при клике правой кнопкой мыши по placeholder появляется контекстное меню как при клике по блоку, а не по textarea.
Возможно это как-то можно сделать, хотя мне пока непонятно зачем. Чем плохо использование background-color: transparent и z-index?
С чистым CSS действительно не прокатывает.
Пост обновил.
Большое спасибо за подсказки!
everythingispossible
17.10.2015 14:27Таки да, overflow: hidden можно применить
для этого у placeholder нужно к position: absolute и top: 0 добавить еще bottom: 0, right:0, left:0;
Надо заметить, что цель использования overflow: hidden достигается не полностью. Размер обертки по вертикали почему-то получается на несколько пикселей больше textarea, а размер placeholder совпадает с размером обертки.
Поэтому overflow: hidden прячет лишний текст placeholder, но часть первой спрятанной строки выглядывает под textarea.
ds_pro
16.10.2015 16:01Работает только с прозрачным textarea, это смех.
gwer
16.10.2015 16:13Комментом выше я написал, как можно реализовать без прозрачного textarea. Впрочем, не считаю это совсем уж большой проблемой. Просто стилей чуть больше. Бэкграунд textarea заменяется бэкграундом обертки.
ds_pro
16.10.2015 16:16А зачем? если можно сделать без велосипедов на JS.
gwer
16.10.2015 16:24Динамически менять контент textarea? Согласен, может быть приемлемым. Только это опять будет велосипедом.
Я на решение смотрел со своей колокольни: недавно реализовывал нечто подобное для однострочных инпутов в соответствиями с принципами Material. Там как раз после перебора пачки вариантов пришел к похожему, но это в силу ограничений, которых нет в задаче автора.
dooza
16.10.2015 19:22+1можно было обойтись без JS, с помощью css
everythingispossible
16.10.2015 19:30Я пробовал разные варианты. На чистом CSS пока не получилось.
Если знаете как — подскажите.
Keyten
17.10.2015 16:21Попробуйте поиграться с разными word-wrap, break-word и т.п., вдруг поможет.
И ещё, помнится, во времена IE6 плейсхолдеры реализовывали, просто изменяя value у текстовых полей, зачем накладывать див сверху? Критично, чтобы value был пустым, если в поле плейсхолдер?
everythingispossible
17.10.2015 17:13Готовые решения с изменением value у текстовых полей показались мне излишне громоздкими и неудобными.
Зачем много кода, если можно обойтись обработкой одного события в JS.
Ninjak
Хрень какая-то… если кликнуть по плэйсхолдеру, то фокус не сработает на текстареи… если так и делать, то плэйсхолдер надо делать лэйбелом и указывать for. Также не понятно, почему только в ФФ? В других браузерах ЦСС нынче не работает? ;)
gwer
Плейсхолдер расположен под textarea (z-index), потому фокус ловится там, где надо.
Работает и в FF, и в прочих браузерах, в отличие от решения «из коробки», которое FF игнорирует. Собственно, отличие от «коробочного» решения заключается в поддержке лисой, что и отражено в заголовке.