一个非前端开发者的CSS布局学习笔记

598 阅读16分钟

在 Web 前端开发中,CSS 布局是非常重要的知识技能。本篇文章主要是记录我在学习 CSS 布局知识时的学习笔记,阅读之前需要你了解部分的 CSS 和 HTML 知识。

几个重要的 CSS 布局相关属性

display 属性

display是 CSS 中非常重要的用来控制布局的属性, HTML 中每个元素都有一个默认的display属性,大多数元素该属性的默认值为blockinlineblock元素被称为块级元素,inline元素通常被称为行内元素。display属性值通常有如下几种取值:

  • block:块级元素。它会新开始一行,HTML 中大多数元素都默认为该值,如:divpform等元素。
  • inline:行内元素。它不会新开始一行,行内元素可以在段落中而不打乱段落布局。spana等元素默认为该值。
  • inline-block:它是 blockinline 的结合体,主要用来把块级元素变换为行内元素,方便布局。
  • flex:一种新的布局方式,可以让布局更简单。
  • none:设置为该值的元素会被隐藏,布局时此类型元素可以不用考虑。

margin 属性

margin属性用于指定本元素距离周围元素的距离,在布局时,会经常用到。

max-width 属性

max-width用于指定当前元素最大宽度,当父容器宽度变小时,元素宽度会减小,但是当父容器宽度变大时,该元素最大宽度为指定宽度。

盒子模型

CSS 元素由内容、内边距、边框、外边距组成,我们平时设置元素的 widthheight 等相关属性时,默认情况下,设置的都只是内容的大小,内边距,边框、外边距都可能会增大元素的实际大小。具体内容可能参考这篇文章:CSS 基础框盒模型介绍

如下所示,两个div元素都设置了同样的宽度,但是设置了外边距和边框的div元素明显实际宽度更大一些。

box-model.png

代码示例:

<style>
    #box-model .simple {
        width: 500px;
        margin: 20px auto;
        border: 2px solid green;
    }
    #box-model .fancy {
        width: 500px;
        margin: 20px auto;
        padding: 50px;
        border: 10px solid green;
    }
</style>

<div class="simple">
    I'm use box-sizing, My width is 500px.
</div>
<div class="fancy">
    I'm use box-sizing, My width is 500px.
</div>

box-sizing 属性

当把一个元素的 box-sizing 属性设置为 border-box 时,内边距和边框不会再增加元素的实际大小。

如下所示,两个div元素都设置了同样的宽度,但是设置了内边距和边框的div元素实际宽度没有变大。

box-sizing.png

代码示例如下:

<style>
    #box-sizing .simple {
        box-sizing: border-box;
        width: 500px;
        margin: 20px auto;
        border: 2px solid green;
    }
    #box-sizing .fancy {
        box-sizing: border-box;
        width: 500px;
        margin: 20px auto;
        padding: 50px;
        border: 10px solid green;
    }
</style>

<div class="simple">
I'm use box-sizing, My width is 500px.
</div>
<div class="fancy">
I'm use box-sizing, My width is 500px.
</div>

使用 position 布局

position 属性

position 属性是 CSS 布局中常用的属性,可以有如下的取值:

  • static:默认值,当一个元素被设置为 static 时,表示元素不能被 positioned(主要为absolute服务)。
  • relative:与 static 基本一致,区别在于元素可以被 positioned
  • fixed:固定定位,元素会相对于整个视窗(可以理解为浏览器窗口)定位,即使页面发生滚动,它还是会停留在相同的位置。
  • absolute:绝对定位,与 fixed 相似,但它的定位是相对于最近的可以被 positioned 的祖先元素。

position 布局示例

使用 position 完成如下所示的布局:

position-layout.png

代码示例:

<style>
    #position-layout {
        width: 90%;
        margin: 0 auto;
        position: relative;
        border: 2px solid green;
    }
    #position-layout .nav {
        position: absolute;
        top: 0px;
        left: 0px;
        width: 200px;
        padding-left: 20px;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #position-layout section {
        margin-left: 200px;
        border: 2px solid orange;
        box-sizing: border-box;
    }
</style>

