CSS - 浮动布局(float)

news2025/1/24 17:37:19

目录

标准布局

标准流

浮动与浮动流,及元素脱标概念

浮动元素

浮动的特点

浮动带来的问题:标准流父级容器高度塌陷

清除浮动

浮动布局 + margin负值


标准布局

CSS将所有的元素都当成盒子,CSS布局其实就是如何堆放盒子。

在说浮动布局之前,我们需要了解标准布局,所谓标准布局,即按照元素在标准流中的特点布局

  • 块级元素独占一行
  • 行内元素、行内块元素共享一行

这种布局方式中

  • 块级元素很难被有效利用起来,因为其独占一行的特性,所以其只能进行垂直方向的布局
  • 行内元素、行内块元素可以进行水平方向布局,但是它们的内容大部分只能是文本,少量的如td中支持放入其他行内块元素,但是并不适合进行通用布局
  • 行内元素、行内块元素之间水平方向会因为代码空格,换行产生间隙,行内块元素垂直方向存在默认的baseline对齐底部间隙,这给水平布局带来额外的麻烦,而td不存在这些问题

所以,在标准布局时代,我们多基于table进行网页布局。但是table布局也有非常严重的缺点:

  • 布局复杂
  • 布局一旦成型,很难变更
  • 渲染性能差

其实,本质上来看,标准布局的短板在于其水平方向上的布局只能使用行内、行内块元素,而行内、行内块元素由于各种问题,并不适用于布局,只适用于作为内容。

而块级元素并不存在行内和行内块元素的这些问题,所以如果块级元素也能用于水平方向布局,那么就完美了。

标准流

标准布局中的元素处于标准流中。

我们可以暂且将标准流理解为PS中的图层。标准流就是网页最底层的图层。

浮动与浮动流,及元素脱标概念

为了解决标准布局中,块级元素不能在水平方向布局的问题,即多个块级元素不能共享一行的问题,CSS提出了浮动的概念。

所谓浮动,即为元素设置float样式,float样式有如下值:

  • left 左浮动
  • right 右浮动
  • none 无浮动(元素默认浮动,无浮动)

一旦,元素设置了float:left或者float:right,则元素就会脱离标准流,简称“脱标”,然后进入浮动流。

所谓浮动流,我们可以理解其为处于标准流图层之上的另一个图层。

而一旦元素脱标后,元素就会释放其在标准流中的占据的位置,这将导致标准流中脱标元素之后的元素前据。

在浮动流中,多个块级元素是可以共享一行的

上例中,box1~box3设置了float:left,所以它们脱标进入浮动流,并共享一行,而box1~box3脱标后,它们在标准流中的位置就会被释放,此时box4这个依旧在标准流中的元素就会进据被释放的位置。

所以上例中,box4实际上有一部分被box1~bxo3遮盖住了,因为浮动流在标准流之上。

浮动元素

一旦标准流中元素被加了float:left或float:right样式,则元素就变为了浮动元素,脱标进入浮动流。

浮动元素其实可以看成是:特殊的行内块元素,它具备行内块的部分特点

  • 浮动元素之间共享一行
  • 浮动元素的width、height默认由元素内容决定,而不是由父级决定
  • 浮动元素支持通过width、height、padding、border、margin来指定盒子内容区、内外边距、边框大小
  • 浮动元素之间不会因为空格、换行产生空隙,浮动元素之间是紧密贴合的

标准流中的行内元素、行内块元素、块级元素加了浮动后,都会变成浮动元素,具备以上浮动元素的特性。

浮动的特点

浮动方向?

  • 垂直方向:向上浮动
  • 水平方向:如果float:left,则水平向左浮动,如果float:right,则水平向右浮动

浮动排列?

  • 浮动元素之间紧密贴合,不会发生覆盖现象。
  • 如果目前顶部的行的剩余宽度不足以放下新的浮动元素,则新的浮动元素自动另起一行排列。

浮动范围?

