【html5/css3】css中清除浮动的五种方式及其原理剖析

清除浮动的四种方式及其原理理解

本文介绍了四种清除浮动的方法,并尝试解释其原理。在理解了各种清除浮动的原理之后,你会发现,很多清除浮动的方法本质上其实是一样的。掌握这些原理,相信你可以根据场景和需求,灵活运用原则发展出不同的清除浮动的方法,而不再死记或拘泥于文中提到的方法。

一、为什么要清除浮动

在讲清除浮动的方法之前,我们先来了解一下为什么要清除浮动,清除浮动的目的是什么,即,要解决什么样的问题。来看一个浮动的例子(略去了文字内容):

HTML:

<div class="topDiv">
    <div class="floatDiv">floatDivdiv>
    <div class="textDiv">textDivdiv>
div>
<div class="bottomDiv">bottomDivdiv>

CSS:

*{
    padding: 0;
    margin: 0;
    color: #fff;
}
.topDiv {
    width: 500px;
    border: 4px solid #000;
}
.floatDiv {
    width: 100px;
    height: 100px;
    background: red;
    float: left;
}
.bottomDiv {
    width: 500px;
    height: 100px;
    margin: 5px 0;
    background: pink;
}
.textDiv {
    background: blue;
}  

图示:

分析:

这肯定不是我们想要的渲染效果,它可能存在如下问题:

文字围绕浮动元素排版,但我们可能希望文字(.textDiv)排列在浮动元素下方,或者,我们并不希望.textDiv两边有浮动元素存在。

浮动元素排版超出了其父级元素(.topDiv),父元素的高度出现了塌缩,若没有文字高度的支撑,不考虑边框,父级元素高度会塌缩成零。

浮动元素甚至影响到了其父元素的兄弟元素(.bottomDiv)排版。因为浮动元素脱离了文档流,.bottomDiv在计算元素位置的时候会忽略其影响,紧接着上一个元素的位置继续排列。

解决第一个问题,需要清除.textDiv周围的浮动,而解决第二个问题,因为父元素的兄弟元素位置只受父元素位置的影响,就需要一种方法将父级元素的高度撑起来,将浮动元素包裹在其中,避免浮动元素影响父元素外部的元素排列。

接下来开始介绍清除浮动的方法。

二、清除浮动的方法

1. 利用clear样式清楚自身浮动

我们给需要清除浮动的元素添加如下样式:

.textDiv {
    color: blue;
    border: 2px solid blue;
    clear: left;
}

图示:

分析:

通过上面的样式,.textDiv告诉浏览器,我的左边不允许有浮动的元素存在,请清除掉我左边的浮动元素。然而,因为浮动元素(.floatDiv)位置已经确定,浏览器在计算.textDiv的位置时,为满足其需求,将.textDiv渲染在浮动元素下方,保证了.textDiv左边没有浮动元素。同时可以看出,父元素的高度也被撑起来了,其兄弟元素的渲染也不再受到浮动的影响,这是因为.textDiv仍然在文档流中,它必须在父元素的边界内,父元素只有增加其高度才能达到此目的,可以说是一个意外收获。(clear的值为both也有相同的效果,通俗理解就是,哪边不允许有浮动元素,clear就是对应方向的值,两边都不允许就是both)

但是,如果我们把HTML中的.floatDiv和.textDiv交换一下位置呢?

<div class="topDiv">
    <div class="textDiv">textDivdiv>
    <div class="floatDiv">floatDivdiv>
div>
<div class="bottomDiv">bottomDivdiv>

图示:

分析:

此时.textDiv的位置先确定了,于是浮动元素就紧接着.textDiv下方渲染在父元素的左侧。然而,父元素的高度并没有被撑起来,没有将浮动影响“内化”,导致浮动影响到了接下来的元素排版。

看来,为达到撑起父元素高度的目的,使用clear清除浮动的方法还是有适用范围的。我们需要更加通用和可靠的方法。

(这里澄清一下,单从元素清除浮动的角度,clear完全已经达到了目的,它已经使得.textDiv特定的方向上不再有浮动元素,清除浮动其实仅仅针对需要清除浮动的元素本身而言,只关注自身需求是否达到,和外界没有什么关系,它不关注浮动是否超出父元素,以及浮动是否影响到后续元素排列。我们只是利用了浮动的一些特性达到某些目的,但这不是清除浮动关心的问题,只不过,相对于清除浮动,我们可能更加关心这些特性能为我们做些什么而已。我的理解是,清除浮动和撑起父元素高度其实是两个不同的问题,在这里,可以简单地理解为工具和目的之间的关系,接下来要讨论的两个方法都是在利用清除浮动这个工具在解决问题,它并不是清除浮动这个工具本身)

