一、display:table-cell属性简述
display:table-cell属性指让标签元素以表格单元格的形式呈现,类似于td标签。目前IE8+以及其他现代浏览器都是支持此属性的,但是IE6/7只能对你说sorry了,这一事实也是大大制约了display:table-cell属性在实际项目中的应用。
我们都知道,单元格有一些比较特别的属性,例如元素的垂直居中对齐,关联伸缩等,所以display:table-cell还是有不少潜在的使用价值的,虽说IE6/7不支持此属性,但是幸运的是,IE6/7一些乱糟糟的属性与渲染,我们可以其他方法实现同样或是类似的效果。
与其他一些display属性类似,table-cell同样会被其他一些CSS属性破坏,例如float, position:absolute,所以,在使用display:table-cell与float:left或是position:absolute属性尽量不用同用。设置了display:table-cell的元素对宽度高度敏感,对margin值无反应,响应padding属性,基本上就是活脱脱的一个td标签元素了。
二、display:table-cell与大小不固定元素的垂直居中
使用display:table-cell让大小不固定元素垂直居中已经是很老的方法了,关于此应用,我已经在“大小不固定的图片、多行文字的水平垂直居中”这篇文章中有过介绍。
方便阅读,这里再次展示下代码:
/*这里的大小是根据高宽上限128像素图片设置的*/
div{display:table-cell; width:1em; height:1em; border:1px solid #beceeb; font-size:144px; text-align:center; vertical-align:middle;}
div img{vertical-align:middle;}
结果如下图:
这里有个demo地址,里面有display:table-cell实现大小不固定图片垂直居中的效果展示,您可以狠狠地点击这里。
二、display:table-cell与两栏自适应布局
就在前不久,看facebook好友动态列表页面前端代码的时候才发现原来display:table-cell可以用在两栏的自适应布局上。
虽然IE6/7不认识display:table-cell,但是亏了其一向自以为是的渲染与解析,我们可以很幸运的使用其他属性实现几乎一致的效果。
您可以狠狠地点击这里:display:table-cell下两栏自适应布局demo
代码展示:
本例中,左侧为头像,右侧内容自适应。其中头像部分使用了float属性,左浮动,IE8+以及Firefox、Chrome、Opera等现代浏览器右侧使用了display:table-cell属性,结果就自适应了,很简单的代码,很神奇的效果。
OK,对于不认识display:table-cell属性的IE6/7呢?哦呵呵,很简单,使用display:inline-block属性代替display:table-cell就完全ok的啦!
原因在于:IE6/7下block属性的元素对inline-block属性是有反应,但是却不是纯洁的反应,而是怪蜀黍看到粉嫩小萝莉的一点邪念,就是让元素有个怪异的haslayout属性。//zxx:大家似乎都喜欢用haslayout解析一些老IE下的一些怪异现象,但我自己打心底里是不认同这个概念。
如果IE6/7是很标准的纯洁的解释inline-block属性的话,是无法实现自适应的,右侧的文字描述内容会跑到头像的下面,哦呵呵~~有点负负得正,以毒攻毒的意味。代码如下:
display:table-cell; *display:inline-block;
就万事大吉,收工回家了。
在本例demo中,右侧内容足够多,所以宽度完整的撑开了,如果内容有限,则宽度就是内容的宽度,此时想要让某个元素(例如关闭按钮)右侧定位就会有问题,解决方法就是定义一个非常宽的宽度,就像上面facebook截图中的CSS属性一样,所以,考虑到各种情况,更健壮耐用的CSS代码应如下:
display:table-cell; *display:inline-block; width:2000px; *width:auto;
或者使用:
display:table-cell; width:2000px; *width:auto; *zoom:1;
这种两栏的自适应布局,不仅不要分别丈量与计算两列的宽度,连“页面重构鑫三无准则 之无宽度准则”中absolute自适应布局的头像宽度都不需要亮了,可以说是更加懒惰,更加直接的好方法。
三、display:table-cell下的等高布局
table表格中的单元格最大的特点之一就是同一行列表元素都等高。所以,很多时候,我们需要等高布局的时候,就可以借助display:table-cell属性。说到table-cell的布局,不得不说一下“匿名表格元素创建规则”:
CSS2.1表格模型中的元素,可能不会全部包含在除HTML之外的文档语言中。这时,那些“丢失”的元素会被模拟出来,从而使得表格模型能够正常工作。所有的表格元素将会自动在自身周围生成所需的匿名table对象,使其符合table/inline-table、table-row、table- cell的三层嵌套关系。
举个例子吧,如果我们为元素使用“display:table-cell;”属性,而不将其父容器设置为“display:table-row;”属性,浏览器会默认创建出一个表格行,就好像文档中真的存在一个被声明的表格行一样。如果您还不是很理解,可见参见支付宝UED的“基于display:table的CSS布局”一文。//zxx:支付宝今年的招牌广告做得很赞的~~
实现等高布局,毫无疑问,display:table-cell是首选,这就好比鼹鼠,生下来就是为了打洞用的。考虑到匿名创建表格元素的问题,所有table-cell元素外一定要留有一个用来包裹的标签。于是,我们有类似下面的CSS代码:
.list_row{display:table-row;}
.list_cell{display:table-cell; width:30%; padding:1.6%; background-color:#f5f5f5;}
/*中间一个元素背景淡蓝,有别于两边的淡灰色*/
.list_center{background-color:#f0f3f9;}
结果在现代浏览器下(如下Firefox3.6下截图):
您可以狠狠地点击这里:table-cell等高布局demo
对于不支持display:table-cell属性的IE6/7浏览器,又当如何解决呢?
我们可以使用“补差等高法”,就是一个一个很大的margin-bottom负值配上一个同样大小的padding-bottom值,本例中为了实例需要,margin-bottom值就百来像素。显然,由于两者原理不同,难免需要用到hack,所以demo完整CSS代码如下:
.list_row{display:table-row; overflow:hidden;} .list_cell{display:table-cell; width:30%; margin-bottom:-100px; padding:1.6%; *padding-bottom:110px; background-color:#f5f5f5; *float:left;} .list_center{background-color:#f0f3f9;}
认识display:table-cell属性的元素对margin属性不敏感,所以上面margin-bottom属性前没有加*号。HTML结构代码如下:
<div class="list_row"> <div class="list_cell">你一定也有过这种感觉的。...罗兰《寂寞的感觉》</div> <div class="list_cell list_center">作为一个被基阿异捅过...水,四积阴功五读书。</div> <div class="list_cell">奔波了一...永远幸福快乐!</div> </div>
//zxx:“补差等高法”虽然有效,也有兼容性,但是会带来一些潜在的问题,不宜多用。
四、display:table-cell下的列表布局
这里的列表布局专指横向repeat的布局,就像下图所示的:
一般这类布局都是使用浮动的。但是浮动布局的不足在于:一是需要清除浮动造成影响;二是不支持不定高列表的浮动。替代浮动布局的方法是有的,如果深究细节以及一些思想,方法还不少。其中有一个方法就是使用display:table-cell。
当然,说句心里话,将display:table-cell属性用在列表元素布局上,有点类似于张飞绣衣服,大马拉小车,优势并没有多大发挥,但是,毕竟也算浮动布局的一个备用替换方案。我的下一篇文章将会详细讲解浮动布局的替换方案,其中table-cell方法可以说是里面最不好的一个方法,本着过渡和热身的目的,这里只简单讲过。
首先是效果:
您可以狠狠地点击这里:display:table-cell下的列表布局
可以看到即使模块高度不一致,也不会产生浮动布局可能产生的错位。
由于table-cell需要每行包裹一个独立的标签,所以,在后台repeat输出的时候,需要两次循环,而是列数是限死的(与浮动布局一样)。对于简单的列表,使用display:table-cell是很难看到什么优势的,但是,如果列表复杂,数据多,内容细,display:table-cell可能会像大S订婚的传闻那样让人震惊。
现在已经很少有人会使用table来设计网页的布局,但是table真的过时了吗?不然!例如,在很常见的一个2列的布局中,左边我们想放一个导航菜单,右边放置正文内容,然后顶上放置一个header,页面最下方放置一个footer,这应该是一个很常见的页面布局方式。
这个时候,我们希望中间的siderbar跟正文内容都有相同的高度,顶着上面的header与下面的footer,该怎么办呢?
带着这个疑问,我将介绍css中的display属性table,table-cell,table-row,table-row-group,table-header-group,table-footer-group,table-caption,table-column,table-column-group。我想大家肯定对display:block,display:inline相当熟悉了,但是在这儿我还是想啰嗦一下对display熟悉的理解。
display属性会定义标签的盒子模型,每一个标签都有自己的默认盒子模型,例如div得默认盒子模型为block,span的默认盒子模型为inline,li的默认盒子模型为list-item。每一种盒子模型都有一些默认特征,例如block模型会默认独占父元素的宽度,当然,我们也可以设置它的宽度。但是inline模型则跟它相比有很大区别,inline元素会根据其内容自动调整宽高,因为就算我们显式设置其宽高也没用,正因为如此,inline元素一般不会独占父元素的宽度。
那么回到主题,当display属性为table,或table-*时,对应的元素会有什么样的特征呢?我们都知道table标签,它可以设置背景,边框,可以定义里面每行的高度,可以定义每列的宽度。可以直观理解当一个标签的display属性设置为table后,它就具有table标签的一些默认特征。那我们会问:这样的话跟直接使用table标签有什么区别呢?这就涉及到一个样式与数据分离的原则了,在HTML中我们应该尽量不要包含样式的信息,它只是用来定义网页的基本结构,元素之间的逻辑位置关系,以及所包含的信息,所以后来都推荐使用XHTML,也许有这方面的考虑吧。而CSS样式则用来告诉浏览器应该怎样展示HTML。如果直接用table,table定义的是一个语义结构,它除了会把数据用表格显示,并且指示这个地方就是一个表格,可能会在可访问性上造成歧义。
另外如果想调整布局也比较困难。另外,难道说我们就要彻底摒弃table标签吗?当然也不是!例如我们要呈现一些数据表,那还是用table非常合适的。
下面是一个用display=table布局的范例:
- <nav>
- <section class="command-list">
- <section class="command-item"><span>Home</span></section>
- <section class="command-item"><span>Archive</span></section>
- <section class="command-item"><span>Download</span></section>
- <section class="command-item"><span>Leisure</span></section>
- </section>
- </nav>
- .command-list {
- display: table;
- border-spacing: 10px;
- table-layout: fixed;
- }
- .command-item {
- display: table-cell;
- border-radius: 10px;
- background-color: #a9ed8c;
- text-align: center;
- width: 200px;
- line-height: 2em;
- vertical-align: middle;
- }
我们知道table, head, tr, td, footer都有严格的层次关系,那么使用display属性时会不会有这方面的限制呢?没有。原因是浏览器会自动创建匿名元素。例如在上面的例子中我们直接让子元素的display属性值为table-cell,这个时候,浏览器在呈现时会自动把这些拥有table-cell属性值的子元素依次添加到一个匿名的元素中,该元素的display属性值为table-row。
- <div class="cell">cell1</div>
- <div class="cell">cell2</div>
- <div class="cell">cell3</div>
- <div>cell4</div>
另外,还有些相关的CSS属性:
table-layout 定义table layout算法
-
auto - 列宽由cell中不可断开(unbreakable)的内容的最大宽度觉得; 缺点是比较慢,因为它要读取table中所有的内容才能确定列宽
- fixed - 水平宽度只由table的宽度和列宽决定,而不是cell中的内容; 性能比较好, 浏览器只要碰到第一行就能决定table怎么显示了
- inherit - 属性值继承至父元素
border-collapse:定义table的边框是否折叠成一个边框
- collapse - 边框尽量折叠,border-spacing和empty-cells属性值被忽略
- separate - 边框分开,border-spacing和empty-cells属性值不被忽略
- inherit - 属性值继承至父元素
- <section class="content-container-sample">
- <section class="left-sidebar">
- <ul>
- <li>Message In Site</li>
- <li>Forum</li>
- <li>Blog</li>
- <li>Ask Question</li>
- </ul>
- </section>
- <section class="right-content">
- <blockquote >
- <p>Perhaps you’re feeling slightly uncomfortable about the example we’ve just seen—after all, haven’t web standards advocates like myself been insisting for years that you shouldn’t be using tables for layout?</p>
- </blockquote>
- <q>
- Perhaps you’re feeling slightly uncomfortable about the example we’ve just seen—after all, haven’t web standards advocates like myself been insisting for years that you shouldn’t be using tables for layout?
- </q>
- </section>
- </section>
- .content-container-sample {
- display: table;
- border-collapse: collapse;
- width: 80%;
- margin:0 auto;
- }
- .left-sidebar {
- display: table-cell;
- width: 25%;
- background-color: #e0e0e0;
- }
- .left-sidebar > ul {
- list-style-type:none;
- }
- .left-sidebar > ul > li {
- margin-bottom:15px;
- }
- .right-content {
- display: table-cell;
- width: 75%;
- height: 500px;
- background: -moz-linear-gradient(45deg, #ab9898, #f3abab);
- }
我的一个布局应用实例:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>无标题文档</title>
<style type="text/css">
#div_table{
width: 960px;
height: 480px;
display: table;
position: absolute;
top: 20px;
left: 100px;
}
#div1{
border: 1px solid #0F0;
display: table-cell;
height: 480px;
width: 200px;
left: 0px;
top: 0px;
position: absolute;
}
#div2{
display: table-cell;
position: absolute;
height: 480px;
width: 460px;
border: 1px solid #F00;
left: 200px;
top: 0px;
}
#div3{
display: table-cell;
position: absolute;
height: 480px;
width: 300px;
left: 660px;
top: 0px;
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="div_table">
<div id="div1">
</div>
<div id="div2"></div>
<div id="div3"></div>
</div>
</body>
</html>
五、结语
对于display:table-cell,我自己其实用的并不多,毕竟其特殊之处就在于垂直居中,等高,水平级联,匿名创建等特性,其他种种属性可以使用其他更好的display属性代替的。但是话说回来,不太使用display:table-cell属性的真正的原因可能是对该属性的了解的还不够深入,可能该属性本身是存在很多非常实用的应用,但是自己由于掌握不够而不知道。所以,要是哪位同行知道display:table-cell其他一些不错的应用的话,欢迎大力补充,不甚感谢!