div模拟textarea文本域轻松实现高度自适应

一、关于textarea文本域以及高度自适应

textarea标签为表单元素,一般用在多行文字的输入。在web应用上常见的是评论输入框,微博信息输入框等。例如企鹅微博的输入框:
企鹅微博的文本域输入框 张鑫旭-鑫空间-鑫生活

作为多行文本域功能来讲,textarea满足了我们大部分的需求。然而,textarea有一个不足就是不能像普通div标签一样高度可以跟随内容自适应。textarea总是很自信地显摆它的滚动条,高度固执地岿然不动。所以,有时候,为了增加交互体验想让文本域高度自适应的时候,就会遇到麻烦。并不是不能实现,例如Google的Buzz的输入框就是高度自适应里面的内容的,如下截图:
Buzz输入框高度自适应默认 张鑫旭-鑫空间-鑫生活
Buzz输入多行文字后高度自动撑高 张鑫旭-鑫空间-鑫生活

不说远的,我个人网站的提问与交流页面中的回答输入框(需登录):
提问与交流页面的回答框 张鑫旭-鑫空间-鑫生活

当输入一些文字后,文本域的高度自动随内容多少撑高了:
输入些文字后高度自动变高 张鑫旭-鑫空间-鑫生活

然而,这些文本域的高度自适应都是通过JavaScript脚本实现的。拿我个人站点上的高度自适应文本框来说,要克隆一个隐藏的textarea,通过实时的文字赋值,检测是否产生滚动条来确定显示文本域的高度是否动态增加。对于JavaScript不熟悉的人来讲,这种方法的实现比想办法跟校花约会还麻烦。

然而,实际上,如果你要求不是很高,是个非常简便,且老少皆宜的实现方法的。这种方法就是使用普通的div标签模拟textarea文本域,同时又利用了div标签的高度自适应性。于是,textarea文本域的高度自适应效果就可以轻松实现。

二、div模拟textarea文本域及高度自适应

我之前翻译过一篇文章,名为“你必须知道的28个HTML5特征、窍门和技术”,其中在“六、内容可编辑”部分介绍了一个标签属性,为contenteditable,顾名思意,就是允许用户编辑元素内容包含的任意文本,包括子元素。

应用了此属性后,普通的div标签也会像文本域一样可以获得焦点,同时有一个光标在那里闪啊闪,闪啊闪,你越看她她越闪。web QQ 2.0 的聊天对话框的输入框就是应用了此属性。
web QQ 2.0的输入框截图 张鑫旭-鑫空间-鑫生活

//zxx:企鹅的圣诞主题界面很nice,视觉效果很赞,下雪的效果也很有爱,连cup也为之奔腾。

使用很简单,一个普通的block元素上加个contenteditable="true"就ok了,如下:

<div contenteditable="true"></div> 

true外面的引号甚至去掉都没关系。

contenteditable属性虽是HTML5里面的内容,但是IE似乎老早就支持此标签属性了。所以,兼容性方面还是不用太担心的。

ok,最麻烦的模拟textarea的可编辑效果已经解决了,现在想要使用div实现高度自适应那就像是给花花草草松松土一样容易的。使用min-height属性基本上就一步到位了,考虑到IE6浏览器对min/max家族不屑一顾,结合其内部元素溢出会撑开父标签高宽的特性,IE6浏览器直接定高就可以了。于是,假设我们要实现默认200像素高度,高度可随内容自适应的效果,直接下面两个样式就可以了:

{ min-height: 200px; _height: 200px; }

于是,把说到现在的内容结合一起,就可以使用div模拟textarea文本域轻松实现高度自适应了。

如下测试代码——
CSS代码:

.test_box {
    width: 400px; 
    min-height: 120px; 
    max-height: 300px;
    _height: 120px; 
    margin-left: auto; 
    margin-right: auto; 
    padding: 3px; 
    outline: 0; 
    border: 1px solid #a0b3d6; 
    font-size: 12px; 
    word-wrap: break-word;
    overflow-x: hidden;
    overflow-y: auto;
    _overflow-y: visible;
}

HTML代码:

<div class="test_box" contenteditable="true"><br /></div> 

结果如下图(全部截自IE6浏览器):
IE6下div模拟的textarea默认 张鑫旭-鑫空间-鑫生活

然后从新浪博客首页随便找篇文章,拷点文字复制进去,结果如下图:
IE6下模拟textarea高度自适应 张鑫旭-鑫空间-鑫生活

可以看到可编辑标签高度自带撑开了。完全的CSS,没有杂碎的js代码。我们设置可以设定一个最大高度(max-height),让其超出的时候出现滚动条,正如下面demo页面所做的一样。

您可以狠狠地点击这里:div模拟textarea以实现高度自适应demo
Firefox3.6下的demo效果截图 张鑫旭-鑫空间-鑫生活

然而,事情并不会如此一帆风顺,还有不少注意事项值得一提。