浮动元素的浮动范围受到其父级元素,和兄弟元素的影响:

浮动元素的浮动范围只能在其父级元素内部(无论父级在标准流还是在浮动流),并且浮动元素不会压住父级元素的border、padding,父级元素content中的行内元素、行内块元素的内容会自动围绕浮动元素排列

浮动元素本身就处于父级元素的content中,如果浮动元素存在兄弟元素:

如果兄弟元素也是浮动元素,则

前面的兄弟先浮动,后面的兄弟后浮动。

如果兄弟元素是非浮动元素,则

浮动元素不会上浮压住前面的非浮动兄弟元素,

而浮动元素脱标,会释放占据的标准流位置,所以浮动元素后面的非浮动兄弟会进据释放的位置,从而被浮动元素压住。

总结:浮动元素只会影响浮动元素后面的标准流,不会影响前面的标准流

浮动带来的问题:标准流父级容器高度塌陷

一般而言,我们不给标准流中父级容器设定height,而是让容器height自动适配为容器内容的高度,但是如果,此时有一个子级元素发生了浮动,则标准流中的父级容器的高度会发生塌陷

 原因是:标准流中父级容器的高度本来是由标准流中子级元素撑开的,但是当子级元素脱标后,对应标准流中的位置就会被释放,所以标准流中父级容器就没有内容了,此时父级容器的height就为0了。

清除浮动

清除浮动是为了解决:当子级元素浮动后,其标准流中高度自适应的父容器高度塌陷问题

方案1:让标准流中父容器变为BFC模式,这样就可以保证父容器中子元素渲染不会影响外界了(即:不会引起父容器高度变化)

前面学习将元素转为BFC渲染模式的方式有:

  • 元素变为浮动元素,即加float样式(非none)
  • 元素变为定位元素,即加position样式(值为absolute或fixed)
  • 元素变为弹性元素,即加display:flex
  • 元素加overflow样式(非visible)
  • 元素变为行内块显示模式

方案2:利用clear样式来清除浮动引起的父容器高度塌陷

在学习clear样式清除浮动影响前,我们要先了解clear样式

首先:

clear样式只能加给块级元素。对行内元素、行内块元素设置clear样式无效。

clear样式既可以加给浮动元素,也可以加给非浮动元素。

clear样式有三种常用值:

  • left
  • right
  • both

如果给浮动元素加clear样式,则含义是:

  • clear:left,表示保证当前元素左侧没有浮动元素
  • clear:right,表示保证当前元素右侧没有浮动元素
  • clear:both,表示保证当前元素两侧都没有浮动元素

box1,box2都是左浮动元素。

如果box2不加clear:left,理论上box1,box2应该左浮动到一行。

但是box2加了clear:left,所以要保证box2左侧无浮动元素,所以只能让box2换行排列。

box1是右浮动元素,box2是左浮动元素。

如果box2不加clear:right,则box1,box2应该在一行,并且box2在左侧,box1在右侧。

但是box2加了clear:right,所以要保证box2右侧无浮动元素,所以只能让box2换行排列。

box1是右浮动元素,box2、box3是左浮动元素。

如果box3不加clear:both,则box1,box2,box3应该排列在一行。

但是box3加了clear:both,所以要保证box3两端无浮动元素,所以只能让box3换行。

另外,我们需要注意下面这种情况

这里box1是右浮动元素 ,box2,box3是左浮动元素。

我们给box2加了clear:both,但是box2却依然和box3排列在一行,而没有保证box2右侧无浮动元素。

我个人理解原因应该是:浏览器按照从上到下顺序,依次渲染每个DOM元素的,当渲染到box2时,执行了clear:both,但是此时box2只有前面的box1右浮动元素,后面的box3还没有被渲染,所以此时clear:both只需要保证box2右侧无浮动元素即可,让其换行,然后clear:both工作结束。

之后,box3被渲染出来,进行左浮动。

