CSS布局(二)

319 阅读9分钟

前言

CSS布局系列的第一篇文章,讲了CSS中的几个基本概念。
文章链接如下:CSS布局(一)
在这一篇文章中,将介绍三种布局方式:正常文档流、浮动和定位。

文档流

文档流(Document Flow),通常也被称为普通流,常规流(Normal Flow),是CSS中最基础的一种布局方式。我们知道,在CSS的盒模型中,所有的 html 元素都被抽象成一个一个的盒子。而这些盒子又被分成两类:块盒子(Block Box)和行内盒子(Inline Box)。文档流所阐述的就是这两类盒子在web页面的呈现方式。也就是说,块盒子和行内盒子设置任何布局属性时在web页面中的呈现方式。
对于块盒子而言,就是将块元素从上到下的进行排列,然后每一个块元素单独占据一行。拿简单的文本来进行举例:

  <div class="container">           
    <div class="normal">1</div>  
    <div class="normal">2</div>
    <div class="normal">3</div>           
  </div>

在页面中呈现的效果如图所示:
块盒子呈现效果.png
对于行内盒子而言,就是将行内盒子按照从左到右的方式进行排列,然后每个行内元素不会换行。例子如下:

<div class="container">           
    <div class="normal">1
        <span>inline-box</span>
    </div>  
    <div class="normal">2</div>
    <div class="normal">3</div>           
</div>

在页面中的呈现效果如图所示:
行内盒子呈现效果.png

浮动

上面介绍了文档流。扯了这么多,正常文档流其实就是浏览器对于html元素的默认渲染方式。接下来我们要将html元素脱离正常的文档流,实现我们想要他变成的布局方式。第一种手段就是浮动(Float).我们首先从浮动的定义聊起吧。W3C对浮动的定义是这样的:

浮动是在当前行上向左或向右移动的盒子。浮动最有趣的特性是内容可能沿着它的侧流动。内容沿着左浮动框的右侧向下流动,并沿着右浮动框的左侧向下流动。 关于浮动的定义,有几点是需要清楚的:

  1. 浮动一定是脱离了正常文档流的。也就是说在没有设置其他属性的前提下,浮动元素的高度是不会计算到正常文本流的高度中的。
  2. 浮动是指在当前行向左或向右移动的盒子。也就是说浮动元素只会跑到父元素的最左侧或者最右侧,不会改变浮动在文本页面中的相对行数。
  3. 关于浮动的关键词问题:只能是none、left、right、inherit,inline-start,inline-end这几个值。也就是说浮动的关键词只跟行内元素相关。
  4. 浮动的元素不会影响到正常的CSS盒模型布局,但是盒模型里面的元素会给浮动的元素腾出位置。 接下来,我们用一个例子来说明浮动的这几个特点,先上代码:
  • html:
 <div class="container">           
    <div class="normal">1</div>  
    <div class="normal">2</div>
    <div class="float">float</div>
    <div class="normal">3</div>   
    <div class="normal">4</div>           
</div>
  • css:
.normal {
    width: 300px;
    background: pink;
    border: 3px solid red;
    text-align: center;
    font-size: 30px;
}

.float {
    width: 100px;
    background: green;
    text-align: center;
    font-size: 30px;
    float: left;
}

这两段代码中,首先html代码表示了html元素的结构:由一个div标签包含了五个div标签,并且设置了他们所属的类。然后在CSS代码中分别设置了正常的文档流和浮动元素的样式。显然在CSS代码中 float:left; 这行代码是标明元素浮动的。这一段代码的显示效果如图所示: 浮动效果.png
对比这个显示结果,我们来看一下浮动元素的上述几个特性:

  1. 这段代码中,我没有设置容器div的高度,这样的话容器的高度应该是自适应的。显然在计算文档流高度的时候没有计算浮动元素的高度。本来父元素中有五个div标签,但是却只计算了四个未浮动的div标签的高度。
  2. 第二个特性就要看float的相对位置了。在html文档中,<div>float</div>元素在<div>2</div><div>3</div>之间。在没有设置浮动的时候,应该在<div>2</div><div>3</div>空出相应的大小,然后,将<div>float</div>这个元素插入到这中间。现在设置了浮动,它就从正常的文档流中脱离了,但是位置仍然是<div>2</div><div>3</div>之间。只是直接叠到了<div>2</div>下面的位置。
  3. 这个特性只是一个参数的问题,这里不赘述了
  4. 第四个特性也是显然的吧。设置了浮动的元素只是叠在了盒模型的上面。它底下渲染的盒模型的边框和背景都还在,只不过内容的宽度重新计算了。 感觉浮动就类似于我们小时候玩的剪纸游戏,我们把html正常文档流的一部分剪下来,然后,把剩余的元素往上推。最后把剪下来的那一块叠到最左边或者最右边。该过程如下图所示: 浮动形象表示.png

浮动布局的问题