三、一些注意与说明

1、 现代浏览器如Firefox在可编辑模式下的div获取焦点的时候会有虚框,而实际上textarea是没有虚框显示的,此迹象会暴露出div是个冒牌货,所以,需要添加下面的样式:

outline:0;

2、 Firefox浏览器下可编辑模式的div如果内部元素是空空的,那么其在获取焦点是时候,光标不可见或是与外部div齐高,这也是会暴露出自己是textarea冒牌货的,所以,默认情况下,我们可以在此div中增加一个孤单的<br />换行标签。但是,IE8下,如果有个默认的br标签,光标位置可能会在第二行闪来闪去,所以,IE8下可编辑div里面默认是不能有br标签的,这个嘛,您自己想办法清掉吧。

3、 IE浏览器下(IE6~8),输入文字回车的时候,div内部是会自动产生p标签包含每行元素的,而其他浏览器貌似是产生br标签(这里尚未全部测试,如有不准,欢迎指正)。由于默认的p标签是有1em大小的上下margin值的,为了效果统一,我们可以设置诸如下面的样式清除p标签的margin值:

.test_box p{ margin: 0; }

4、可编辑模式的div输入的内容都会是很正宗的HTML代码,如果作为内容提交的话需要进行HTML字符过滤。还有,如果您是从其他页面上拷贝一段内容过来,然后粘贴到可编辑模式下的div中,会连HTML也完整的复制过来的(不同于textarea),所以,这里也有必要进行HTML字符过滤(例如web QQ)。
复制的HTML代码显示 张鑫旭-鑫空间-鑫生活

5、 IE6浏览器不支持max-height属性,所以,只用CSS是无法实现超过一定高度出现滚动条的效果,需要js配合实现。

6、 可编辑模式的div标签与textarea一样,是支持focus, blur事件的。自然也支持focus伪类,demo页面中Firefox等现代浏览器获取焦点时的外发光就是使用的:focus。

四、圣诞前夜之结语

明天平安夜,公司的老外市场主管raph已经回家过年去了,这几天是不会过来了。像圣诞节这种具有喜庆气息的日子,正是埋头写代码的好日子,因为比较容易受刺激。麻麻,无所谓啦,闷骚无敌,大不了什么时候去百合网,世纪佳缘什么的溜达溜达。

啊,就这些,感谢您的阅读。要是文章有表述不准确的地方欢迎指正。

原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址: http://www.zhangxinxu.com/wordpress/?p=1362

(本篇完)

分享到:

标签: , , , , , ,

赞助商推荐(我也要赞助)

想学到点真东西? ×
如果你有1~3年前端开发经验,不妨 ×
想要工资30K? ×


