你所不知道的表格

发布于 2017-07-31 21:24 阅读数 167

本文必须得到作者授权后,方可转载,摘要引流随意。
By 依韵 , From https://blog.cdswyda.com/post/2017073121

表格 table 出现的很久了,曾经作为风靡一时的布局神器,但随着css层叠样式的各种优势,表格布局基本都已经淡出人们的视线。目前表格基本上的作用就只有用作表格了。但是由于我们对表格了解甚少,在表格上其实是有不少坑的,下面就让我们一起来填填坑。

填坑进行时

单元格宽度无效

这个是非常常见的问题了,简单重现如下:

代码:

<style>
    #test1 td {
        border:1px solid #333;
    }
</style>
<table id="test1">
    <tr>
        <td width="50px">1</td>
        <td width="50px">2223232323232323</td>
        <td width="50px"></td>
        <td width="50px"></td>
    </tr>
    <tr>
        <td style="width:50px;">1</td>
        <td style="width:50px;">2223232323232323</td>
        <td style="width:50px;"></td>
        <td style="width:50px;"></td>
    </tr>
</table>

效果:

1 2223232323232323
1 2223232323232323

显而易见,无论是 w3c 已经不赞成使用的 html 标签上的 width 属性,还是以css形式指定的 width ,所指定的宽度在内容超出时都没有任何效果。

或许你会想到 overflow 这个属性,不过你可是试试,加上它也并没有什么效果。如何解决请看下文的 表格超宽 问题。

表格超宽

除了上面讲到的宽度无效之外,还有一个很常见的问题就是表格的宽度不受限制。

依旧代码说话:

<style>
    #test2 {
        width:400px;
    }
    #test2 td,
    #test2 th {
        border:1px solid #333;
    }
</style>
<table id="test2">
    <thead>
        <tr>
            <th style="width:50px;">序号</th>
            <th style="width:50px;">名称</th>
            <th style="width:300px">详情</th>            
        </tr>
    </thead>
    <tbody>
        <tr>
            <td style="width:50px;">1</td>
            <td style="width:50px;">测试</td>
            <td style="width:300px;"><img src="http://dummyimage.com/600x300" alt=""></td>
        </tr>
    </tbody>
</table>

效果如下:

序号 名称 详情
1 测试

如上代码所示,我们本是想表格宽度为400px,序号和名称各占50px,剩下的详情列宽度为300px。

而实际的效果可能非常令你失望,序号和名称列会被挤得非常窄,详情列的宽度也不是预想的300px,而是表格中当前列最宽的内容的宽度。

前两列被挤窄的也就罢了,你会发现表格的宽度也不是你所指定的 400px。(400px只是此处举例,通常的使用常为表格占容器宽度的100%,出现这种超宽的情况会使得表格超出容器。)

如果你遇到过这些,你肯定觉得表格很坑。

百度一搜这种问题很多,而且大多的答案都不能解决问题。多数答案基本是表格或是单元格宽度由内容决定,让你不要给表格设置宽度,而是给表格单元格内的内容设置宽度。

如单元格宽度无效时,可进行如下改造(本例类似):

代码:

<style>
    #test1 td {
        border: 1px solid #333;
    }
    .td-inner {
        width:50px;
    }
</style>
<table id="test1">
    <tr>
        <td>
            <div class="td-inner">1</div>
        </td>
        <td>
            <div class="td-inner">2223232323232323</div>
        </td>
        <td>
            <div class="td-inner"></div>
        </td>
        <td>
            <div class="td-inner"></div>
        </td>
    </tr>
</table>

效果

1
2223232323232323

从效果上看,确实达到了预期效果。可是这实际上是治标不治本的伪解决方案,其本质上根本没有解决表格单元和自身宽度无效的问题。

这个问题无解了吗?其实想想都不可能,表格曾经作为一种布局方案,如果存在这么大的坑,如何用来布局?

解决这个问题实际上只要知道一个表格的属性即可,它就是—— table-layout

table-layout 的属性值如下表:

描述
auto 默认。列宽度由单元格内容设定。
fixed 列宽由表格宽度和列宽度设定。
inherit 规定应该从父元素继承 table-layout 属性的值。

可以看出其默认形式就是自动布局,即由单元格中内容决定。想要我们在单元格或表格上的宽度上生效,只用给表格加上 table-layout:fixed;即可。

一行代码解决根本问题,而且可以避免无谓的嵌套多层html。

<style>
    #test3 {
        width:400px;
        table-layout: fixed;
    }
    #test3 td,
    #test3 th {
        border:1px solid #333;
    }
