Coding → Кроссбраузерный placeholder

Добрый день.

Наконец-то дошли руки до написания первого тематического поста в блог. Им я начну цикл статей о jQuery плагинах, которые мы активно используем в студии. Итак, статья о такой полезной вещи как плэйсхолдер (placeholder).

Интро

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

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

В данный момент атрибут «placeholder» работает только в браузерах на движке Webkit (Google Chrome и Safari), то есть только очень маленький процент юзеров увидит его. А хочется порадовать всех.

Требования

  • Плагин должен обрабатывать и текстовые поля (<input type=’text’>) и текстовые области (<textarea>)
  • Для браузеров на движке Webkit оставлять их реализацию
  • При отправке формы плэйсхолдеры должны убираться(несмотря на очевидность, в большинстве аналогичных плагинов это не сделано :)
  • Плагин должен быть кроссбраузерным, т.е. под все браузеры, в которых вообще работает jQuery.
  • Плагин должен быть удобным (подключил — юзай)

Реализация

Основой всего в этом плагине для нас будет, так называемый, «Has Attribute» селектор (мануал). Сначала была мысль выбрать все элементы, у которых есть атрибут «placeholder», и для каждого вешать нужные обработчики. Но в ходе тестирования стало понятно, что для текстовых полей будет одна обработка, а для текстовых областей другая, поэтому я решил сначала выбирать по селектору input[placeholder] и потом по textarea[placeholder].

Начнём с «каркаса». Сделан выход, если браузер на Webkit, создаётся нужный для работы класс (#a9a9a9 — цвет «родного» Webkit’овского плэйсхолдера)

$(function(){
	if ($.browser.safari) return; // Webkit has own placeholder, so we are free

	$('<style>').html('.jqueryPlaceholder{color:#a9a9a9!important;}').appendTo('head'); // Create placeholder class

	$('input[placeholder]').each(function(){ //Processing placeholders for input.texts
		// ...
	});

	$('textarea[placeholder]').each(function(){ //Processing placeholders for textareas
		// ...
	});

});

Затем ставим полям значения, которые у нас стоят в атрибуте «placeholder», и вешаем наш созданный класс. Тут я наткнулся на забавный баг, когда тестировал плагин в Firefox’е. Он заключался в том, что если написать что-нибудь в поле, то  после обновления окна, плейсхолдер не появлялся (как и должно быть), а вот класс снова навешивался. После скрупулезного дебага выяснилось, что Огнелис при обновлении окна не очищает форму. Это, в принципе, удобно, но в данном случае было нам вредно. Для исправления проблемы я просто добавил ещё одно условие.

if(this.value == '' || this.value == $(this).attr('placeholder')){ // (Mozzi refresh fix)
	$(this).addClass('jqueryPlaceholder');
	this.value = $(this).attr('placeholder');
};

Дальше, всё просто и очевидно. Вешаем обработчики событий focus и blur на наши элементы.

$(this).focus(function(){
	if($(this).val() == $(this).attr('placeholder')){
		$(this)
			.removeClass('jqueryPlaceholder')
			.val('');
	}
});

$(this).blur(function(){
	if($(this).val() == ''){
		$(this)
			.addClass('jqueryPlaceholder')
			.val($(this).attr('placeholder'));
	}
});

Для текстовых областей всё аналогично, за исключением того, что вместо $(this).val() мы используем this.value, по причине что в первом случае в некоторых браузерах странно определяется содержимое. Ну и заодно немного разгружаем жквери. :)

Базовый функционал плагина сделан, всё работает, но не очищаются поля при сабмите. Сделаем и это. Для этого находим все формы на странице (так как их обычно немного, не будем устраивать гонки за скоростью), и вешаем на их сабмит обработчик. Он будет искать все текстовые поля и области и проверять, не стоит ли в них текст плэйсхолдера. Если стоит — очищаем.

$('form').each(function(){ //Processing "clear on submit"
	$(this).submit(function(){
		$(this).find("input").each(function(){
			if($(this).val() == $(this).attr('placeholder')) $(this).val('');
		});
		$(this).find("textarea").each(function(){
			if(this.value == $(this).attr('placeholder')) this.value = '';
		});
	});
});

Теперь тестируем весь плагин на нашей демке. Убеждаемся, что всё хорошо во всех браузерах, и со спокойной душой скачиваем сжатый исходник (ну или полный, если хочется поразбираться). Не забывайте, что для работы нужен jQuery.

Outro

Надеюсь вам пригодится этот плагин. Любые багрепорты, пожелания или вопросы можете оставлять в комментариях, или присылать на me@pashinblog.ru.

Спасибо за внимание.