所以我们应该将设置了clear样式的元素放在容器尾部。

如果给非浮动元素加clear样式,则含义是:

clear:left清除当前元素前面的,左浮动元素脱标后带来的影响(高度塌陷)
clear:right清除当前元素前面的,右浮动元素脱标后带来的影响(高度塌陷)
clear:both清除当前元素前面的,左、右浮动元素脱标后带来的影响(高度塌陷)

 可以发现,

非浮动元素上clear:left

  • 只能清除左浮动元素带来的影响(父容器高度保持)
  • 不能清除右浮动元素带来的影响(父容器高度塌陷)

同理,非浮动元素上clear:right也是如此。

而clear:both既可以清除左浮动元素脱标的影响,也可以清除右浮动元素脱标的影响。

另外需要注意的是,加了clear样式的元素只能清除位于它前面的浮动元素的影响,无法清除它后面的浮动元素的影响。

所以我们需要保证加了clear样式的元素在父容器尾部。 

因此,为了清除浮动带来的父容器高度塌陷影响,我们可以使用如下方案:

额外标签法:在父容器内容最后新增一个块级标签,并为其设置clear:both

 ::after伪元素法:为父容器新增一个::after伪元素,设置其显示模式为block,并为其设置clear:both

其中额外标签法会引入无关标签,破坏原有DOM结构,而::after伪元素法,不会引入无关标签,不会破坏DOM结构。

还有一种双伪元素法,即给父容器添加 ::before,::after伪元素,并在这两个伪元素上设置clear:both,以形成严格的浮动闭合。

但是我觉得有点多次一举了,因为clear:both只对它前面的浮动元素有效果,对后面的浮动元素无效果,所以::before伪元素清除浮动几乎没有任何效果。

浮动布局 + margin负值

浮动布局最出名的就是:圣杯布局和双飞翼布局。

圣杯布局和双飞翼布局,都属于三栏式布局,且都是两侧边栏宽度固定,中间内容区宽度自适应。