</style>
<table id="test3">
    <thead>
        <tr>
            <th style="width:50px;">序号</th>
            <th style="width:50px;">名称</th>
            <th style="width:300px">详情</th>            
        </tr>
    </thead>
    <tbody>
        <tr>
            <td style="width:50px;">1</td>
            <td style="width:50px;">测试</td>
            <td style="width:300px;"><img src="http://dummyimage.com/600x300" alt=""></td>
        </tr>
    </tbody>
</table>
序号 名称 详情
1 测试

关于 table-layout 的详细介绍如下:

定义和用法
tableLayout 属性用来显示表格单元格、行、列的算法规则。
固定表格布局:
固定表格布局与自动表格布局相比,允许浏览器更快地对表格进行布局。 在固定表格布局中,水平布局仅取决于表格宽度、列宽度、表格边框宽度、单元格间距,而与单元格的内容无关。 通过使用固定表格布局,用户代理在接收到第一行后就可以显示表格。
自动表格布局:
在自动表格布局中,列的宽度是由列单元格中没有折行的最宽的内容设定的。 此算法有时会较慢,这是由于它需要在确定最终的布局之前访问表格中所有的内容。

table相关的巧用

垂直居中

对需要垂直居中的元素加上 display:table-cell; 再配以 vertical-align: middle; 即可使得当前元素像表格中的单元格一样垂直居中。如下所示:

<style>
    .test3 {
        width:300px; 
        height: 300px; 
        border:1px solid #333;
        display: table;
    }
    .test3 > .vertical-middle {
        display: table-cell;
        text-align: center;
        vertical-align: middle;
    }
</style>
<div class="test3">
    <div class="vertical-middle">
        我能垂直居中
    </div>
</div>
<div class="test3">
    <div class="vertical-middle">
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中
        我能垂直居中            
    </div>
</div>

父容器的上设置的宽高度只是为了示意,为其他值依然能够做到垂直居中。

我能垂直居中
我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中 我能垂直居中

可以看到目标元素上存在 display: table-cell; 其父元素也只有 display: table; 他们之间并没有表格行(即display:table-row;)的存在,这实际上是因为表格存在 匿名表格元素创建规则 ,即

CSS2.1表格模型中的元素,可能不会全部包含在除HTML之外的文档语言中。这时,那些“丢失”的元素会被模拟出来,从而使得表格模型能够正常工作。所有的表格元素将会自动在自身周围生成所需的匿名table对象,使其符合table/inline-table、table-row、table- cell的三层嵌套关系。

此方式垂直居中优势:

  • 支持不定宽高的元素

不足:

  • 实际就是把当前元素变成了一个td,不能和绝对定位、浮动同时使用,margin 无效。

行等高布局

进行水平列表渲染的时候,可能的一种情况就是不同的列表条目有不同的高度。这时候如果使用浮动,则会存在问题,如:

<style>
    #test4 {
        width:300px;
    }
    #test4:after {
        clear: both;
        content: " ";
        display: table;
    }
    #test4>.t4-item {
        float: left;
    }
</style>
<div id="test4">
    <div class="t4-item"><img src="http://dummyimage.com/100x80" alt=""></div>
    <div class="t4-item"><img src="http://dummyimage.com/100x110" alt=""></div>
    <div class="t4-item"><img src="http://dummyimage.com/100x60" alt=""></div>
    <div class="t4-item"><img src="http://dummyimage.com/100x90" alt=""></div>
    <div class="t4-item"><img src="http://dummyimage.com/100x30" alt=""></div>
    <div class="t4-item"><img src="http://dummyimage.com/100x70" alt=""></div>
</div>

效果如下:

预想的情况应该是前三个一行,后面三个另起一行,直接使用浮动则会出现上面情况,第四个占据一行,后面两个又新起了一行。

仅使用浮动也可以实现等高布局,可以为每个浮动的元素设置一个最小高度,设置值为列表中最高的元素的高度。不过如果高度均无法确定,则仅用浮动无法实现等高布局。

而表格有一个特性就是每行的高度相同,因此等高的可以使用表格相关属性实现。如:

<style>
    #test5 >.row{
        display: table-row;
    }

    #test5 .t5-item {
        display: table-cell;
        vertical-align: top;
    }
</style>
<div id="test5">
    <div class="row">
        <div class="t5-item"><img src="http://dummyimage.com/100x80" alt=""></div>
        <div class="t5-item"><img src="http://dummyimage.com/100x110" alt=""></div>
        <div class="t5-item"><img src="http://dummyimage.com/100x60" alt=""></div>
    </div>
    <div class="row">
        <div class="t5-item"><img src="http://dummyimage.com/100x90" alt=""></div>
        <div class="t5-item"><img src="http://dummyimage.com/100x30" alt=""></div>
        <div class="t5-item"><img src="http://dummyimage.com/100x70" alt=""></div>
    </div>