<div id="position-layout">
    <div class="nav">
        <li><a href="#">menuItem1</a></li>
        <li><a href="#">menuItem2</a></li>
        <li><a href="#">menuItem3</a></li>
    </div>
    <section>
        This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.
    </section>
    <section>
        This is a long section too.This is a long section too.This is a long
        section too.This is a long section too.This is a long section too.This
        is a long section too.This is a long section too.This is a long section
        too.This is a long section too.This is a long section too.This is a long
        section too.This is a long section too.
    </section>
</div>

使用 float 布局

float 属性

为了防止影响后续元素,在使用 float 时注意使用 clear 清除浮动。

float 可以用于实现如下所示的文字环绕图片效果:

float.png

代码示例:

<style>
    #float {
        overflow: auto;
        border: 2px solid orange;
    }
    #float img {
        width: 200px;
        float: left;
        margin: 0 1em 1em 0;
    }
    #float:after {
        content: '.';
        display: block;
        height: 0;
        clear: both;
        visibility: hidden;
    }
</style>
<div id="float">
    <img
         src="https://cn.bing.com/th?id=OHR.RhinosOxpecker_ZH-CN6392794613_1920x1080.jpg"
         />
    <section>
        犀牛(学名:Dicerorhinus)是哺乳类犀科的总称,有4属5种。是世界上最大的奇蹄目动物,
        犀类动物腿短、体肥笨拙,体长2.2-4.5米,肩高1.2-2米,体重2000-5000千克。前后肢均三趾;
        皮厚粗糙,并于肩腰等处成褶皱排列,毛被稀少而硬,甚或大部无毛;耳呈卵圆形,头大而长,颈短粗,长唇延长伸出;
        头部有实心的独角或双角(有的雌性无角),起源于真皮,角脱落仍能复生;无犬齿;尾细短,身体呈黄褐、褐、黑或灰色。
        栖息于低地或海拔2000多米的高地。夜间活动,独居或结成小群。生活区域从不脱离水源。食性因种类而异,
        以草类为主,或以树叶、嫩枝、野果、地衣等为食物。母兽妊娠期18-19个月。寿命30-50年。
        因犀牛角的装饰和药用价值而被大量捕捉,除白犀外均为濒危物种。分布于亚洲南部、东南亚和非洲撒哈拉以南地区
        9月22日是“世界犀牛日”(World Rhino
        Day)。2010年,“世界犀牛日”由南非世界自然基金会创办(WWF-South
        Africa),现已为全世界广泛接受。该活动旨在关注全球稀有动物。
        在渐新世出现了有史以来最大陆生哺乳动物——巨犀,它体格健壮和高大,体长约8米,身高5米。不过虽然巨犀和犀牛同属奇蹄目,但并不属于犀牛科。
        中新世的后期,出现了独角犀牛的祖先。独角犀牛仅存爪哇犀牛和印度犀牛,均分布在亚洲。在中新世以后出现的犀牛体型与现代犀牛相接近。
        其中有下唇比上唇略大些的大唇犀,下颌有两颗大牙向前伸出,生活在沼泽地带,以水中的植物为食。
        上新世后期(约300万年前),双角犀牛出现。双角犀牛有苏门达腊犀、白犀牛和黑犀牛。第四纪时期人类已经出现,早期的犀牛以板齿犀、披毛犀为代表。
        板齿犀个体巨大,5米长,身披厚甲,在额部生有大角,约2米长,牙齿的齿冠高,呈方柱状,草地上生活,
        更新世时期在中国华北的及欧洲等地曾有板齿犀生活;披毛犀和猛犸象外形相似,巨大的身体及长着粗毛的厚皮可以抵御寒冷,长鼻上有一对巨角,
        前面一支最长可达1米,生活在寒冷地带。这两种犀类先后在不同的时期都已经灭绝了。
        在犀类的后代中,现仅残存有犀牛科的4属5种,主要分布在亚洲和非洲,其中分布在亚洲的犀牛已经濒临绝种。
        主要是因为犀牛角作为药材,其实犀牛角跟指甲是一样的构造,随数量减少现在也不容易买到真正的犀牛角,
        市场还得以购买是因为现在商贩懂得以牛角替代来获利,甚至用相似成分的猫狗爪磨成假货变换充数。
    </section>
</div>

float 布局示例

使用 float 完成如下所示的布局:

