固定表格布局下的各浏览器对与表格宽度计算算法不同。
列的宽度不够容纳其内容时,IE6 IE7 IE8(Q) 会将溢出的内容隐藏,而其他浏览器则会根据单元格的 'overflow' 属性决定是否隐藏溢出内容,这时候溢出单元格的内容有可能与其他单元格的文字重叠。
有浏览器对于 TABLE 元素均是将宽度作用于 'border-box',但是对于 TD 元素的宽度的作用范围在不同浏览器中却产生了差异,而 IE(Q) Chrome Safari 中的处理更接近标准,即单元格与表格一样,其宽度均作用于 border-box 。
由于单元格边白的影响,当我们为一组列设定宽度后,其实际运行效果不一定与设定宽度相符。这有可能造成一系列的问题,如内容溢出、内容折行等。这时应尽量避免设置单元格的 'padding',若需要单元格内容需要留有空白,可以为其添加子元素 DIV,为 DIV 元素设置 margin 达到相同的效果。
所有浏览器 |
---|
CSS2 中的 'table-layout' 属性定义了两种不同的表格宽度计算方式,根据 W3C CSS2.1 规范第 17.5.3 节中的描述, 'table-layout' 属性值有 'auto' 与 'fixed',对应两种不同的计算方法,'auto'为缺省值。
1.1. 固定布局算法概述
CSS 规范中对 'table-layout:fixed' 这种固定布局算法有更具体的描述,这种算法下,表格的宽度应显式的由 'width' 属性指定。如果其 width 为 auto,则代表将使用自动算法('table-layout:auto')对表格布局。
在固定表格布局算法中,各列的宽度也有规定:
所以,表格的实际宽度是 TABLE 元素的 'width' 设定宽度和各列宽(加上单元格间隔或边框)之和的较大值。若表格比各列之和更宽,则多余的空间(或宽度)将被分配到所有列中。
上述内容仅规定了最一般情况下对于 'table-layout:fixed' 时表格宽度计算所应遵循的基本规范。而对于列宽设定为百分数及像素单位时,单元格包含边白(padding),或者 TABLE 元素设置了 cellpadding 及 cellspacing 属性时等复杂情况,规范并没有明确说明浏览器端应该遵循的一些基本算法。下面将就这些较复杂的情况分析各浏览器对固定布局算法的表格、单元格宽度的计算。
由于在 IE6(SQ) IE7(SQ) IE8(Q) 中TD元素内容溢出 BUG,所以为了简化情况,下面的测试样例只讨论算法的差别,不再对 IE 的 BUG 进行截图。各浏览器对于计算后的宽度为小数时,由于精度不同带来的 1px 的差异不再进行分别讨论。
由于 W3C 规范中并没有明确说明宽度算法,各浏览器根据各自的理解进行宽度计算,而浏览器之间出现差异主要体现在表格元素设置的宽度与单元格设置的宽度之和不符时,各浏览器的算法差异。
测试代码中均在 TD 元素内加了一层 DIV 元素,目的是通过 TD 与 DIV 背景色区分出 TD 元素的实际可用宽度,即 TD 内可以容纳内容的实际宽度。
2.1. 宽度设定为百分比
2.1.1. 算法分类
<table style="width:200px; table-layout:fixed; background:darkkhaki;" cellpadding="0" cellspacing="0"> <tr> <td style="width:10%; background:plum;"> <!-- 【TD1】 --> <div style="background:pink;">AAA</div> </td> <td style="width:30%; background:dodgerblue; padding-left:50px;"> <!-- 【TD2】 --> <div style="background:lightblue;">BBB</div> </td> <td style="width:60%; background:crimson;"> <!-- 【TD3】 --> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6 IE7 IE8(Q) | |
---|---|
IE8(S) Chrome Safari Opera | |
Firefox |
从上面截图中可以明显看出,Firefox与其他浏览器对于单元格设置了padding后的算法不同,而IE6/7及IE8混杂模式与Chrome的区别仅仅是对于TD元素中的内容溢出后浏览器是否隐藏溢出的内容。W3C CSS2.1规范第17.5.2.1节 中有明确的规定:
In this manner, the user agent can begin to lay out the table once the entire first row has been received. Cells in subsequent rows do not affect column widths. Any cell that has content that overflows uses the 'overflow' property to determine whether to clip the overflow content.
上面规范中说明:如果单元格内容有溢出,经根据 'overflow' 属性确定是否剪裁溢出的内容。默认的 'overflow' 属性值为 'visible',在本例中浏览器应该保持内容的默认 'overflow' 属性,但由于 'table-layout:fixed' 下 TD 元素宽度无法被其内容撑开,所以会发生内容溢出后与其他单元格内容重叠的现象。而在 IE6 IE7 IE8(Q) 中,浏览器的处理是错误的。
通过各浏览器的开发人员工具可以测得:
2.1.2. 加入边框、边白、及边距
<table style="width:200px; table-layout:fixed; background:darkkhaki; border:1px solid black" cellpadding="5" cellspacing="5"> <tr> <td style="width:10%; background:plum;"> <!-- 【TD1】 --> <div style="background:pink;">AAA</div> </td> <td style="width:30%; background:dodgerblue; padding-left:20px;"> <!--【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:60%; background:crimson; padding-right:20px;"> <!--【TD3】 --> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6 IE7 IE8 Chrome Safari Opera | |
---|---|
Firefox |
在增加了边框、cellpadding、cellspacing 后,与上面的情况类似,同样是 Firefox 中的算法与其他浏览器不同。
在这里当单元格设置了 'padding' 后,如 'padding-left:20px' ,且 TABLE 元素有 'cellpadding' 属性,如 cellpadding="5",这时候该单元格实际的左补白为 CSS 的 padding-left 而不再是cellpadding 属性,即 'padding-left' 为 '20px'。
TABLE 元素的内容宽度为200px - 1px - 1px = 198px,即TABLE设置的宽度减去左右边框所占的宽度,因为在所有浏览器下TABLE的宽度都是作用于 border-box,且与文档模式无关。由于 border="1"、cellpadding="5"、cellspacing="5",所以这时的TABLE元素的列的可用宽度为198px - 4 * 5px = 178px,即TABLE元素的内容宽度减去由 cellspacing 属性带来的4个水平方向的单元格间距。列的可用内容宽度为178px - 5px - 5px - 20px - 5px - 5px - 20px = 118px,即列的可用宽度再减去各列左右边框及边白占去的宽度。
在IE Chrome Safari Opera中,【td1】的实际宽度为10% * 178px = 18px,其可用内容宽度为18px - 5px - 5px = 8px,即减去由单元格边白带来的2个5px;【td2】的实际宽度为30% * 178px = 54px,其可用内容宽度为54px - 20px - 5px = 29px,【td3】的实际宽度为60% * 178px = 106px,其可用内容宽度为106px - 5px - 20px = 81px。
在 Firefox 中,【td1】的可用宽度为10% * 118px = 12px,其实际宽度为12px + 5px + 5px = 22px,即加上由单元格边白带来的2个5px;【td2】的可用宽度为30% * 118px = 35px,其实际宽度为35px + 20px + 5px = 60px;【td1】的可用宽度为60% * 118px = 71px,其实际宽度为71px + 5px + 20px = 96px。
2.1.3. 列的宽度之和小于 TABLE 的总宽度
<table style="width:200px; table-layout:fixed; background:darkkhaki; border:5px solid black" cellpadding="5" cellspacing="5"> <tr> <td style="width:10%; background:plum;"> <!--【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:20%; background:dodgerblue; padding-left:20px;"> <!-- 【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:30%; background:crimson; padding-right:20px;"> <!--【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6 IE7 IE8 Chrome Safari Opera | |
---|---|
Firefox |
三个列的宽度之和仅为60%,这时各浏览器均是将剩余的40%根据这三列的宽度的比例大小进行分配。如上例中,【td1】的实际宽度百分比为10% / 60% = 16.667%;【td2】的实际宽度百分比为20% / 60% = 33.333%;【td3】的实际宽度百分比为 30% / 60% = 50%。而对于各列的实际渲染宽度计算则遵循上面 2.1.2 中的规律。
<table style="width:200px; table-layout:fixed; background:darkkhaki; border:5px solid black" cellpadding="5" cellspacing="5"> <tr> <td style="width:20%; background:plum;"> <!--【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:40%; background:dodgerblue; padding-left:20px;"><!--【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:120%; background:crimson; padding-right:20px;"> <!--【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6 IE7 IE8 Opera | |
---|---|
Chrome Safari | |
Firefox |
三个列的宽度之和达到了180%,超出了TABLE自身宽度100%,且第三列【td3】的宽度已经超出了100%,这时各浏览器对于列宽分配出现的不同:
而对于各列的实际渲染宽度计算则同样遵循上面3.2.1.2中的规律。
针对 IE Opera 下的特殊情况,再看一组测试代码:
<table style="width:200px; table-layout:fixed; background:darkkhaki; border:5px solid black" cellpadding="5" cellspacing="5"> <tr> <td style="width:110%; background:plum;"> <!--【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:120%; background:dodgerblue; padding-left:20px;"> <!-- 【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:130%; background:crimson; padding-right:20px;"> <!-- 【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6 IE7 IE8 Opera | |
---|---|
Chrome Safari | |
Firefox |
可以看到,IE 和 Opera 中,【td1】宽度直接被裁切至100%,而其他两列宽度均变成了0。
2.2. 宽度设定为像素
在单元格无边框、边白、边距,各列宽度之和更好等于 TABLE 宽度时,各浏览器处理一致,下面讨论其中任何一个条件发生变化迫使浏览器对列宽重新计算时的情况。
2.2.1. 无边框、边白、边距,各列宽度之和小于 TABLE 宽度
<table style="width:200px; table-layout:fixed; background:darkkhaki;" cellpadding="0" cellspacing="0"> <tr> <td style="width:10px; background:plum;"> <!-- 【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:20px; background:dodgerblue;"> <!-- 【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:30px; background:crimson;"> <!-- 【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6 IE7(Q) IE8(Q) Opera | |
---|---|
IE7(S) | |
IE8(S) Firefox Chrome Safari |
各浏览器对于无边框、边白、边距,且各列宽度之和小于 TABLE 宽度时,均会对各列宽度进行调整,调整算法均为:该列宽度 / 各列宽度之和 * 表格宽度,即对于【td1】则是10px / 60px * 200px = 34px。
但此时 IE 对于 TD 元素内的 DIV 元素的宽度计算有差异,DIV 元素为 TD 元素内的唯一子元素,且没设置宽度,即 'width:auto',对块级元素来说其宽度应该撑满其父元素的内容区域的宽度:
下面只讨论宽度算法的差异,不再就 IE 中TD元素的特殊现象进行讨论。
2.2.2. 无边框、边白、边距,各列宽度之和大于TABLE宽度
<table style="width:200px; table-layout:fixed; background:darkkhaki;" cellpadding="0" cellspacing="0"> <tr> <td style="width:50px; background:plum;"><!--【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:100px; background:dodgerblue;"> <!-- 【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:150px; background:crimson;"> <!--【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
所有浏览器 |
---|
各浏览器结果一样,对于无边框、边白、边距,且各列宽度之和大于 TABLE 宽度时,不会对各列宽度进行调整,各列宽度维持其设置的宽度,TABLE 元素原有的设置宽度无效,表格被各列撑大。
2.2.3. 算法分类,列的宽度与边框、边白、单元格间距之和小于TABLE宽度
<style> td {border: 5px solid black;} </style> <table style="width:200px; table-layout:fixed; background:darkkhaki; border:5px solid black" cellpadding="5" cellspacing="5"> <tr> <td style="width:10px; background:plum;"> <!--【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:20px; background:dodgerblue; padding-left:20px;"> <--【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:30px; background:crimson; padding-right:20px;"> <!--【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6(S) IE7(S) IE8(S) Firefox Opera | |
---|---|
IE6(Q) IE7(Q) IE8(Q) Chrome Safari |
增加了单元格的border、边白、边距后,浏览器直接出现了宽度算法差异。
所以,TABLE 的可用宽度为200px - 2 * 5px - 4 * 5px = 170px,各列的宽度之和为10px + 20px + 30px + 5px + 5px + 20px + 5px + 5px + 20px + 5px + 5px + 5px + 5px + 5px + 5px = 150px,则【td1】的实际宽度为( 10px + 2 * 5px + 2 * 5px ) / 150px * 170px = 34px;【td2】的实际宽度为( 20px + 20px + 5px + 2 * 5px ) / 150px * 170px = 62px;【td3】的实际宽度为( 30px + 5px + 20px + 2 * 5px ) / 150px * 170px = 74px。
2.2.4. 列的宽度与边框、边白、单元格间距之和大于 TABLE 宽度
<style> td {border: 5px solid black;} </style> <table style="width:200px; table-layout:fixed; background:darkkhaki; border:5px solid black" cellpadding="5" cellspacing="5"> <tr> <td style="width:50px; background:plum;"> <!--【TD1】--> <div style="background:pink;">AAA</div> </td> <td style="width:80px; background:dodgerblue; padding-left:2px;"> <!--【TD2】--> <div style="background:lightblue;">BBB</div> </td> <td style="width:150px; background:crimson; padding-right:20px;"><!--【TD3】--> <div style="background:gold;">CCC</div> </td> </tr> </table>
这段代码在各浏览器环境中的表现如下:
IE6(S) IE7(S) IE8(S) Firefox Opera | |
---|---|
IE6(Q) IE7(Q) IE8(Q) Chrome Safari |
这种情况下,TABLE 出现了两种不同的宽度。
在 'table-layout:fixed' 这种固定布局算法下的表格中,可以为表格最后一列不设置宽度,尽量消除由算法差异带来的列的宽度差异。
如果内容溢出,可以为溢出的单元格设置 'overflow:hidden'。