HaPBoy's Notes


  • 首页

  • 归档

CSS 两栏布局方法总结

发表于 2017-12-02 |

CSS 布局是前端开发的一个重要内容,在 CSS2.1 之前没有出现真正意义上的布局属性,直到 CSS3 才出现了如 Flex、Grid 等布局属性。本文总结了目前主流的两栏布局方法。

注意:本文中涉及 float 的布局均未对父元素进行清除浮动,在实际使用中需要在父容器清除浮动。(本文不讨论清除浮动的方法)

两栏布局

绝对定位法 absolute + margin

HTML

1
2
3
4
5
6
<div class="hd">Header</div>
<div class="bd">
<div class="aside">侧边栏 固定宽度</div>
<div class="main">主内容栏 自适应宽度</div>
</div>
<div class="ft">Footer</div>

CSS

1
2
3
4
5
6
7
8
9
.aside {
position: absolute;
top: 0;
left: 0;
width: 200px;
}
.main {
margin-left: 210px; /* 10px 列间隙 */
}

DEMO1:绝对定位法 absolute + margin 两栏布局

特点:1. 在不修改 HTML 的情况下,只需要修改 CSS 即可支持任意调整列顺序。2. 支持主内容优先显示,只需将主内容的 HTML 放置在前即可。
缺陷:绝对定位 absoulte 是定位流,会脱离常规流,不影响上下文排版,无法撑开父元素高度。
结论:在内容量不可控的场景,不推荐使用该方式。

浮动法 float + margin

HTML

1
2
3
4
5
6
<div class="hd">Header</div>
<div class="bd clearfix">
<div class="aside">侧边栏 固定宽度</div>
<div class="main">主内容栏 自适应宽度</div>
</div>
<div class="ft">Footer</div>

CSS

1
2
3
4
5
6
7
.aside {
float: left;
width: 200px;
}
.main {
margin-left: 210px; /* 10px 列间隙 */
}

DEMO2:浮动法 float + margin 两栏布局

特点:1. 在不修改 HTML 的情况下,只需要修改 CSS 即可支持任意调整列顺序。
缺陷:1. 不支持主内容优先显示。2. 不兼容IE6,.main 内部第一个元素存在清除浮动时,会发生 .main 掉下去的情况。3. .main 中存在清除浮动 clear: both 属性,样式会出错,DEMO3:浮动法 float + margin 两栏布局 clear: both BUG。
结论:若主内容栏包含需要清除浮动之类的元素,不适合使用该方式。

浮动法改进版一 float + margin + wrap 双标签

HTML

1
2
3
4
5
6
7
8
<div class="hd">Header</div>
<div class="bd clearfix">
<div class="aside">侧边栏 固定宽度</div>
<div class="main-wrap">
<div class="main">主内容栏 自适应宽度</div>
</div>
</div>
<div class="ft">Footer</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
.aside {
float: left;
width: 200px;
position: relative; /* 提升侧边栏层级 */
}
.main-wrap {
float: right;
width: 100%;
margin-left: -200px;
}
.main {
margin-left: 210px; /* 10px 列间隙 */
}

DEMO4:浮动法改进版一 float + margin + wrap 双标签 两栏布局

特点:1. 在不修改 HTML 的情况下,只需要修改 CSS 即可支持任意调整列顺序。2. 支持主内容优先显示,只需将主内容的 HTML 放置在前即可。3.兼容性好,兼容所有浏览器。
缺陷:结构增加,样式复杂。
结论:推荐使用该方法,除了结构复杂没有其他明显缺陷。

浮动法改进版二 float + overflow

HTML

1
2
3
4
5
6
<div class="hd">Header</div>
<div class="bd clearfix">
<div class="aside">侧边栏 固定宽度</div>
<div class="main">主内容栏 自适应宽度</div>
</div>
<div class="ft">Footer</div>

CSS

1
2
3
4
5
6
7
8
9
.aside {
float: left;
width: 200px;
margin-right: 10px; /* 10px 列间隙 */
}
.main {
overflow: hidden; /* 触发BFC */
*zoom: 1; /* IE6 使用 zoom: 1 触发 hasLayout */
}

DEMO5:浮动法改进版二 float + overflow 两栏布局

特点:1. 在不修改 HTML 的情况下,只需要修改 CSS 即可支持任意调整列顺序。2. 设置简单,基于 BFC。
缺陷:1. 不支持主内容优先显示。2. overflow: hidden 会影响主内容栏滚动条。