float-layout.png

代码示例:

<style>
    #float-layout {
        width: 90%;
        margin: 0 auto;
        border: 2px solid green;
    }
    #float-layout .nav {
        float: left;
        width: 200px;
        padding-left: 20px;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #float-layout section {
        margin-left: 200px;
        border: 2px solid orange;
        box-sizing: border-box;
    }
    #float-layout:after {
        content: '.';
        display: block;
        height: 0;
        clear: both;
        visibility: hidden;
    }
</style>

<div id="float-layout">
    <div class="nav">
        <li><a href="#">menuItem1</a></li>
        <li><a href="#">menuItem2</a></li>
        <li><a href="#">menuItem3</a></li>
    </div>
    <section>
        This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.
    </section>
    <section>
        This is a long section too.This is a long section too.This is a long
        section too.This is a long section too.This is a long section too.This
        is a long section too.This is a long section too.This is a long section
        too.This is a long section too.This is a long section too.This is a long
        section too.This is a long section too.
    </section>
</div>

使用 inline-block 布局

使用 inline-block 的注意事项

  • vertical-align 属性会影响到 inline-block 元素,可能需要把它的值设置为 top
  • 需要设置每一列的宽度
  • 如果源代码中 inline-block 元素之间有空格或者换行,那么列之间会产生空隙。如果同行的元素使用了百分比宽度且加起来和是100%宽度,但是由于代码的换行,导致列之间有空隙,会出现元素无法排列在同一行的现象。

inline-block 布局示例

使用 inline-block 完成如下所示的布局:

inline-block-layout.png

代码示例:

<style>
    #inline-block-layout {
        width: 90%;
        margin: 0 auto;
        border: 2px solid green;
        font-size: 0;
    }
    #inline-block-layout .nav {
        display: inline-block;
        vertical-align: top;
        width: 25%;
        padding-left: 20px;
        border: 2px solid red;
        box-sizing: border-box;
        font-size: 16px;
    }
    #inline-block-layout .column {
        display: inline-block;
        vertical-align: top;
        width: 75%;
        border: 2px solid red;
        box-sizing: border-box;
        font-size: 16px;
    }
    #inline-block-layout .column section {
        border: 2px solid orange;
        box-sizing: border-box;
    }
</style>

<div id="inline-block-layout">
    <div class="nav">
        <li><a href="#">menuItem1</a></li>
        <li><a href="#">menuItem2</a></li>
        <li><a href="#">menuItem3</a></li>
    </div>
    <div class="column">
        <section>
            This is a long section.This is a long section.This is a long
            section.This is a long section.This is a long section.This is a long
            section.This is a long section.This is a long section.This is a long
            section.This is a long section.This is a long section.This is a long
            section.
        </section>
        <section>
            This is a long section too.This is a long section too.This is a long
            section too.This is a long section too.This is a long section too.This
            is a long section too.This is a long section too.This is a long
            section too.This is a long section too.This is a long section too.This
            is a long section too.This is a long section too.
        </section>
    </div>
</div>

使用 flexbox 布局

flextbox 是一种新的布局方式,可能会有一些旧的浏览器无法支持 flexbox 布局。使用flexbox布局可以轻松实现复杂的布局,可以非常容易的实现垂直居中和水平居中,使用起来极为方便。

flexbox 简单布局示例

使用 flexbox 完成如下所示的布局:

flexbox-layout.png

代码示例:

<style>
    #flexbox-layout {
        display: flex;
        width: 90%;
        margin: 0 auto;
        border: 2px solid green;
    }
    #flexbox-layout .nav {
        width: 200px;
        padding-left: 20px;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #flexbox-layout .column {
        flex: 1;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #flexbox-layout .column section {
        border: 2px solid orange;
        box-sizing: border-box;
    }
</style>

<div id="flexbox-layout">
    <div class="nav">
        <li><a href="#">menuItem1</a></li>
        <li><a href="#">menuItem2</a></li>
        <li><a href="#">menuItem3</a></li>
    </div>
    <div class="column">
        <section>
            This is a long section.This is a long section.This is a long
            section.This is a long section.This is a long section.This is a long
            section.This is a long section.This is a long section.This is a long
            section.This is a long section.This is a long section.This is a long
            section.
        </section>
        <section>
            This is a long section too.This is a long section too.This is a long
            section too.This is a long section too.This is a long section too.This
            is a long section too.This is a long section too.This is a long
            section too.This is a long section too.This is a long section too.This
            is a long section too.This is a long section too.
        </section>
    </div>