目前来看实现起来非常容易,借助CSS的calc函数和浮动即可:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
    }

    .container {
      width: 100%;
    }

    .container::after {
      content: "";
      display: block;
      clear: both;
    }

    .left-aside, .right-aside {
      width: 200px;
      height: 200px;
      float: left;
    }

    .left-aside {
      background-color: red;
    }

    .right-aside {
      background-color: blue;
    }

    .content {
      width: calc(100% - 400px);
      height: 200px;
      background-color: green;
      float: left;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="left-aside"></div>
    <div class="content"></div>
    <div class="right-aside"></div>
  </div>
</body>
</html>

但是圣杯和双飞翼都是上古时代的布局方式,那时候CSS还没有calc函数,所以实现起来要更加困难一点。

在上古时代,前端大能们巧妙地利用了margin负值来实现圣杯和双飞翼布局。

下面是圣杯布局的实现代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
    }

    .container {
      padding: 0 200px; /* 预留出左右padding,给left-aside,right-aside */
    }

    .container::after {
      content: "";
      display: block;
      clear: both;
    }

    .left-aside, .right-aside {
      float: left;
      width: 200px;
      height: 200px;
    }

    .left-aside {
      background-color: red;
      margin-left: -200px; /* 左移200px */
    }

    .right-aside {
      background-color: blue;
      margin-right: -200px; /* 右移200px */
    }

    .content {
      float: left;
      width: 100%;
      height: 200px;
      background-color: green;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="left-aside"></div>
    <div class="content"></div>
    <div class="right-aside"></div>
  </div>
</body>
</html>

效果和上面calc函数实现的效果一致。

这里内容区宽度自适应的逻辑是:

父容器不设置宽度,但是设置左右padding,左右padding的大小等于侧边栏的固定宽度。

父容器的内容区的width占满剩余宽度,即100%。

然后我们先将红色的left-aside向左移动200px,即margin-left:-200px 

 此时,发生了两件事:

  • left-aside左移了200px
  • content 再次向上浮动了一行!!!!

为什么content会再次向上浮动一行呢?

答案肯定是:顶部行的剩余宽度足够容纳content了

但是content宽度现在是是100%,自动占满剩余宽度,也就是说left-aside宽度为0了,content才有机会向上浮动一行。

那么为啥left-aside宽度为0呢?

其实这里说的left-aside宽度为0,

并不是指left-aside盒子的width为0,

而是指left-aside盒子的width+ 左右padding + 左右border + 左右margin = 0

有可能吗?

有,前面我们说过,margin和width、padding、border最大的区别在于:margin支持负值。

left-aside盒子的width+ 左右padding + 左右border + 左右margin = 0

是完全有可能的,我们看看当前left-aside盒子的实际数据:

  • width 值为200px
  • 左右padding 值为0
  • 左右border 值为0
  • margin-left 值为 -200px,margin-right 值为0

则它们的和为0。

所以同理,我们设置right-aside盒子的margin-left或margin-right也为-200px,就能让right-aside盒子的整体宽度为0,然后right-aside盒子也能继续上浮。

假设,我们设置right-aside盒子的margin-left为-200px

发现出问题了,蓝色的right-aside盒子虽然上浮了(因为整体宽度变为0),但是却没有覆盖父容器的padding-right区域,而是覆盖了content,这是为什么呢?

我们可以看下right-aside的盒子模型

可以发现盒子左侧margin-left:-200px和盒子内容width:200px抵消了

假设,right-aside盒子只margin-left:-199px,则此时right-aside盒子只被抵消了199px的盒子内容宽度,则还剩1px的内容宽度。

再假设,content所在行,还剩1px的剩余宽度,则right-aside盒子就可以上浮,并且肯定将自身1px有效区域放到content所在行剩余宽度1px中,而right-aside盒子其余199px无效区域只能覆盖在content身上。

 上面都理解了的话,我们可以继续抽象出一个0px的有效区域,200px的无效区域的right-aside盒子 放入了 content所在行的剩余宽度0px中。

到此,就完成了right-aside盒子为啥margin-left:-200px后,会压在content盒子上了。

所以我们应该很容易理解right-aside盒子margin-right:-200px后的样子

 此时right-aside盒子的0px有效区域,被上浮到了content所在行的0px剩余宽度中,则right-aside盒子的200px无效区域自然被压倒了父容器padding-right区域。

下面是双飞翼布局的实现代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    html, body {
      margin: 0;
      padding: 0;
    }

    .container {
      float: left;
      width: 100%;
    }

    .container::after {
      content: "";
      display: block;
      clear: both;
    }

    .left-aside, .right-aside {
      float: left;
      width: 200px;
      height: 200px;
    }

    .left-aside {
      margin-left: -100%;
      background-color: red;
    }

    .right-aside {
      margin-left: -200px;
      background-color: blue;
    }

    .content {
      padding: 0 200px;
      height: 200px;
      background-color: green;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="content"></div>
  </div>
  <div class="left-aside"></div>
  <div class="right-aside"></div>
</body>
</html>

双飞翼布局和圣杯布局的表现效果相同,并且实现原理也一样,都是依赖于float + margin负值,二者的区别在于双飞翼的布局结构更复杂一点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/407901.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【玩转CSS】学成在线(文末素材源码自取)

&#x1f525;一个人走得远了&#xff0c;就会忘记自己为了什么而出发&#xff0c;希望你可以不忘初心&#xff0c;不要随波逐流&#xff0c;一直走下去&#x1f3b6; &#x1f98b; 欢迎关注&#x1f5b1;点赞&#x1f44d;收藏&#x1f31f;留言&#x1f43e; &#x1f984; …

vue监听缓存数据(localStorage) 中值的更新

2个vue组件之间数据同步&#xff0c;可以通过监听localStorage数据变化&#xff0c;来改变数据的值。 方法&#xff1a;可以重写localStorage的setItem方法&#xff0c;当调用setItem方法设置新值的时候&#xff0c;会new Event(setItemEvent) 用window.dispatchEvent()这个…

vue 项目兼容 IE 浏览器

前言 : 网上 找了很多关于 vue项目兼容 IE 浏览器的 教程步骤 , 写的 非常详细 , 但根据我自己的项目,怎么找 都没有找到 webpack.base.conf.js 这个文件 ,就没办法配置 因为 vue-cli最新版本原因 , 隐藏了配置文件, 所有的 都在 vue.config.js中配置 可以根据自己的 vue-cli 版…

手摸手带你玩转Vue3——Vue2升级Vue3

今年年初&#xff0c;尤大大公布了一个重磅消息&#xff0c;将Vue3作为Vue的默认版本。 这无疑不是对我们开发人员的内卷煽风点火&#xff01; vue默认版本改动意味着&#xff0c;官方将会把Vue研发重心放到vue3上&#xff0c;vue2也开始走下坡路&#xff0c;至于淘汰过时只是…

前端插件库之vue3使用element-plus实现登录、注册页面和忘记密码弹窗,以及已有样式的覆盖

vue3使用element-plus实现登录/注册页面登录/注册页面组件预览添加忘记密码弹窗预览已有样式的修改1.字体大小2.router-link默认样式登录/注册页面组件 vue3 的登录和注册页面 目前只有框架和函数框架, 根据具体需要填充, 已有功能: 1.没有勾选同意使用手册, 登录和注册按钮是…

后端返回各种图片形式在前端的转换及展示

一、 接口返回的图片显示如下所示&#xff1a;&#xff08;在控制台看的&#xff09;返回的是这个图片&#xff08;二进制&#xff09; 可是&#xff0c;在 打印的时候&#xff0c;返回的却是 出现问题的原因的axios 默认返回的是 json 文本形式&#xff0c;二进制图片数据被强…

TS复习-----TS中的函数

目录 一、ts函数的定义 二、ts中定义函数传参 1.函数传参方法 2.可选参数 3.默认参数 4.剩余参数 函数重载 一、ts函数的定义 函数是一种特殊的对象&#xff0c;可以被调用。TS 里的函数和原生&#xff0c;ES 6 里的函数差不太多&#xff0c;只是多了一些其他功能。 //…

HTML入门学习笔记+详细案例

✨HTML入门学习笔记详细案例 作者介绍: &#x1f393;作者:偷偷敲代码的青花瓷&#x1f431;‍&#x1f680; &#x1f440;作者的Gitee:代码仓库 ✨✨我和大家一样都是热爱编程✨,很高兴能在此和大家分享知识,希望在分享知识的同时,能和大家一起共同进步,取得好成绩&#x1f9…

实现H5和小程序之间相互跳转

功能描述&#xff1a; 1、 当点击理赔服务的时候&#xff0c;跳转到小程序页面 2、 当点击返回的时候&#xff0c;从小程序跳回H5页面&#xff08;内嵌H5以及关闭小程序&#xff09; 功能1&#xff1a;H5跳转小程序 vue中实现步骤 在 template 标签中写html <wx-open-lau…

【Maven】maven安装、IDEA创建maven的web项目、添加依赖、集成Tomcat

学习目录前言maven简介maven的下载与安装优化配置参数1.修改本地仓库路径2.设置阿里云私服镜像3.指定JDK版本IDEA创建第一个maven的web项目IDEA集成TomcatHello java&#xff01;前言 朋友们在写后端的过程中&#xff0c;遇到功能复杂的业务时需要导入不同的jar包&#xff0c;…

Logging system failed to initialize using configuration from ‘classpathlogbacklogback-spring.xml‘

2021-12-31&#xff1a; 项目在Windows系统上可以正常运行,然而移到Mac系统上运行出现一下报错!! 据报错信息显示,初始化“logback-spring.xml”失败,监测到“Logback”配置出错,非法的声明异常, 创建“[/apps/logs/sns_error.log]”的父目录失败… 主要原因是初始化配置文…

[暑假]Vue生命周期-笔记

什么是生命周期? 生命周期: 又名: 生命周期回调函数, 生命周期函数, 生命周期钩子. 所谓的生命周期函数, 就是Vue在关键时刻帮我们调用的一些特殊名称的函数 生命周期函数的名字不可更改, 但是函数的具体内容是程序员根据需求编写的 生命周期函数中的 this 指向是 vm 或 组件…

CSS样式:渐变色圆角边框

目录预期效果解决方法1.两层元素&#xff1a;外层渐变背景圆角内边距&#xff0c;里层圆角背景色2.伪元素&#xff1a;background-clip属性伪元素定位元素本身背景&#xff08;以伪元素背景色做边框&#xff09;3.单层元素&#xff1a; background-clipbackground-iamgebackgro…

PDF.js 预览pdf文件流预览pdf,及ie浏览器兼容性问题,解决方案!!(开发笔记)

一、 官网下载pdf.js &#xff1a;Getting Started 注意&#xff1a; 这俩包 都不支持ie&#xff0c;因为用的是es6&#xff0c;ie解析不出来 下完以后引进去。下面为省事 找几个市面上常用的方法&#xff1a; 1、文件流转base64的 这是在自己的js请求里面 //PDFdata 是a…

Nginx超时配置

Nginx主要有四类超时设置&#xff1a;客户端超时设置、DNS解析超时设置、代理超时设置&#xff0c;如果使用ngx_lua&#xff0c;则还有lua相关的超时设置。 1&#xff0e;客户端超时设置 对于客户端超时主要设置有读取请求头超时时间、读取请求体超时时间、发送响应超时时间、…

vue项目 升级依赖包

项目维护过程中&#xff0c;可能会因为依赖包存在漏洞而升级依赖&#xff0c;或者因为需要高本版中提供的新特性而升级依赖。 在升级依赖之前&#xff0c;可以先执行 npm outdated 命令&#xff0c;查看当前哪些已安装软件包版本过时了。 标签释义current代表当前版本号want…

【面试】什么是网关/服务网关?网关/服务网关的作用是什么?

文章目录一、前言二、网关2.1 什么是网关&#xff1f;2.2 网关的作用是什么&#xff1f;2.3 网关的工作流程2.4 软件系统网关三、什么是服务网关四、为什么需要服务网关五、服务网关应用一、前言 对于网关&#xff0c;从专业角度&#xff0c;一般运维和网络管理员会比较了解一…

vant官网-vant ui 首页-移动端Vue组件库

Vant 是有赞前端团队开源的移动端vue组件库&#xff0c;适用于手机端h5页面。 鉴于百度搜索不到vant官方网址&#xff0c;分享一下vant组件库官网地址&#xff0c;方便新手使用 vant官网地址https://vant-contrib.gitee.io/vant/#/zh-CN/ 通过 npm 安装 在现有项目中使用 V…

【JavaScript】JS实用案例分享:输入智能提示 | 打字机输出效果

CSDN话题挑战赛第2期 参赛话题&#xff1a;学习笔记 &#x1f5a5;️ NodeJS专栏&#xff1a;Node.js从入门到精通 &#x1f5a5;️ 博主的前端之路&#xff08;源创征文一等奖作品&#xff09;&#xff1a;前端之行&#xff0c;任重道远&#xff08;来自大三学长的万字自述&am…

前端Vue之发布订阅模式

目录 1.什么是发布订阅模式 2.实现简单的发布订阅 3.收集更新函数 4.触发更新函数 5.总结 一个响应式数据可能会有多个视图部分都需要依赖&#xff0c;也就是响应式数据变化之后&#xff0c;需要执行的更新函数可能不止一个&#xff0c;对于这种情况&#xff0c;有必要学习…