弹性盒子法 Flexbox 布局

HTML

1
2
3
4
5
6
<div class="hd">Header</div>
<div class="bd">
<div class="aside">侧边栏 固定宽度</div>
<div class="main">主内容栏 自适应宽度</div>
</div>
<div class="ft">Footer</div>

CSS

1
2
3
4
5
6
7
8
9
10
.bd {
display: flex;
}
.aside {
width: 200px;
margin-right: 10px; /* 10px 列间隙 */
}
.main {
flex: 1; /* 展开适应宽度 */
}

DEMO6:弹性盒子法 Flexbox 布局 两栏布局

特点:1. 在不修改 HTML 的情况下,只需要修改 CSS 即可支持任意调整列顺序(使用 order 属性)。2. 支持主内容优先显示,只需将主内容的 HTML 放置在前即可。
缺陷:不兼容 IE < 11
结论:推荐使用该方法,除了对IE兼容性较差外没有其他明显缺陷。

总结

以上为目前主流的两栏布局方法,在不需要兼容 IE < 11 的情况下,推荐使用 弹性盒子法 Flexbox 布局 方法,其次推荐 浮动法改进版一 float + margin + wrap 双标签 方法。

参考文献

margin系列之布局篇 - CSS探索之旅
CSS多列布局 - 三省吾身丶丶

CSS3 Flexbox 知识点整理

发表于 2017-09-12 |

这段时间经常用到 Flexbox 弹性盒模型,十分简洁好用,不需要 float, position 等属性即可完成复杂的页面布局。若无需兼容 IE 或只在移动端开发,推荐使用 Flex 布局。

Flexbox 布局

Flexbox 是一种布置元素的布局模式,适应不同的屏幕尺寸,弹性盒子模型是对块模型的改进,flex容器的边缘也不会与其内容的边缘折叠。

Flex 容器默认存在两条轴,分别是水平主轴(main axis) 和 垂直的交叉轴(或侧轴)(cross axis),可以通过修改 flex-direction 来改变主轴和交叉轴。

Flex 容器(Flex container): 包含着弹性项目的父元素。通过设置 display: flex | inline-flex 定义弹性容器。

1
2
3
.container {
display: flex | inline-flex;
}

Flex 容器的 6 个属性

  1. flex-direction 确立主轴。

    1
    2
    3
    .container {
    flex-direction: row | row-reverse | column | column-reverse; // 默认值 row
    }

    row/row-reverse: 水平方向从左到右/从右到左
    column/column-reverse: 垂直方向从上到下/从下到上

  2. flex-wrap 控制侧轴的方向和新行排列的方向,即弹性项目单行、多行排布。

    1
    2
    3
    .container {
    flex-wrap: nowrap | wrap | wrap-reverse; // 默认值 nowrap
    }

    nowrap(默认值): 不换行
    wrap/wrap-reverse: 项目主轴总尺寸超出容器时换行,第一行在上方/换行,第一行在下方

  3. flex-flow 是 flex-direction 和 flex-wrap 的简写,决定弹性项目如何排布。

    1
    2
    3
    .container {
    flex-flow: <flex-direction> || <flex-wrap>; // 默认值 row nowrap
    }
  4. justify-content 定义弹性项目沿主轴如何排布。

    1
    2
    3
    .container {
    justify-content: flex-start | flex-end | center | space-between | space-around; // 默认值 flex-start
    }

    flex-start(默认值): 向主轴起始位置靠齐; flex-end: 向主轴结束位置靠齐; center: 向主轴中间位置靠齐;
    space-between: 两端对齐,项目之间等距;
    space-around: 每个项目两侧的间隔相等,项目之间的间隔比项目与边缘的间隔大一倍.

  5. align-items 定义弹性项目沿侧轴如何排布。

    1
    2
    3
    .container {
    align-items: flex-start | flex-end | center | baseline | stretch; // 默认值 stretch
    }

    stretch(默认值): 项目未设置高(宽)度或者设为 auto,将在侧轴拉伸填充整个容器;
    flex-start: 向侧轴起始位置靠齐; flex-end: 向侧轴结束位置靠齐; center: 向侧轴中间位置靠齐;
    baseline: 根据项目的基线对齐.

  6. align-content 定义多个侧轴的空间分配方式,只有一根侧轴不起作用。

    1
    2
    3
    .container {
    align-content: flex-start | flex-end | center | space-between | space-around | stretch; // 默认值 stretch
    }

    stretch(默认值): 项目未设置高(宽)度或者设为 auto,将在侧轴拉伸填充整个容器;
    flex-start: 向侧轴起始位置靠齐; flex-end: 向侧轴结束位置靠齐; center: 向侧轴中间位置靠齐;
    space-between: 两端对齐,项目之间等距;
    space-around: 每个项目两侧的间隔相等,项目之间的间隔比项目与边缘的间隔大一倍.