</div>

flexbox 复杂布局示例

实现如下所示四列布局方式,左边两列固定宽度,右边两列分别占剩下的空间1/3和2/3。

flexbox-complex-layout.png

示例代码:

<style>
    #flexbox-complex-layout {
        display: flex;
        width: 90%;
        margin: 0 auto;
        border: 2px solid green;
    }
    #flexbox-complex-layout .nav {
        width: 200px;
        min-width: 100px;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #flexbox-complex-layout .carousel {
        flex: none;
        width: 200px;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #flexbox-complex-layout .column1 {
        flex: 1;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #flexbox-complex-layout .column2 {
        flex: 2;
        border: 2px solid red;
        box-sizing: border-box;
    }
</style>

<div id="flexbox-complex-layout">
    <div class="nav">
        I have 200px width when the space is enough, otherwise my width is
        100px.
    </div>
    <div class="carousel">
        I have 200px width whenever the space is enough or not.
    </div>
    <div class="column1">
        I have one third width of the left space.
    </div>
    <div class="column2">
        I have two third width of the left space.
    </div>
</div>

flexbox 水平与垂直居中示例

实现如下所示的水平与垂直方向上的居中。

flexbox-center.png

示例代码:

<style>
    #flexbox-easy-center {
        display: flex;
        width: 90%;
        height: 100px;
        margin: 0 auto;
        align-items: center;
        justify-content: center;
        border: 2px solid green;
        box-sizing: border-box;
    }
    #flexbox-easy-center section {
        border: 2px solid green;
        box-sizing: border-box;
    }
</style>

<div id="flexbox-easy-center">
    <section>
        I'm in the middle of the container.
    </section>
</div>

媒体查询与响应式

布局随着不同大小的视窗动态调整布局,这就被称为响应式布局,响应式布局可以通过媒体查询来实现。

如下图表示,当视窗的宽度大于600px时,采用两栏式布局,当宽度小于600px时,采用单栏式布局,菜单也切换为横向菜单。

media-query-1.png

media-query-2.png

示例代码:

<style>
    #media-query {
        width: 90%;
        margin: 0 auto;
        position: relative;
        border: 2px solid green;
    }
    #media-query .nav {
        padding-left: 20px;
        border: 2px solid red;
        box-sizing: border-box;
    }
    #media-query section {
        border: 2px solid orange;
        box-sizing: border-box;
    }
    @media screen and (min-width: 600px) {
        #media-query .nav {
            position: absolute;
            top: 0px;
            left: 0px;
            width: 25%;
        }
        #media-query section {
            margin-left: 25%;
        }
    }
    @media screen and (max-width: 599px) {
        #media-query .nav li {
            display: inline;
        }
    }
</style>
<div id="media-query">
    <div class="nav">
        <li><a href="#">menuItem1</a></li>
        <li><a href="#">menuItem2</a></li>
        <li><a href="#">menuItem3</a></li>
    </div>
    <section>
        This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.This is a long section.This is a long section.This is a long
        section.
    </section>
    <section>
        This is a long section too.This is a long section too.This is a long
        section too.This is a long section too.This is a long section too.This
        is a long section too.This is a long section too.This is a long section
        too.This is a long section too.This is a long section too.This is a long
        section too.This is a long section too.
    </section>
</div>

元素居中

元素居中是常用的布局技巧,包括水平居中和垂直居中。下文的居中示例代码使用的通用CSS代码如下所示:

<style>
  h4 {
    text-align: center;
  }

  #align-center > div {
    margin-top: 50px;
    width: 100%;
    height: 100px;
    box-sizing: border-box;
  }

  #align-center .child {
    height: 30px;
    border: 2px solid black;
  }

  #vertical-center > div {
    margin-top: 50px;
    width: 100%;
    height: 100px;
    box-sizing: border-box;
  }

  #vertical-center .child {
    height: 30px;
    border: 2px solid black;
  }
</style>

水平居中的常用方法