发表评论(目前53 条评论)

  1. 简单说道:

    那么问题来了,placeholder和maxlength等基本的拿来就用的属性要怎么实现?又要配合大段的的js和css来模拟

  2. 尘泥说道:

    张大大,您好,请问用div模拟的textarea文本框,在苹果手机上需要长按才能显示光标输入,有什么办法可以让它像安卓机一样轻触就可显示光标输入吗?

  3. 沙漠地说道:

    div的placeholder怎么搞?

  4. 大熊说道:

    但是这个使用在ios上有bug,就是将属性移除的时候,失去焦点的时候键盘无法隐藏啊,还有,在ios的app的webview上复制粘贴后,焦点无法移到文字最后。这个该如何解决?

  5. 游客007说道:

    可惜在手机上,自动获取焦点,呼出不了键盘

  6. kaikai说道:

    百度知道回答框用了这个属性,

  7. kaikai说道:

    好像web QQ 现在没在使用这个属性了!

  8. 夕风色说道:

    可惜这个属性在手机上无法呼出键盘,要是能就好了,谢谢分享。

  9. xxr说道:

    我想在里面写alert(0),怎么让他有弹出框出现,它老是变成字符串。。。。

  10. shejuly说道:

    旭神,我是这么个情况,本来用的textArea加JS。但后来我们要求能识别超链接,textArea不支持HTML标签。于是我改成了div+contenteditable的方式,虽然识别超链接了,但是超链接只能选中,不能点击打开。极其诡异。这种情况怎么破?

    • WEB大白说道:

      这个问题有点早了 不知道解决了没有,正好我也遇到了就来回答一下吧 其实并不难创建一个iframe内联框架即可

  11. 少华说道:

    用contenteditable这种方式,在一些浏览器上当内容太高出现滚动条的时候光标会有问题啊

  12. ching说道:

    大神,膜拜啊

  13. 小凡说道:

    第二点问题有便捷的方法解决么?

  14. asdfg说道:

    如果在文字里面添加表情,要怎么获取光标位置呢,添加表情后光标位置怎么设置呢

  15. csy说道:

    问一下,我让一个div变成可编辑div 怎么自动获取焦点呢?

  16. 表单中包含一个可编辑div,那么想请教一下 如何提交这个div的内容呢?
    新手,望赐教

  17. 说道:

    首先感谢分享,不过有一个疑问不知楼主能不能解答?contenteditable也不是万能的,当你不是手工输入而是复制粘贴时,会连同文本的样式也贴入其中,这样对获取数据来说是非常不美妙的。请问有没有完美解决方法呢?

  18. 小漆说道:

    太棒了!解决我很大一问题,受教了。谢谢–

  19. 梁经国说道:

    我正在搞一个像webqq这样的东东,本来想用textarea来作为输入框的,当看到你的这篇文章时,呵呵,我改变主意了。大神!向你学习了。

  20. lee说道:

    很喜欢你的博客,不仅是技术有意思,更是那种乐观的精神,让人喜欢。这个正需要,谢谢lz啦,膜拜

  21. 美格印象说道:

    刚前两天做项目用textarae+js实现了,今天就发现更好的方法了。

  22. 强记说道:

    用div模拟,还是html标签也能输入进去,用word复制代码会带上html标签

  23. zhanghongbo说道:

    如果页面引用了jquery mobile在使用textarea。文本域会随内容的增加而一起增高。我想弄成不会自动增高的。现在已经弄出来了。但是如果页面同时也引用了jquery mobile那么。textarea又会自动随文本的增多而增高。去掉jquery mobile就可以时间类似QQ聊天窗口那样输入内容,超过textarea高度会自动在内部向上滚。现在不知道怎么解决,同时引用jquery mobile的页面怎么设置textarea

  24. Liner_z说道:

    刚被textarea的问题折磨得头疼,原来鑫同学早在2010年就发现这东西了。
    补充下,chrome用到是来包裹内容。FF用了。IE用。
    负责了网页内容的话,编辑会很麻烦,此时源代码显示的是表格布局,导致容易出现一个退格键就把整个表格删了,一般人还以为是bug。另外一个问题是在单元格内删东西,删完了,就不动了,又会让人以为是bug。
    15楼abc那个问题,必须用js去获取,div不是表单元素,不能直接拿到内容。

  25. 勤劳的xiaoshi说道:

    报告:咋个在IE7下,div内的文字不可以执行复制、粘贴和全选文字的一些操作呢?是contenteditable=”true”属性的问题吗?

  26. 游客说道:

    我想在表单中使用,该如何操作?我的意思是怎么提交div的数据并传给表单处理程序?

  27. 路人甲说道:

    在Opera浏览器下不能用。

  28. 路人说道:

    非常好,非常详细,受用。

  29. robertsky说道:

    我想说的为了实现这个需要做很多兼容代码,而且你依然要使用js来实现原本textarea中可以很容易实现的效果,楼主的钻研精神我很佩服

  30. lykk说道:

    HTML字符过滤要怎么做你?这个是要涉及剪贴板的操作吧,ff是很严的

    • 张 鑫旭说道:

      @lykk 设置一个几毫秒的定时器,在粘贴事件触发后执行div内部HTML代码的过滤即可。IE浏览器保留p标签,其他浏览器保留br标签。

  31. abc说道:

    你好,我是初学者,在用div模拟后,如何获取输入的内容呢,如果是放在form中

  32. afeiship说道:

    回复: 赤金WEB程序 说:

    能用XHTML和CSS实现的,你去用jQuery.只能说你对Web标准还没有理解好!

  33. SkyWoo说道:

    你好,请问你写文章的时候就是直接用WP的编辑器写出来的吗?我博客刚做好,我怎么觉得写文特别麻烦呢?排版方面,好多体验都不爽……

  34. 裕波说道:

    你先把内容写进去
    写很多很多
    最后你在删除试试?

  35. GodSon说道:

    在ie6里面没有出现滚动············

  36. 奚少说道:

    嗯,这一点很实用的。
    学习一下~

  37. 老朋友说道:

    因为专,所以精,继续加油。

  38. 你们真是厉害。。天天都可以研究这些代码 。、稍是难一点的我都看不懂。。

  39. 赤金WEB程序说道:

    就这一个小小问题还…………至于嘛~~~
    用jQuery给textarea绑定两事件就搞定了
    $(“textarea”).bind(“keydown keyup”, function(){
    var th = $(this), thsh = th.attr(“scrollHeight”);
    if (thsh > th.height()) th.animate({height: thsh + 30}, 300);
    });
    不就得了?

    • reyhappen说道:

      骚年,你要是把文字从页面拖到输入框你就知道你的问题所在了,还有右键粘贴或者删除剪切等

  40. 独孤逸辰说道:

    简直就是一个小小的编辑器了,呵呵

  41. 时时彩群说道:

    感谢楼主分享的好文章!!!

  42. 香袭人2代说道:

    感谢楼主分享的好文章!!!http://www.xiangxiren2dai.com

  43. oogps说道:

    全是经典的文章。圣诞,元旦快乐!