Открыть меню    

Автоматическое изменение высоты у элемента textarea

Для одного проекта передо мной стояла задача найти способ автоматически изменять высоту элемента textarea согласно тому контенту, который будет динамически загружаться посредством Ajax. Так как высота контента мне была неизвестна, а элемент textarea не может подстраивать свои размеры под контент так же гармонично, как это делают другие HTML элементы, то при каждом изменении контента мне приходилось вручную вносить высоту элемента в JavaScript.

<Textarea> - многострочное поле текстового ввода в форме.
textarea автоматическая высота

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

Воспользуемся невидимым элементом-клоном

Элемент <div> будет растягиваться, чтобы подстроиться под высоту своего контента (при условии отсутствия абсолютно позиционированных элементов и плавающих объектов). Итак, чтобы получить высоту textarea, нужно сделать следующее:

  • Захватить контент, загруженный в элемент textarea
  • Создать невидимый элемент-клон (div)
  • Задать для элемента-клона такие же типографические свойства и ширину, как и у элемента textarea.
  • Поместить контент в клон
  • Получить высоту элемента-клона
  • У элемента textarea высоту сделать равной высоте элемента-клона

Код

Ключевую роль в моем решении будет играть CSS. Как упоминалось выше, невидимый клон должен иметь те же типографические свойства, что и элемент textarea. Поэтому свойства font-size, font-family, white-space и word-wrap элемента-клона должны соответствовать свойствам font-size, font-family, white-space и word-wrap элемента textarea.

CSS

textarea {
    width: 500px;
    min-height: 50px;
    font-family: Arial, sans-serif;
    font-size: 13px;
    color: #444;
    padding: 5px;
}

.noscroll {
    overflow: hidden;
}

Заметьте, что мною был добавлен отдельный класс с объявлением overflow: hidden. Это было сделано для того, чтобы предотвратить появление scrollbar-ов. Обычно добавлять такое объявление тегу textarea весьма сомнительно. Но в нашем случае оно уместно, так как я буду менять размеры элемента textarea с помощью JavaScript. Этот класс будет добавлен к textarea посредством JavaScript, что обеспечит нам скроллирование поля формы в случае, если JavaScript выключен.

СSS невидимого элемента-клона

CSS

.hiddendiv {
    display: none;
    white-space: pre-wrap;
    width: 500px;
    min-height: 50px;
    font-family: Arial, sans-serif;
    font-size: 13px;
    padding: 5px;
    word-wrap: break-word;
}

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

Свойству white-space задано значение pre-wrap, что означает: в тексте сохраняются все пробелы и переносы, однако если строка по ширине не помещается в заданную область, то текст автоматически будет перенесен на следующую строку. Элементу-клону я задал такую же ширину, как и у элемента textarea, и продублировал типографические свойства. И клон, и textarea имеют одинаковый min-height, чтобы они всегда изначально имели стандартный и практичный вид.

Перейдем к jQuery

JQuery


$(function() {
// описываем поле ввода (тег textarea)
	var txt = $('#comments'),
// создаем элемент-клон
	hiddenDiv = $(document.createElement('div')),
	content = null;
// добавляем класс .noscroll элементу #comments(эл-т textarea)
	txt.addClass('noscroll');
// добавляем класс .hiddendiv элементу-клону 
	hiddenDiv.addClass('hiddendiv');
//добавляем элемент-клон в тег  body 
	$('body').append(hiddenDiv);
//связываем событие keyup (пользователь отпускает 
//клавишу клавиатуры)
//c функцией. Все приминительно к элементу textarea#comments
	txt.bind('keyup', function() {
// возвращаем значение атрибута value  элемента 
// #comments(textarea)
// (вводимые пользователем данные)
	    content = txt.val();
// символ перевода каретки (\n), везде (g) меняем на <br>  
	    content = content.replace(/\n/g, '<br>');
	    hiddenDiv.html(content);
// назначаем высоту элемену #comments(эл-т textarea)
	    txt.css('height', hiddenDiv.height());

	});
});

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

Как видите, высота будет меняться автоматически посредством событие keyup. Очень удобно, если для загрузки контента вы используете Ajax.

Как насчет IE6-8?

Я чуть не бросил написание этой статьи, так как код не работал в IE6-8. Не работал он в связи со слабой обработкой в IE внутреннего содержания HTML. Решение я все же нашел, плюс мне попался jQuery плагин. Он использует тот же метод, что и я (клонированный элемент), и работал он (главным образом) в IE.

Вот строка, которую я позаимствовал из этого примера и которая решает (главным образом) мою проблему с IE:

CSS

content = content.replace(/\n/g, '<br>'); 

Однако даже после добавления этой строки все еще оставалась одна загвоздка: длинные строки текста не влияли на высоту элемента textarea. Решить эту проблему помогло добавление к элементу-клону объявление word-wrap: break-word к CSS.

Взглянуть на демо вы можете, кликнув по ссылке ниже. Дайте мне знать, если столкнетесь с какими-либо проблемами.

Использованы материалы статьи

высота у textarea меняется автоматически

Комментарии к статье

аватарка пользователя
2012-03-27
Артем

А демка не работает (Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2)

аватарка пользователя
2012-03-27
Костя

может быть, только что проверил в своих старых (IE 7, FF 4.0.1, opera 10) - все работает, Да и все статьи - это всего лишь идеи, никогда не буду проверять на 100% кроссбраузерность.

аватарка пользователя
2012-04-16
Dober

ни в одном браузере не работает....

аватарка пользователя
2012-04-16
dnzl

работает, включить javascript стоит

аватарка пользователя
2013-01-06
Дмитрий С

Зачем извраты с div-ами?

function textAreaHeight(textarea) {
if (!textarea._tester) {
var ta = textarea.cloneNode();
ta.style.position = 'absolute';
ta.style.zIndex = -2000000;
ta.style.visibility = 'hidden';
ta.style.height = '1px';
ta.id = '';
ta.name = '';
textarea.parentNode.appendChild(ta);
textarea._tester = ta;
textarea._offset = ta.clientHeight - 1;
}
if (textarea._timer) clearTimeout(textarea._timer);
textarea._timer = setTimeout(function () {
textarea._tester.style.width = textarea.clientWidth + 'px';
textarea._tester.value = textarea.value;
textarea.style.height = (textarea._tester.scrollHeight - textarea._offset) + 'px';
textarea._timer = false;
}, 1);
}

аватарка пользователя
2013-01-06
Дмитрий С

Это надо повесить на onkeydown текстбокса.

аватарка пользователя
2013-11-09
Веб профи

Отличная штука, работает лучше даже, чем в других местах предлагали. Спасибо!

Добавить комментарий