将浮动用于布局,有几个问题需要解决。这些问题总结起来就是父元素塌陷和文字环绕的问题。

  • 父元素塌陷:当父元素中的子元素都设为浮动的情况下,会导致父元素的高度为0,造成父元素塌陷。具体的效果如图所示: 父元素塌陷.png
  • 文字环绕:当设置了元素浮动之后,其行内盒子的字元素会绕着浮动元素进行排列。具体的效果如图所示: 文字环绕.png
    这种文字环绕的效果还是可以接受的,但是如果是块元素和行内元素都存在,那么可能会造成如下图所示的后果:

文字环绕-块元素.png
这样的显示效果,块元素和浮动元素叠在一起了,并且文字还在浮动元素的另一侧排列。这样看起来就比较怪异。

解决办法

为了解决这些问题,我们需要触发BFC。

  • 利用 clear 清除浮动
  • 设置overflow值为非visible
  • display属性设置为flow-root 清除了浮动之后的显示效果为: 清除浮动.png

温馨提示

由于浮动对于其他元素布局的破坏性,在布局的时候,浮动还是不要滥用。关于为什么浮动不能滥用这个问题,有一篇文章讲的比较深刻了。
这里放链接:CSS float浮动的深入研究、详解及拓展

定位

第二个脱离正常文档流的方式是定位。定位(position),按照字面意思的理解就是对html元素按照一定的格式,将其位置固定下来。定位是靠position属性来实现的,它规定了特定的盒子在总体布局上应该处于什么位置以及对周围的元素有什么影响。值得一提的是:除了position属性规定的一些定位模式之外,float和正常文档流都规定了一种定位模式
接下来,我们就来分别谈一谈CSS中的position属性的取值:

  • position : static
  • position : absolute
  • position : relative
  • position : fixed
  • position : sticky
  • position : inherit position : inherit自然不用说,它代表的显然是继承父元素的定位方式。position : static则为浏览器的默认值,它表示静态文本定位,规定了正常的文档流的定位方式,并不会对页面的布局产生任何其他的影响。因此,我们将关注的重点放到其他 position 的其他四种取值上。

position:absolute VS position:relative

关于position这个属性,有两个值是相对的。一个是“relative”,另一个是“absolute”。把他们翻译成中文会发现一个是相对的,一个是绝对的。他们都可以通过 top、right、bottom和left这四个值来决定元素的位置。那么这个相对和绝对是如何定义的呢?这两个属性的参照对象是不一样的,接下来我们就对比着来看这两个概念:

  • relative:设置了该值的元素偏移是相对于自己在文档流中原本应该在的位置而言的。
  • absolute:设置了该值的元素偏移是相对于第一个position值不为static的父元素而言的。 由于一个相对性和一个绝对性,它俩经常放一块使用。我们来看个例子:
 <div class="accordionMenu">
    <div class="menuSection" id="brand">
        <h2><a href="#brand">Brand</a></h2>
        <p>Lorem ipsum dolor...</p>
    </div>

    <div class="menuSection" id="promotion">
        <h2><a href="#promotion">Promotion</a></h2>
        <p>Lorem ipsum dolor sit amet...</p>
    </div>

    <div class="menuSection" id="event">
        <h2><a href="#event">Event</a></h2>
        <p>Lorem ipsum dolor sit amet...</p>
    </div>
</div>

我们来看他的CSS位置属性设置:

.accordionMenu h2 {
    margin: 5px 0;
    padding: 0;
    position: relative;
}
.accordionMenu h2:before {
    border: 5px solid #fff;
    border-color: #fff transparent transparent;
    content: "";
    height: 0;
    position: absolute;
    right: 10px;
    top: 15px;
    width: 0
}

在这段代码中,将.accordionMenu下的h2标签的position属性设置为relative,然后将伪元素h2:before的position属性值设置为absolute。其中,h2:before利用边框的特性绘制了一个小三角形。显然,如果设置了偏移量,h2将会相对于它原本的位置发生偏移,而h2:before则会相对于h2元素发生偏移。在这个例子中,设置的是right: 10px; top: 15px;那么,会发生的情况是h2:before相对于h2偏移,并且距离h2的右侧10px,距离h2的顶端15px。具体的显示结果如下图所示: 定位效果.png

position:fixed

固定定位和绝对定位的行为比较类似。区别就在于他们的定位起点不一样,固定定位始终是相对于浏览器窗口进行定位的。他的显示效果,我想我们应该可以经常能看到。比如说一些网上上面的小广告,不管页面怎样滑动,小广告的窗口始终都在同一个位置不会发生变化。这种定位方式就是固定定位。同样,他也是使用top、right、bottom和left这四个属性来进行位置的计算的。

position:sticky

黏贴定位实现的效果是允许被定为的元素像相对定位一样起作用,直到滑动到某个阈值点,此后它就变得固定了。其实就是相对定位和固定定位的混合体。关于这种定位模式,我要举的例子还是小广告的例子。

温馨提示

在页面布局的时候,这种定位模式只能用来进行局部的微调,而不能将整个页面都进行定位。这样做会搞乱整个页面布局,给后期的维护和开发带来很大的困难。

写在后面的话

各位路过的大佬,喜欢的给点个赞,不喜欢的看看就得了。如果有什么问题的,希望大佬能够帮忙指出来(^▽^) CSS布局系列的文章未完待续...