水平居中包括以下几种常见实现方式。水平居中效果如下图所示:

align-center.png

子元素为inline

父元素设置text-align: center,代码示例:

<style>
  #align-center > .inline {
    text-align: center;
    border: 2px solid green;
  }

  #align-center > .inline > .child {
    display: inline;
  }
</style>
<div id="align-center">
  <div class="inline">
    <div class="child">I am inline</div>
  </div>
</div>
子元素为block并且宽度固定

子元素设置margin: 0 auto,代码示例:

<style>
  #align-center > .block-width {
    border: 2px solid blue;
  }

  #align-center > .block-width > .child {
    display: block;
    width: 200px;
    margin: 0 auto;
  }
</style>
<div id="align-center">
  <div class="block-width">
    <div class="child">
      I am block with width
    </div>
  </div>
</div>
子元素为block并且宽度不固定

设置子元素display: inline,设置父元素text-align: center,代码示例:

<style>
  #align-center > .block-no-width {
    border: 2px solid red;
    text-align: center;
  }

  #align-center > .block-no-width > .child {
    display: inline;
  }
</style>
<div id="align-center">
  <div class="block-no-width">
    <div class="child">
      I am block without width
    </div>
  </div>
</div>
使用transform

父元素设置position: relative,子元素使用绝对定位与transform配合实现,代码示例:

<style>
  #align-center > .transform {
    position: relative;
    border: 2px solid orange;
  }

  #align-center > .transform > .child {
    position: absolute;
    transform: translate(-50%, 0);
    left: 50%;
  }
</style>
<div id="align-center">
  <div class="transform">
    <div class="child">
      I am transform
    </div>
  </div>
</div>
使用flex

父元素设置flex布局与justify-content: center,代码示例:

<style>
  #align-center > .flex {
    display: flex;
    justify-content: center;
    border: 2px solid purple;
  }
</style>
<div id="align-center">
  <div class="flex">
    <div class="child">I am flex</div>
  </div>
</div>

垂直居中的常用方法

垂直居中包括以下几种常见实现方式。水平居中效果如下图所示:

vertical-center.png

子元素为block

父元素设置position: relative,子元素使用绝对定位与margin配合实现,代码示例:

<style>
  #vertical-center > .block {
    position: relative;
    border: 2px solid green;
  }

  #vertical-center > .block > .child {
    display: block;
    position: absolute;
    margin: auto;
    top: 0;
    bottom: 0;
  }
</style>
<div id="vertical-center">
  <div class="block">
    <div class="child">I am block</div>
  </div>
</div>
子元素为inline

父元素设置line-heightheight值相等,代码示例:

<style>
  #vertical-center > .inline {
    border: 2px solid blue;
    line-height: 100px;
  }

  #vertical-center > .inline > .child {
    display: inline;
  }
</style>
<div id="vertical-center">
  <div class="inline">
    <div class="child">I am inline</div>
  </div>
</div>
子元素为inline-block

父元素添加after伪元素,子元素设置vertical-align: middle,代码示例:

<style>
  #vertical-center > .inline-block {
    border: 2px solid red;
  }

  #vertical-center > .inline-block:after {
    content: '';
    height: 100%;
    display: inline-block;
    vertical-align: middle;
  }

  #vertical-center > .inline-block > .child {
    display: inline-block;
    vertical-align: middle;
  }
</style>
<div id="vertical-center">
  <div class="inline-block">
    <div class="child">I am inline-block</div>
  </div>
</div>
使用transform

父元素设置position: relative,子元素使用绝对定义配合transform实现,代码示例:

<style>
  #vertical-center > .transform {
    position: relative;
    border: 2px solid orange;
  }

  #vertical-center > .transform > .child {
    position: absolute;
    transform: translate(0, -50%);
    top: 50%;
  }
</style>
<div id="vertical-center">
  <div class="transform">
    <div class="child">I am transform</div>
  </div>
</div>
使用flex

父元素设置flex布局与align-items: center,代码示例:

<style>
  #vertical-center > .flex {
    display: flex;
    align-items: center;
    border: 2px solid purple;
  }
</style>
<div id="vertical-center">
  <div class="flex">
    <div class="child">I am flex</div>
  </div>
</div>

参考文档