</div>

效果:

虽然可以实现效果。但是也有局限性,必须新增一个辅助元素 .row

等宽布局

假设有一个水平列表,元素个个数不定,但是无论多少个,要使得列表元素评分容器控件。这时候使用 display:table-cell 。 就非常方便了。

<style>
    .test6 {
        display: table;
        width:500px;
        table-layout: fixed;
    }
    .test6>.t6_item {
        display: table-cell;
        background: #ccc;
        color:#000;
        text-align: center;
    }
</style>
<div class="test6">
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
</div>
<div class="test6">
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
</div>
<div class="test6">
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
    <div class="t6_item">等宽</div>
</div>
等宽
等宽
等宽
等宽
等宽
等宽
等宽
等宽
等宽
等宽
等宽

即无论列表有2个、3个6个还是任意个都能使得每个列表平均占据父容器宽度。

这实际是利用了表格中不给单元格指定宽度时,单元格宽度平均分配的特性。

两列布局

这种两列布局如何实现呢? 比较常用的是就是左侧绝对定位,右侧直接用margin-left 推动左侧占据的宽度即可。而实际上使用display: table-cell;来实现代码量更少。

代码:

<style>
    .test7 {
        width: 600px;
    }
    .test7:after {
        content: " ";
        display: table;
        clear: both;
    }
    .test7>.left {
        float: left;
        padding: 10px;
    }
    .test7>.right {
        display: table-cell;
        width: 2000em;
    }
    .r-content {
         word-break: break-all; 
    }
</style>
<div class="test7">
    <img src="http://dummyimage.com/100x100" alt="" class="left">
    <div class="right">
        <div class="r-content">sdfsjdfgjdsgfjsdgfjdsgjfgdsjfgdsjfgjdsgfjdsgfjdsgfhdsghfgdshfgdshfgdshfghdghsdgfhdsgfhsdgfhdsgfhdsgfhsdgfhdsgfhdsgfhdsgfhs
            7月30日,朱日和训练基地,中共中央总书记、国家主席、中央军委主席习近平检阅部队并发表重要讲话。   这是新中国成立后我军首次以庆祝建军节为主题的盛大阅兵,受阅官兵列阵沙场,以战斗姿态接受检阅。这场场面燃爆的沙场点兵,传递五个重大信号:
              第一,沙场点兵,展示的是中国军队的实战能力   在成吉思汗扬鞭跃马的古战场,一支现代化军队的沙场点兵如何更有气势?主要看战力!   虽然这次阅兵主题是庆祝建军节,但沙场特色非常浓厚:铁流滚滚,风尘仆仆。这次阅兵打破广场阅兵惯例,所有曲目都是播放录音,不安排军乐团、合唱队,也不搞群众性观摩。标兵不穿礼服而是穿迷彩服,就位方式也不是以往的踢正步,而是采用跑步形式,更添实战味。女兵以战斗员身份出现,多个方队集结机动也完全是实战化。值得注意的是,领导人也着野战军服。
            </div>
    </div>
</div>

效果

sdfsjdfgjdsgfjsdgfjdsgjfgdsjfgdsjfgjdsgfjdsgfjdsgfhdsghfgdshfgdshfgdshfghdghsdgfhdsgfhsdgfhdsgfhdsgfhsdgfhdsgfhdsgfhdsgfhs 7月30日,朱日和训练基地,中共中央总书记、国家主席、中央军委主席习近平检阅部队并发表重要讲话。   这是新中国成立后我军首次以庆祝建军节为主题的盛大阅兵,受阅官兵列阵沙场,以战斗姿态接受检阅。这场场面燃爆的沙场点兵,传递五个重大信号:   第一,沙场点兵,展示的是中国军队的实战能力   在成吉思汗扬鞭跃马的古战场,一支现代化军队的沙场点兵如何更有气势?主要看战力!   虽然这次阅兵主题是庆祝建军节,但沙场特色非常浓厚:铁流滚滚,风尘仆仆。这次阅兵打破广场阅兵惯例,所有曲目都是播放录音,不安排军乐团、合唱队,也不搞群众性观摩。标兵不穿礼服而是穿迷彩服,就位方式也不是以往的踢正步,而是采用跑步形式,更添实战味。女兵以战斗员身份出现,多个方队集结机动也完全是实战化。值得注意的是,领导人也着野战军服。

如果你觉得什么东西坑比较多,那是因为你不了解它,学起来吧!


Comments
Write a Comment