Flex 项目的 6 个属性

  1. order 规定了弹性容器中的可伸缩项目在布局时的顺序,数值越小,排列越靠前,默认值为 0。

    1
    2
    3
    .item {
    order: <integer>; // 默认值 0
    }
  2. flex-basis 伸缩基础,在进行计算剩余空间或超出空间前,给伸缩项目重新设置一个宽度,然后再计算。

    1
    2
    3
    .item {
    flex-basis: <length> | auto; // 默认值 auto
    }
  3. flex-grow 当伸缩项目在主轴方向的总宽度 < 伸缩容器,伸缩项目根据扩展因素分配伸缩容器的剩余空间。

    1
    2
    3
    .item {
    flex-grow: <number>; // 默认值 0,即存在剩余空间不放大
    }
  4. flex-shrink 当伸缩项目在主轴方向的总宽度 > 伸缩容器,伸缩项目根据缩小因素分配总宽度超出伸缩容器的空间。

    1
    2
    3
    .item {
    flex-shrink: <number>; // 默认值 1,即如果空间不足,该项目将缩小,负值对该属性无效。
    }
  5. flex flex-grow, flex-shrink 和 flex-basis 的简写

    1
    2
    3
    .item {
    flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
    }

    initial(默认值): flex: 0 1 auto 即 flex-grow: 0; flex-shrink: 1; flex-basis: auto;
    none: flex: 0 0 auto 元素会根据自身宽高来设置尺寸。它是完全非弹性的:既不会缩短,也不会伸长来适应 flex 容器;
    auto: flex: 1 1 auto;
    <number>: flex: number 1 0%;
    <width>: flex: 1 1 width 例如 flex: 0% => flex: 1 1 0%, flex: 10px => flex: 1 1 10px.

    拉伸后弹性项目宽度计算

    弹性项目扩展宽度 = (容器宽度 - 项目宽度或项目设置的 flex-basis 总和) * 对应的 flex-grow 比例
    拉伸后弹性项目宽度 = 原弹性项目宽度 + 扩展宽度

    压缩后弹性项目宽度计算

    弹性项目缩小宽度 = (项目宽度或项目设置的 flex-basis 总和 - 容器宽度) *(对应的 flex-shrink 项目宽度或项目设置的 flex-basis 加权比例)
    压缩后弹性项目宽度 = 原弹性项目宽度 - 缩小宽度

    注意:使用缩写属性会留下一些陷阱,导致表现的结果不尽如人意。

    例如 flex: 1 与 flex-grow: 1
    flex: 1 => flex: 1 1 0%
    flex-grow: 1 => flex: 1 1 auto
    两者的区别在于 flex-basis 的值不同。flex: 1 为项目宽度重新设置了宽度为0,所以可分配空间为整个容器。

  6. align-self 定义单个弹性项目在侧轴上应当如何对齐,这个定义会覆盖由 align-items 所确立的默认值。

    1
    2
    3
    .item {
    align-self: auto | flex-start | flex-end | center | baseline | stretch;
    }

需要注意的 Flexbox 特性 / Bug

  1. 无效属性

    • float 和 clear 在弹性项目无效
    • vertical-align 在弹性项目无效
    • column-* 在弹性容器无效
    • ::first-line 和 ::first-letter 在弹性容器无效
  2. 弹性容器中的 非空字符文本节点 也是弹性项目

  3. margin 折叠

    • 弹性容器和弹性项目的 margin 不会折叠
    • 弹性项目间的 margin 不会折叠
  4. 旧版 Flexbox 的 BUG

    弹性项目为行内元素要加 display: block 或 display: flex 属性

参考文献

CSS 弹性盒子布局 - MDN
30 分钟学会 Flex 布局 - 林东洲
Flexbox布局的正确使用姿势 - Leechikit

HaPBoy

HaPBoy

2 日志
12 标签
RSS
GitHub E-Mail
© 2017 HaPBoy
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.3