2. 父元素结束标签之前插入清除浮动的块级元素

根据HTML结构,在有浮动的父级元素的末尾插入了一个没有内容的块级元素div:

<style>
...上面样式不变...
.emptyDiv{
    clear: both;
}
style>
<body>
    <div class="topDiv">
        <div class="textDiv">textDivdiv>
        <div class="floatDiv">floatDivdiv>
        <div class="emptyDiv">div>    // 添加空标签
    div>
    <div class="bottomDiv">bottomDivdiv>
body>

图示:

分析:

原理无需多讲,和第一个例子里.textDiv应用clear清除浮动,撑起父级元素高度的原理完全一样。这里强调一点,在父级元素末尾添加的元素必须是一个块级元素,否则无法撑起父级元素高度,这种方法唯一不好的就是如果项目涉及很多清理浮动的话,这种毫无疑问会添加很多无意义的空标签,有违结构与表现的分离,在后期维护中将是噩梦;

3.利用伪元素(clearfloat)

HTML结构如下,为了惯例相符,在.topDiv的div上再添加一个clearfloat类:

<style>
...上面样式不变...
.clearfloat:after{
    display:block;
    content: ".";
    height: 0;
    visibility: hidden;
    clear: both;
}
.clearfloat{
    zoom: 1;
}
style>
<div class="topDiv clearfloat">
    <div class="textDiv">textDivdiv>
    <div class="floatDiv">floatDivdiv>
div>
<div class="bottomDiv">bottomDivdiv>

分析:

这种方法中需要注意,IE8以上和非IE浏览器才支持:after,原理和方法1有点类似,zoom(IE转有属性)可解决ie6,ie7浮动问题;顺便说一下这些样式的作用,display:block 使生成的元素以块级元素显示,占满剩余空间; height:0 避免生成内容破坏原有布局的高度;visibility:hidden 使生成的内容不可见,并允许可能被生成内容盖住的内容可以进行点击和交互;zoom:1 触发IE hasLayout。

该样式在clearfloat,即父级元素的最后,添加了一个:after伪元素,通过清除伪元素的浮动,达到撑起父元素高度的目的。注意到该伪元素的display值为block,即,它是一个不可见的块级元素(有的地方使用table,因为table也是一个块级元素)。你可能已经意识到,这也只不过是前一种清除浮动方法(添加空白div)的另一种变形,其底层逻辑也是完全一样的。前面的三种方法,其本质上是一样的。

4.父级div定义height

这个的代码就不展示了,如果项目中可以使用固定高度的话就可以使用这个方法;

原理:父级div手动定义height,就解决了父级div无法自动获取到高度的问题

优点:简单,代码少,容易掌握

缺点:只适合高度固定的布局,要给出精确的高度,如果高度和父级div不一样时,会产生问题

建议:不推荐使用,只建议高度固定的布局时使用

5.父级利用overflow清除浮动

在父级添加overflow:hidden/auto,hidden和auto都可以

.topDiv {
    width: 500px;
    border: 4px solid #000;
    overflow:hidden;
}

图示: 跟上一个图是一样的,这里不展示了哈

分析:

仅仅只在父级元素上添加了一个值为hidden或者auto的overflow属性,父元素的高度立即被撑起,将浮动元素包裹在内。看起来,浮动被清除了,浮动不再会影响到后续元素的渲染(严格讲,这和清除浮动没有一点关系,因为不存在哪个元素的浮动被清除,不纠结这个问题)。其实,这里的overflow值,还可以是除了"visible"之外的任何有效值,它们都能达到撑起父元素高度,清除浮动的目的。不过,有的值可能会带来副作用,比如,scroll值会导致滚动条始终可见,hidden会使得超出边框部分不可见等。那它们是如何做到浮动清除的呢?

要讲清楚这个解决方案的原理,有一个概念始终是绕不过去,那就是块格式化上下文(BFC),然而这又是一个非常抽象的概念,如果要清楚地把这个概念讲出来,恐怕需要非常大的篇幅,这里仅提及和理解该问题相关的内容。

BFC是什么?

块级格式化上下文(BFC)是CSS可视化渲染的一部分。它是一块区域,规定了内部块盒的渲染方式,以及浮动相互之间的影响关系。

块格式化上下文(BFC)有下面几个特点:

BFC是就像一道屏障,隔离出了BFC内部和外部,内部和外部区域的渲染相互之间不影响。BFC有自己的一套内部子元素渲染的规则,不影响外部渲染,也不受外部渲染影响。BFC的区域不会和外部浮动盒子的外边距区域发生叠加。也就是说,外部任何浮动元素区域和BFC区域是泾渭分明的,不可能重叠。BFC在计算高度的时候,内部浮动元素的高度也要计算在内。也就是说,即使BFC区域内只有一个浮动元素,BFC的高度也不会发生塌缩,高度是大于等于浮动元素的高度的。HTML结构中,当构建BFC区域的元素紧接着一个浮动盒子时,即,是该浮动盒子的兄弟节点,BFC区域会首先尝试在浮动盒子的旁边渲染,但若宽度不够,就在浮动元素的下方渲染。

有了这几点,就可以尝试解释为什么overflow(值不为visible)可以清除浮动了。

当元素设置了overflow样式,且值不为visible时,该元素就建构了一个BFC(哪些情况下,元素可以建构出BFC,可以看查看CSS文档对 )。在我们的例子中,.topDiv因设置了值为auto的overflow样式,所以该元素建构出一个BFC,按照第三个特点,BFC的高度是要包括浮动元素的,所以.topDiv的高度被撑起来,达到了清除浮动影响的目的。(至于为什么值为visible的overflow不能建构BFC,给了一个解释)

其实,这里overflow的作用就是为了构建一个BFC区域,让内部浮动的影响都得以“内化”。如果你看了BFC的定义,你会发现,构建一个BFC区域的方法有很多种,overflow只是其中的一种,那在这里,我们是否也可以利用其它的方式构建BFC,且同样能达到清除浮动的目的呢?

BFC定义中说,inline-block同样也能构建BFC,那我们就用该样式来试试:

.topDiv {
    width: 500px;
    border: 4px solid #000;
   display: inline-block;
}

图示:

效果完全一样!只要我们理解了原理,就可以灵活演变出不同的清除浮动的方法,而不必死记某种手段。

当然,要说明的是,在实际项目中选择采用哪种方式构建BFC是要具体问题具体分析的,因为要考虑到选用的样式自身的作用和影响。这个例子中,选用inline-block和选用overflow效果完全一样,没有看出有什么副作用,但不代表在其他项目中一样能行得通。甚至对overflow值的选择也要考虑其表现和影响。在各种构建BFC的方式中,overflow方式可能是外部影响更可控的一种,我猜想这也许就是为什么普遍采用overflow来清除浮动的原因吧。

到这里,分享的清除浮动的方法已经讲完了。其实,如果在不同的使用场景下,对这几个方法进行拆分组合(其实是对底层原理的拆分组合),还可以实现其他形式不同的清除浮动的方法,最重要的还是对底层原理的把握。知其然,亦知其所以然才是最有效的学习方式。

vscode 配合 eslint 自动格式化代码

vscode 配合 eslint 自动格式化代码 前言

最近在主导开发一个新项目,公司要求用 vue 来开发,用 vue-cli 生成了项目,就着手开动了。

但是后来发现一个问题,挺令人恼火的。

因为我默认在项目中开启了 eslint 检测代码,来保证项目代码的规范性。

这个初衷是好的,但是坏就坏在,eslint 检测代码一开启,才发现自己代码中到处都是不符合规范的问题。

一般情况下,遇到问题,第一反应肯定是开始上网查找解决方案,但是找了很多博文,发现好像不太对啊,怎么大家都是推荐,将 eslint 关掉,不检测,这样固然是可以解决报错的问题,但是代码质量就无法保证了。

这显然违背了我的初衷。

于是我就只有开始自己研究解决方案了,索性功夫不负有心人,经过一段时间的摸索以后,终于找到了完美的解决方案。

当然,我的项目是基于 vue 的,但是其实所有的前端项目,甚至于后端的项目,只要你用的是 JavaScript 来写的代码,其实原理都是一样的。

下面我就详细的介绍一下,如何在项目中配置 eslint 检测,并且配合 vscode 实现自动格式化代码。

过程 1. vscode 装上 eslint 插件

装 vscode 插件的方式,我这里就不赘述了,如果您还不知道该如何安装,请参考官方文档:

eslint 插件长这样:

安装好以后,打开 vscode 的配置文件—— settings.json ,加上下面这几行规则:

"eslint.autoFixOnSave": true,
"eslint.packageManager": "yarn",
"eslint.validate": [
  "javascript",  //  用eslint的规则检测js文件
  {
    "language": "vue",   // 检测vue文件
    "autoFix": true   //  为vue文件开启保存自动修复的功能
  },
  {
    "language": "html",
    "autoFix": true
  },
],

加上以后,相当于就开启了自动安装项目中的配置来格式化代码的功能。

2. 项目根目录加上 .eslintrc.js 文件

这个文件就是默认的 eslint 规则的配置文件,我在项目中使用了下面这些:

// https://eslint.org/docs/user-guide/configuring
module.exports = {
  root: true,
  parserOptions: {
    parser: 'babel-eslint',
    "sourceType": "module",
  },
  env: {
    browser: true,
    "es6": true
  },
  // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
  // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
  extends: ['plugin:vue/essential', 'airbnb-base'],
  // required to lint *.vue files
  plugins: [
    'vue'
  ],
  // check if imports actually resolve
  settings: {
    'import/resolver': {
      webpack: {
        config: 'build/webpack.base.conf.js'
      }
    }
  },
  "globals": {
    "twaver": "readonly",
    "mono": "readonly"
  },
  // add your custom rules here
  rules: {
    'linebreak-style': ["error", "unix"],
    // don't require .vue extension when importing
    'import/extensions': ['error', 'always', {
      js: 'never',
      vue: 'never'
    }],
    // disallow reassignment of function parameters
    // disallow parameter object manipulation except for specific exclusions
    'no-param-reassign': ['off', {
      props: true,
      ignorePropertyModificationsFor: [
        'state', // for vuex state
        'acc', // for reduce accumulators
        'e' // for e.returnvalue
      ]
    }],
    // allow optionalDependencies
    'import/no-extraneous-dependencies': ['error', {
      optionalDependencies: ['test/unit/index.js']
    }],
    'no-underscore-dangle': 0,
    'global-require': 0,
    "import/no-dynamic-require": 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    "no-console": 0,
    "no-unused-vars": [
      "off",
      {
        "args": "none"
      }
    ],
    "no-mixed-operators": [
      "error",
      {
        "groups": [
          // ["+", "-", "*", "/", "%", "**"],
          // ["&", "|", "^", "~", "<<", ">>", ">>>"],
          // ["==", "!=", "===", "!==", ">", ">=", "<", "<="],
          ["&&", "||"],
          ["in", "instanceof"]
        ],
        "allowSamePrecedence": true
      }
    ]
  },
}

当然,我是在 vue-cli 生成配置文件的基础上修改了一下,从而形成的这一份配置文件。

这个配置文件中的配置方式,其实都能在 eslint 的官网上找到详细的说明,我这里就简单的讲讲,一般情况下,我们该怎么改这份配置文件呢。

一旦你配置了规则以后,你打开编辑器在编码的过程中,就会出来编码不规范的提示,如下所示:

比如这个地方,我的 break 前面没加空格,于是编辑器会提示我——“Missing whitespace after semicolon.”,这个时候,如果你只是想按照这个规则改正这个错误,那么很简单,你有几种选择:

直接手动加空格点开快速修复,会弹出一个面板

有四个选项,分别是:修复这个问题;给这一行加上跳过规则检测的代码;给整个文件加上跳过 semi-spacing 规则检测的代码;显示相关文档。

可以看出,我们选择第一项,工具就会将我们的问题自动修复了。

由于之前安装了 eslint 插件,并且开启了保存自动修复的功能,因此直接按 ctrl+s 保存文件,会自动修复这个问题。

以上说的是几种简单的修复方式,但是如果我们想要配置哪些规则需要检测,哪些规则不需要检测,那么我们可以先上官网搜搜相关配置选项的说明:

比如这里,我搜索了 space-before-blocks 规则,然后详细的看了下简介,里面还有代码示例:

看完以后,我发现自己还是不喜欢这条规则,想要去掉它。

那么我就打开 .eslintrc.js 文件,在 rules 选项里加上下面配置:

{
	...
	"rules": {
    "space-before-blocks": 0,	// 适用于不想配置的情况
    // 适用于想要配置的规则
    "space-before-blocks": ["error", { "functions": "never", "keywords": "always", "classes": "never" }]
  }
  ...
}

一般情况下,如果不想开启这个规则,那么就直接将 value 设为 0,具体使用请参考这个页面:

3. .eslintignore.js

通过加上这个文件,配置一些不想进行 eslint 检测的目录,用法跟 .gitignore 类似

后记

其实写了这么多,到最后会发现好像自己什么都没写。

因为这篇文章里面的内容,原理本来就很简单,并不是什么高深的东西。

而且作为一个开源的框架来说,eslint 的使用方式,我相信应该没有比官网介绍的更好了。

所以,学习什么新技术,不要害怕,不要有一种畏难的心理,去官网瞅瞅,耐心研究一下,可能一切的问题都可以迎刃而解呢。

本站内容来自用户投稿,如果侵犯了您的权利,请与我们联系删除。联系邮箱:835971066@qq.com

本文链接:http://news.xiuzhanwang.com/post/2136.html

发表评论

评论列表

还没有评论,快来说点什么吧~

友情链接: