zoukankan      html  css  js  c++  java
  • HTML布局四剑客-Flex,Grid,Table,Float

    前言

    在HTML布局中有很多的选择,同一种表现方式可以使用不同的方法来实现.下面来对四种最常见的布局方式进行阐述和解释,它们分别是Float,Table,Grid和Flex

    Float

    第一位出场的就是最年老的Float,"老骥伏枥,志在千里".作为最早出现的定位方式,为元素赋予了"浮动显示"的技能,从此,元素可以不跟着文档的方向随波逐流,而可以拥有自己的"浮动方向",可以说是CSS里面最常出现的熟人了.

    float不仅仅出现在网页上,事实上它借鉴了印刷行业的特性,参见下图

    图片下方有文字,此时的图片就是浮动的,可以想象整个文档流就是一条河,图片是一条船,文字是水上漂浮的花瓣,当这艘船放在水里的时候,花瓣是会围绕在这艘船而不会被这艘船压在下边,因为都是"浮动"的.

    如上图所示,当头像被设置为浮动的时候,介绍的文字是根据头像大小"可响应"(responsive)的,如果设置为非浮动,也就是绝对定位,当头像变大了之后,文字便会被遮盖,就像花瓣感知不到船的存在一样.

    如果float只能用于图片文字的排版那就太小看它了,float可以很轻松的实现整个页面的布局

    float有四种可选值:

      1 none(default):没有浮动

      2 left:向左浮动

      3 right:向右浮动

      4 inherit:继承祖上的浮动方式.

      还有一个孪生的属性clear,用于清除float的属性.

    如上图所示,当SideBar不足以占满右边所有内容的时候,Footer便会浮动到图示的位置,但是Footer并不想这样放在内容的右边,它向单独向下另起一行,如果将其clear属性设置为both,就可以满足他的心愿.

    clear还有别的选择吗?当然有,跟float一样,有四种选择以上的both是清除左右浮动,自成一行,还有清除  左浮动(left),  右浮动(right),  移除clear属性(none:该值为默认值),其实还有一个inherit:继承,IE不兼容该属性(在IE11上进行测试依然不兼容).

    如果父元素只包含属性为float的子元素,那么该父元素的的高度将会为0,这时候需要使用到clear

    方法1 将文字元素设为block

    这样可以避免父元素的高度为0的尴尬,但是,为每个文本设置块太"贵"了,并且还需要调整两个文本间的margin来使段落看起来间隔自然

    方法2 在浮动子元素之后,在父元素闭合标签之前清除浮动属性.

      1 添加一个空div

    <div class="container">
      <image src="http://via.placeholder.com/350x150"></image>
      <image src="http://via.placeholder.com/150x100"><image>
      <div class="clearfloat"></div>
    </div>

      将其属性设置为clear:both

    img {
      float:left;
    }
    .container {
      width:500px;
    }
    .clearfloat {
      clear:both;
    }

      最后可以看到container已经有了宽高,为子元素宽高的和

    2 使用:after伪类选择器

    <div class="container">
      <image src="http://via.placeholder.com/350x150"></image>
      <image src="http://via.placeholder.com/150x100"><image>
    </div>
    img {
      float:left;
    }
    .container {
      width:500px;
    }
    .container:after {
      content:'.';
      visibility:hidden;
      display:block;
      height:0;
      clear:both;
    }

     3 使用overflow属性

    描述
    visible 默认值。内容不会被修剪,会呈现在元素框之外。
    hidden 内容会被修剪,并且其余内容是不可见的。
    scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
    auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
    inherit 规定应该从父元素继承 overflow 属性的值。

    在使用的时候需注意,虽然overflow不需要引入新的空标签,但是会出现子元素内容被裁减或显示滚动条.

    结果是父元素有了宽高,高是子元素高的和,但是宽是继承来的宽(如果没有显式设置width,默认为100%)

    <div class="container">
      <img src="http://via.placeholder.com/350x150"></img>
      <img src="http://via.placeholder.com/150x100"></img>
    </div>
    img {
      float:left;
    }
    .container {
      overflow: hidden;
    }

    如果想让浮动元素进行分组有什么办法呢?比如将下列不同颜色的分为一组

    方法1 在需要分割元素后添加一个空元素,然后清除float属性

    img {
      float:left;
    }
    .container {
      overflow: hidden;
    }
    .clearfloat {
      clear:both;
    }

    方法2 将同一个颜色的包裹在同一个group中,清除group的浮动的属性

    img {
      float:left;
    }
    .container {
      overflow: hidden;
    }
    .group {
      clear:both
    }

    在使用float属性的时候有一些bug传说:

      1 overflow:如果图片超出浮动容器,会影响其他浮动容器的浮动布局.在IE11上进行了测试,已修复,会将Image裁切到容器宽度

      2 双边距,在具有浮动属性的元素设置margin,值会翻倍,在IE11已修复.

      3 3px Jog:text与具有浮动属性的元素之间有3px的左间隔 在IE7被修复

     

      4 底边距bug 父元素会无视子元素的margin-bottom属性,IE11已修复

     

    * 参考网址及截图来源CSS Tricks

    Table

    Structure:

    表结构: <thead><tfoot><tbody>

      thead和tfoot(如果有)需要尽早的列在前面,而不是将tfoot放在table标签的末尾,这么做的理由是让table的结构一目了然.tbody就是表数据内容.

    单元格:<th> --> tabular headers  <td> --> tabular data <tr> -->table row 

      <th>虽然有header,但是完全不影响它的位置,可以放在表结构的任何地方,只要你认为这个单元格重要到可以成为"头".比如这样:

      附属物: <caption> <col>一个没有内容,定义列属性的标签(对齐align valign,宽度,颜色等) <colgroup> 列集合,跟<col>联合使用的定义表格的展现方式

      <col>和<colgroup>必须在<caption>之后,任意的表结构或<tr>之前定义好.不过该属性在HTML5中已经不支持了.

    <colgroup>
      <col span="2" style="background-color:red">
      <col style="background-color:yellow">
    </colgroup>

      以上代码的意义是该列表集合由两部分组成,前两列的背景颜色为红色,后一列的颜色为黄色

    Style:

    默认表中每一行都有2px的间隔:

    collapse属性去除间隔

    table {
      border-collapse: collapse;
    }

    "合并单元格"是excel中很常见的操作,那么在table布局中如何实现呢?

     <th colspan="2"> 表示占两列 <td rowspan="2"> 表示占两行,结合这两个属性就可以实现需要的布局.

    可以将其拆分成以下的元素(colspan,rowspan)进行设置

    表格的宽度有三种情况,

    1 表格宽度为内容宽度 (内容宽度小于容器宽度)

    2 刚好占满整个容器 (内容宽度等于容器宽度)

    3 超出容器大小 (内容宽度大于容器宽度)

    使用 white-space:nowrap 设置文字超过容器大小后是否换行(默认换行)

    Table的用武之地:

    需要表格化展示数据的时候(tables are for tabular data),常见的有:日程表,价格表,属性表,得分表,员工表,财务数据,日历,营养表.

    但是 将Table用于布局是不符合语义的,是一种hack的方法

      1 HTML标签必须有意义,就像之前说的,table只能用于表格化展示数据.

      2 确保网站的可访问性,其中一个便是屏幕阅读,屏幕阅读是从左往右,从上到下,意味着整个网站变成了视觉上的支配而不是可访问性的支配.而且还会宣布表格的开始,比不用更糟糕

      3 源代码的顺序依赖, 为了实现Table布局,会在更重要的内容之前声明Table,导致SEO的情况并不好.

    再一次但是有时候还是会使用Table来布局,比如HTML Email,他需要在各种的设备上运行,包括老旧的设备,一些更现代的布局方式会造成兼容性的问题,通过表格被视为最安全的方式.

    Tables are for and only for tabular data

    扩展:还有一个table的崇拜者模仿table的表现方式 

    display: table                /* <table>     */
    display: table-cell           /* <td>        */
    display: table-row            /* <tr>        */
    display: table-column         /* <col>       */
    display: table-column-group   /* <colgroup>  */
    display: table-footer-group   /* <tfoot>     */
    display: table-header-group   /* <thead>     */

    注意,没有<th>的替代,且以上都是语义值,并不是实际的标签

    Flex

    这是我研究最多的布局方式,真是特别的灵活,可以很快速的设置我想要的方式,而且自适应也做的比较好,响应式布局也能用它来实现,不得不说是四剑客当中实力很强的选手了.

    Characteristics:

      1 可以从任何方向布局-->flow direction,包括leftwards,rightwards,downwards, upwards(请注意,只能选择一个方向)

      2 可以重建视觉顺序(visual order)而不影响文档中的顺序, 包括 Reverse: row-reverse, column-reverse Rearrangement: order属性,这样的好处是可以保持网页的可读性(accessibility).

      3 两种方式布局 1 线性的(no-wrap),只有一条主轴(main axis) 2 折叠换行的(wrapped),包括主轴和交叉轴(cross axis)

      4 弹性的size,可以充分利用剩余空间

      5 能够分别设置主轴和副轴的对齐方式

      6 在保留副轴的情况下在主轴下动态的折叠或展开

    Concept:

      最核心的就是下面这一张图,可以将flex的规则包括80%.(图片来自W3C Candidate Recommendation)

      在container上设置 dispaly: flex; ,那么所有属于他的items(所有的in-flow children elements)都会按照相同的高度进行flex布局.

     Container

      1 display: flex或者inline-flex 设置为"块"级还是行内级容器,需要注意的是,这里的"块"只针对container,至于它的item只是flex-level,不是block不能设置以下属性(设置了无效):

        1 float和clear

        2 vertical-align,可以用align-self代替

        3 ::first-line和::first-letter伪类选择器,flex布局没有第一行或第一个letter的概念

      2 flex-flow:包含1 flex-direction: row | row-reverse | column | column-reverse , flex-wrap: nowrap | wrap | wrap-reverse

      3 justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly

      这里重点说一下space-between,space-around和space-evenly.一张图表示(修改自 CSS-Tricks)

      4 align-items: flex-start | flex-end | center | baseline | stretch

        跟justify-content的对齐是相对的,前者对应猪猪,此对应副轴,这里有一个baseline的概念,先按下不表

      5 align-content: flex-start | flex-end | center | space-between | space-around | stretch;

        如果有多行(flex-wrap设置为wrap时)每一行的对齐方式,如果只有一行则失效

    Item:

    item就是弹性容器内容的内容流,只要在流里(in-flow)的都是item,都能受flex控制

    1 flex:包括三个属性,每个属性都值得一讲

      1 flex-grow: 如果一行之后还有剩余空间,那么会按照每个item设置的grow进行扩展,此属性无单位,表示所占的权重,如果三个item设置的flex-grow均为1,1,1且未wrap,也没有其他item了,那么每一个会在除开自己的宽度之后的剩余空间每个占1/3.默认为0

      2 flex-shrink: 在必要时收缩,默认为1,可以缩小至最小值

      3 flex-basis: grow和shrink之前的基础值,默认为auto<length> | auto

    以上三个属性不要分开用,因为会有部分属性未设置的隐患,使用flex:统一设置,未设置的为默认值.

    flex基本值有4个:

    四个基本值
    flex:initial flex:0 1 auto
    flex:auto  flex:1 1 auto
    flex:none flex:0 0 auto
    flex:一个正值 flex:正值 1 0

     2 align-self: 表示对齐方式,跟在container上设置align-items是一样的, auto | flex-start | flex-end | center | baseline | stretch

     3 order: 表示显示的顺序,可以在不改变文档书写顺序的情况下改变视觉呈现顺序,使页面具有更好的"可访问性"(Accessible),默认值为0 可以为负值.

    到目前为止所有的属性已经介绍完了,下面补充一点与flex有关的知识

    1 什么是匿名item?

    <div style="display:flex">
    
        <!-- flex item: block child -->
        <div id="item1">block</div>
    
        <!-- flex item: floated element; floating is ignored -->
        <div id="item2" style="float: left;">float</div>
    
        <!-- flex item: anonymous block box around inline content -->
        anonymous item 3
    
        <!-- flex item: inline child -->
        <span>
            item 4
            <!-- flex items do not split around blocks -->
            <q style="display: block" id=not-an-item>item 4</q>
            item 4
        </span>
    </div>

    注意打引号的item4,它是一个"block",flex布局不会在block进行item的拆分(不属于item了),所以"item4"换了行,如果不是"block"的话,"item 4"会接着在第一个item 4右面出现.

    2 flex布局是如何确定宽度和高度的?( Line Length Determination )

      1 definite size: 定义为不根据所在的布局而改变的size值,例如显式设置height和100px.

      2 max(min):最大最小内容约束,这也是item使用grow和shrink的基础.

      3 如果都没有的话,除去container的margin,padding,border后的值为可用的值(这个值可能是无限大的"infinite",比如高度)

    3 container的baseline基线是什么东西?

    在之前讲align-items对齐方式的时候讲过baseline,定义为:

      1如果有多行flex lines,那么baseline就是多个lines共享的集合

      2 如果container只有一行,包含超过一个item,首尾item中定义了对齐方式,默认是content,text为字的底边的方式对齐

    Grid

    /**
     * 定义grid item空间(space)
     */
    #grid {
      /**
       * 两列
       *  1. 第一列宽度为内容的大小
       *  2. 第二列占据剩下的空间
       *
       * 三行
       *  3. 第一行高度为内容大小
       *  4. 中间行占据剩下的空间
       *  5. 最后一行高度为内容大小
       */
      display: grid;
      grid-template-columns:
        /* 1 */ auto
        /* 2 这个1fr是不是很像flex布局中的flex-grow?*/ 1fr;
      grid-template-rows:
        /* 3 */ auto
        /* 4 */ 1fr
        /* 5 */ auto;
    }
    
    /* 定义每个grid item所在的位置
     */
    #title    { grid-column: 1; grid-row: 1; }
    #score    { grid-column: 1; grid-row: 3; }
    #stats    { grid-column: 1; grid-row: 2; align-self: start; }
    #board    { grid-column: 2; grid-row: 1 / span 2; }
    #controls { grid-column: 2; grid-row: 3; justify-self: center; }

     HTML代码

    <div id="grid">
      <div id="title">Game Title</div>
      <div id="score">Score</div>
      <div id="stats">Stats</div>
      <div id="board">Board</div>
      <div id="controls">Controls</div>
    </div>

     结果示意图:图片来自W3C Candidate Recommendation

     

    表格布局就是将内容变成表格一样的东西,二维,包含水平和垂直(可以与flex中的main,cross对应理解)

    Characteristics:

    1 固定的,灵活的和基于内容的追踪size功能

    2 使用正(向前),负(向后)的坐标值来显式设置item位置.

    3 自动放置项目到空白区域(包括重新排序时)

    4 空间敏感的重复跟踪(track),自动添加行列适应内容

    5 通过margin,gutter(row&column gap),对齐属性控制spacing和alignment

    Concept:

    1 block axis 列所(column axis)在的line1,2,3就是在block axis上

    2 in-line axis 行(row axis)所在的1,2,3,4就是在in-line axis上

    3 grid line,水平和垂直分割线,上图中的line1,2,3,4和line1,2,3,索引值自动生成,可以在grid item中进行引用,定位.下例表示占据H(右)B空间的item1

    用line(线)的概念而不是row和column

    #item1 { grid-column: 2; /*从列的line2到line3(默认占据一个单位)*/
             grid-row-start: 1; grid-row-end: 2; } /*从行的line1到line2*/

    named line:可以通过设置[item-start][item-end]来进行与上例相同的定位,但是需要在container中进行对应的修改

    #grid {
      display: grid;
      grid-template-columns: 150px [item1-start] 1fr [item1-end];
      grid-template-rows: [item1-start] 50px 1fr 50px [item1-end];
    }
    
    #item1 {
      grid-column: item1-start / item1-end;
      grid-row: item1-start / item1-end;
    }

    4 grid track:相邻grid lines之间的距离,每一个grid track会交给一个sizing函数,会计算出行列的宽高.邻近的grid track会被gutter(column&row gap)打断.

    5 grid cell:grid item能引用的最小单位(单元格)

    6 grid-area是一个逻辑空间(如上例的HHABFF),用来存放一个或多个items的.但是必须是连续的,只能用4条lines来划出这个area,可以在grid container的grid-template-area中显式命名,也可以隐式的与line的值绑定,grid item通过grid-property(grid-area)属性来将item放到对应的area中

    #item1 { grid-area: A }
    #item2 { grid-area: B;align-self: start;}
    #item3 { grid-area: B;justify-self:end;align-self:end}

      item1放入A中,item2和item3都放入B中,两者根据不同的align和justify位置有所区分.

    Grid Container:

    main {
      grid: "H    H " 50px
            "A    B " 1fr
            "F    F " 50px
      /     150px 1fr;
    }

     

    这是最简洁和形象的方式,上图表示了三行两列区域名分别为ABHF的内容,第一列150px,第二列占据剩余空间,第一行和第三行分别为50px,第二行占据剩余空间.(fr: fraction 分数)

    1 display:跟flex一样,有grid和inline-grid的区分,以及item不能使用的属性也跟flex item一致

    2 grid-template-columns, grid-template-rows

    grid-template-columns: 100px 1fr max-content minmax(min-content, 1fr) repeat(2, 1fr);
    
    /* 5条lines创建了,
    * 1 起始位置
    * 2 距离起始位置宽度为100px
    * 3 距离第二条line1/4剩余宽度
    * 4 距离第三条最大item宽度
    * 5 距离第四条不小于最小item宽度,不大于1/4剩余宽度
    * 6 距离第五条分别为1/4,1/2的两条lines * 为了避免超出container的宽度,最好在item中设置弹性值,比如fr.
    * 也可根据上面提到的named line来自定义lines名称创建行列
    */

    有一个神奇的clamp a grid area:当grid-area部分超过了grid的限制,那么span会被压缩到最后一个line,如果全部都超过了,那么会在已有的限制上加1,并都压缩至那个1中

    /**如果grid只支持1000个tracks/
    .grid-item {
      grid-row: 500 / 1500;/*部分超出*/
      grid-column: 2000 / 3000;/*全部超出*/
    }
    /*保留未超过部分,将超过的部分加1;如果全部超过,则都压缩至最后一个1中*/
    .grid-item {
      grid-row: 500 / 1001;
      grid-column: 1000/1001  
    }

     3 grid-template-area: 将自定义命名的item按顺序放置

    #grid {
      display: grid;
      grid-template-areas:
                 "head head"
                 "nav  main"
                 "foot ...."
    }
    #grid > header { grid-area: head; }
    #grid > nav    { grid-area: nav; }
    #grid > main   { grid-area: main; }
    #grid > footer { grid-area: foot; }                

    4 grid-template将2,3均包括

    grid-template: auto 1fr / auto 1fr auto;/*设置了row和column,template-area为none*/
    grid-template: [header-top] "a   a   a"     [header-bottom]
                   [main-top] "b   b   b" 1fr [main-bottom]
                   / auto 1fr auto;

     上面代码的结果为:(图片来自W3C Candidate Recommendation)

    5 在grid-column&row属性中还有一个比较重要的就是grid-auto-column&row,设置隐式的大小

      #grid {
      /*template只包含了一行一列,超出的部分则按照auto来设置大小*/
        display: grid;
        grid-template-columns: 20px;
        grid-auto-columns: 40px;
        grid-template-rows: 20px;
        grid-auto-rows: 40px;
      }
      #A { grid-column: 1; grid-row: 1; }
      #B { grid-column: 2; grid-row: 1; }
      #C { grid-column: 1; grid-row: 2; }
      #D { grid-column: 2; grid-row: 2; }

     图片来自(W3C Candidate Recommendation)

    6 grid-auto-flow:定义自动的流向,[ row | column ] || dense

    row和column就是定义那个方向自动"流",dense代表密集排布,即如果后面的item足够小能够将前面留下的空白(hole)给补上,那么会将后面的item提到前面,实现密集型排布(可能会影响顺序),如果不设置,默认为sparse,稀疏排布.

    grid: grid-template | grid-template-rows / [auto-flow &&dense?] grid-auto-column | [auto-flow &&dense?] grid-auto-rows / grid-template-columns, 尽量使用grid而不是分别使用各自的属性.

    grid: auto-flow 1fr / 100px;
    /*相当于*/
    grid-template: none / 100px;
    grid-auto-flow: row;
    grid-auto-rows: 1fr;
    grid-auto-columns: auto;

     8 间距和对齐: 对齐属性包括align-items justify-content align-content都跟flex一样.间距属性: row-gap|column-gap|gap,当然在对齐中的 space-around|space-between|space-evenly对gap有影响.

    Grid-Item

    1 grid-placement-priorities: 要注意这里line(线的概念)

    .one {
      grid-area: main;/*命名main,放在container定义的template对应位置*/;
    }
    .two {
      grid-column: 2;
      grid-row: 3; /*相当于grid-area: 3/2 放在行3列2的位置,默认span为1*/ 
    }
    .three {
      grid-row: 2 / span 5;/*从第二行开始span5行到第七行结束*/
    }
    .four {
      grid-row: span 5 / 7;/*跨5行,到第七行为止(可以推导出从第二行开始)*/
    }
    .five {
      grid-column: first / middle;/*从first列到middle列*/
    }
    .six {
      grid-area: auto;/*自动布局*/
    }
    .seven {
      grid-area:span 3/ span 2;/*跨3行2列,这是隐式的自动布局,受container的grid-auto-flow控制*/
    }

      有一个绝对定位值得一提,在container中设置了position:relative,那么在item中使用position:absolute,可以对在所占的grid-area中进行绝对定位:

    .abspos {
      grid-row-start: 1;    
      grid-row-end: span 2;  
      grid-column-start: 3; 
      grid-column-end: auto; /* 直到最右边的line即5th line */
      position: absolute;/*设置absolute*/
      /*设置相对定位*/
      top: 70px;
      bottom: 40px;
      left: 100px;
      right: 30px;
    }

    2 对齐: column轴:align-self(相当于container中的align-items)跟flex布局的概念一样

    Grid和Flex的联系:

    看到这两者之间有很多共同的属性(名字都一模一样),其实,Grid是为了更好的使用Flex,Flex只能在一个方向上具有弹性,row或者column但是Grid可以在row和column上都具有弹性.两者结合起来就可以实现任何方向任何颗粒度的弹性化.比如,想要设置整个Grid的背景图为拉伸的,但是所有的item垂直居中,那么可以这样来实现:

    .grid {
      align-items: stretch;
    }
    .griditem {
      display: flex;
      align-items: center;
    }

     Grid做layout,Flex做component

  • 相关阅读:
    inflate用一个XML源填充view. LayoutInflater
    关于inflate的第3个参数
    关于inflate的第3个参数
    android ImageView scaleType属性
    android ImageView scaleType属性
    Android中设置文本颜色的三种方法
    JDK1.8与spring3.x的不兼容
    Spring整合activiti单元测试
    良好编程习惯的养成
    No output operations registered, so nothing to execute
  • 原文地址:https://www.cnblogs.com/BigJ/p/layouts.html
Copyright © 2011-2022 走看看