深入理解浮动元素与margin负值用法及三栏布局

浮动元素与margin负值使用

正常两个浮动元素

首先给元素设置浮动以后,元素就会变成块级元素

  <div class="content">
      <div class="middle">123456789123456789123456789123456789</div>
      <div class="left">111</div>
  </div>

  .content {
      width: 600px;
      height: 300px;
      background-color: green;
      margin: 100px auto;
      color: white;
      overflow: hidden;  //超出隐藏
      font-size: 50px;
  }

  .middle {
      float: left;
      width: 400px;
      height: 300px;
      word-break: break-all;
      background-color: blue;
  }

  .left {
      float: left;
      width: 100px;
      content: '';
      height: 300px;
      background-color: black;
  }

如图
给 middle 元素设置属性
在这里插入图片描述
图1: 为默认浮动
图2: 给 middle 元素添加margin-left:-200px,因为给 content 元素设置了 overflow: hidden 所以 middle 元素向左移动200px后,左边超出的部分将被隐藏
图3: 给 middle 元素添加margin-right:-200px

给 middle 元素添加margin-right:-200px,为什么 left 元素会覆盖到 middle 元素上呢?

因为一个盒子 总宽度 = 内容宽度 + 左填充 + 右填充 + 左边框 + 右边框 + 左边距 + 右边距
当我们给 middle 元素设置 margin-right: -200px 后,middle元素的实际总宽度 = 400 + (-200) = 200

1: 给元素设置margin只会影响相邻元素摆放位置、自己的摆放位置、自己的总宽度、自己的总高度,并不会影响自己的内容宽度或高度的显示。
2: 给元素margin-left、margin-right设置负值,不会影响内容宽度显示,但元素总宽度会改变,每个元素的摆放位置是根据总宽度、总高度来进行摆放的,虽然元素的内容宽高会完全显示,但设置负值的那部分距离对其它元素位置摆放没有影响,这部分距离是显示在相邻元素的上边还是下边,是要根据每个元素的层级来决定的。

两个左浮动元素

如果一行剩余宽度无法容下接下来的浮动元素,那么浮动元素会掉下来

<div class="content">
    <div class="middle"></div>
    <div class="left"></div>
</div>

  .content {
      width: 600px;
      height: 600px;
      background-color: green;
      margin: 100px auto;
  }

  .middle {
      float: left;
      width: 500px;
      height: 200px;
      background-color: blue;
  }

  .left {
      float: left;
      width: 200px;
      height: 200px;
      background-color: black;
  }

没有给 content 容器设置overflow: hidden,所以超出去的部分会显示出来
给left元素设置margin-left值如图
在这里插入图片描述
图1: left元素掉下来很好理解
图2: 给元素设置margin-left:200px后,元素向右移动200px
图3: 给元素设置margin-left:-99px后,元素向左移动99px
图4: 给元素设置margin-left:-100px后,left元素跑上去了,是不是很神奇?
如果你是从头开始看这篇文章的,那么应该很好理解,left现在的总宽度 = 200 + (-100) = 100,
而第一行正好剩余了 100px 的空间,所以left元素必须上去,那为什么left元素的右边和content容器右边对齐了,而不是left元素左边和middle的右边对齐呢?因为给left元素设置margin-left负值后,元素的总宽度变小了,而总宽度减少的这部分也就是margin-left设置负值的这部分,不会影响各个元素位置摆放且内容宽度也必须要显示出来,由后边的浮动会盖住前边的浮动元素,所以元素的右边和容器右边就对齐了。
图5: 给元素设置margin-left:-500px后,left元素左边和content容器左边对齐了,看完图4的解释,其实图5就很好理解了,现在left总宽度 = 200 + (-500) = -300,当left元素宽度为0时,left元素的右边界是和middle右边界对齐的,现在把left元素再向左移动300px,则left元素的右边界就要向左移动300px距离,所以就出现图5这种显示效果
图6: 给元素设置margin-left:-100%后,这里 100% 是基于父元素的宽度的设置的外边距,等同于margin-left:-600px,再根据图5的分析就很好理解了

给left元素设置margin-right值如图
在这里插入图片描述
图7: 给元素设置margin-right:100px后,元素位置不动,但总宽度 = 200 + 100 = 300
图8: 给元素设置margin-right:-99px后,元素位置不动,因为在文档流中它是应该向右移动99px,但元素设置了左浮动,所以就又把元素拉回来了,这和设置margin-left:-99px是有区别的
图9: 给元素设置margin-right:-100px后,元素跑上去了且元素左边界和middle右边界对齐。因为left元素总宽度 = 200 + (-100) =100,而第一行正好剩余了 100px 的空间,所以left元素必须上去,而总宽度减少的 100px 是不影响各个元素位置摆放的,我们可以把他理解成是透明的,而剩下的 100px 刚好装到第一行剩余的位置,但由于margin值不会影响元素内容区域宽高的显示,所以就如图9的效果了
图10: 给元素设置margin-right:-500px后,元素跑上去了且元素左边界和middle右边界对齐。这里是不是很奇怪?给元素设置margin-left:-500px后,元素应该覆盖到middle元素上啊,为什么设置margin-right:-500px而不会向左覆盖呢?此时元素的总宽度为 -300px,因为设置的是margin-right,所以元素的左边应该是要从middle元素从左往右数的200px处开始显示啊?这里我的理解是,当设置margin-right:-200px时,此时元素的总宽度为0,left元素的左边和middle元素的右边对齐,此时我们再增加margin-right负值时,
元素其实是要向右移动,但是它又有左浮动限制,所以就又紧贴 middle 元素,但当设置margin-left负值时,正好和浮动方向一致,所以就会覆盖元素了。总感觉这种理解有点牵强,希望有明白的大神帮忙解释下吧

这里先记住结论吧

  • 当元素的浮动方向和margin的方向相同时,该元素可以覆盖或远离上一个浮动元素
  • 当元素的浮动方向和margin的方向相反时,该元素不能覆盖上一个浮动元素,最近只能紧贴上一个元素右边

两个右浮动元素

如果一行剩余宽度无法容下接下来的浮动元素,那么浮动元素会掉下来

  <div class="content">
      <div class="middle"></div>
      <div class="left"></div>
  </div>

  .content {
      width: 600px;
      height: 600px;
      background-color: green;
      margin: 100px auto;
  }

  .middle {
      float: right;
      width: 500px;
      height: 200px;
      background-color: blue;
  }

  .left {
      float: right;
      width: 200px;
      height: 200px;
      background-color: black;
  }

给left元素设置margin-right值
在这里插入图片描述

给left元素设置margin-left值
在这里插入图片描述

这里各个效果和两个左浮动元素效果正好相反,可以结合上面去理解

单行多行省略号

单行文本溢出显示省略号

  overflow: hidden;  //超出设定宽度隐藏
  text-overflow: ellipsis; //超出文本文末显示省略号
  white-space: nowrap; //不换行

多行文本溢出显示省略号-webkit内核专用

  p {
      width: 200px;
      overflow: hidden;
      text-overflow: ellipsis;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
  }
  <p>我有一个梦像雨后彩虹,用所有泪水换来笑容,还有一种爱穿越了人海,拾起那颗迷失的尘埃。</p>

这三个属性需要结合使用,仅适用于WebKit浏览器及移动端

  • -webkit-line-clamp: 2; //设置文本行数
  • display: -webkit-box; //设置弹性盒子
  • -webkit-box-orient: vertical; //排列方式
    如图
    在这里插入图片描述

通用-多行文本溢出显示省略号

  .wrap {
      width: 200px;
      height: 50px;
      margin: 100px auto;
      overflow: hidden;
  }

  .before {
      float: left;
      width: 1px;
      height: 50px;
      content: '';
  }

  .content {
      float: right;
      width: 100%;
      line-height: 25px;
      margin-left: -1px;
      word-break: break-all;
  }

  .after {
      float: right;
      width: 20px;
      height: 25px;
      line-height: 25px;
      content: '...';
      margin-left: -20px;
      padding-right: 1px;
      position: relative;
      left: 100%;
      top: -25px;
      background-color: white;
      box-shadow: -10px 0 10px white;
  }

  <div class="wrap">
      <i class="before"></i>
      <div class="content">我有一个梦像雨后彩虹,用所有泪水换来笑容,还有一种爱穿越了人海,拾起那颗迷失的尘埃。</div>
      <i class="after">...</i>
  </div>

如图
在这里插入图片描述
分步解释
在这里插入图片描述
图1: 当只给before、content、after元素设置左浮动,右浮动、右浮动时,就如图1所示,都各占一行,因为content元素宽度为100%,第一行无法容下,只能另起一行
图2: 当给content元素设置margin-left: -1px时,它的总宽度 = 200 + (-1) = 199,这里宽度100%相当于父元素的宽度,也就是200px,因为before这一行剩余宽度正好是199px,所以content元素会跑上去,又因向左移动了1像素,所以会占满整个宽度
图3: 当给after元素设置margin-left: -20px时,它的总宽度 = 20 + (-20) = 0,这时总宽度已为0,又因为是右浮动,所以就会跟随在content元素的左边显示
图4: 当再给after元素设置padding-right: 1px时,此时它的总宽度 = 20 + (-20) + 1 = 1,这时总宽度为1,而before元素在的这一行,正好放下before、content两个元素,没有多余的空间了,又因content元素现在还没有超过固定高度(50px) ,after又是右浮动,所以就如图4显示了,但after元素的总显示宽度变大了,为什么要写padding-right: 1px呢?大家先想想,稍后解释。
图5: 当content元素超过固定高度时(50px),此时因before元素只有50px,这时content元素左边就有了1px的空间,而根据图4计算,此时after元素总宽度为1px,所以就如图5显示
图6: 当给after元素添加上position、left、top属性后,content元素未超过固定高度时,就如图6显示
图7: 当给after元素添加上position、left、top属性后,content元素超过固定高度时,就如图7显示,省略号就正常显示了

最后一步: 给外层的wrap容器设置overflow: hidden,则content元素超出部分隐藏,after元素根据情况显示。
如图
在这里插入图片描述

为什么给after元素添加padding-right: 1px呢?
如果你知道为什么设置是1px,而不是10px、20px,那么你肯定就知道为什么要设置这个属性了。
这里padding-right设置的值就是before元素的宽度,也就是图7超出的黄色部分,而具体内容会在里边的黄色部分显示,如果不设置这个属性,就会如图3所示,省略号无法正常显示。

如果把after元素设置成左浮动可以吗?
当content元素超过固定高度时,after元素设置成左浮动或右浮动如果不加position属性时都会如图5显示,加上position都会如图7显示,所以省略号可以正常显示
当content元素没超过固定高度时,after元素因为是左浮动再加上position属性,则会一直显示省略号,所以不符合需求,此时不能左浮动

如果把content元素设置成左浮动可以吗?
不可以,具体大家自己脑补下吧,如果设置左浮动那结果就会类似用如图6显示

注意
1: 给content元素设置word-break: break-all,防止最后一个单词过长引起换行导致省略号与上一个单词距离过长
2: 给after元素设置box-shadow: -10px 0 10px white,使单词与省略号之间过度看起来更自然,缓解单词被遮挡半个的突兀感

通用-多行文本溢出显示省略号(伪元素推荐)

  .wrap {
      width: 200px;
      height: 50px;
      margin: 100px auto;
      background-color: white;
      overflow: hidden;
  }

  .wrap::before {
      float: left;
      width: 1px;
      height: 50px;
      content: '';
  }

  .content {
      float: right;
      width: 100%;
      line-height: 25px;
      margin-left: -1px;
      word-break: break-all;
  }

  .wrap::after {
      float: right;
      width: 20px;
      height: 25px;
      line-height: 25px;
      content: '...';
      margin-left: -20px;
      padding-right: 1px;
      position: relative;
      left: 100%;
      top: -25px;
      background-color: white;
      box-shadow: -10px 0 10px white;
  }

  <div class="wrap">
    <div class="content">我有一个梦像雨后彩虹,用所有泪水换来笑容,还有一种爱穿越了人海,拾起那颗迷失的尘埃。</div>
  </div>

如图:
在这里插入图片描述

三栏布局

圣杯布局

中间宽度自适应,两边内容定宽,中间内容优先渲染

<!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>圣杯布局</title>
     <style type="text/css">
         * {
             padding: 0;
             margin: 0;
         }
 
         body {
             min-width: 600px;
         }
 
         header, footer {
             height: 20px;
             background: pink;
         }
 
         .wrap {
             padding: 0 200px;
             overflow: hidden;
         }
 
         .middle {
             float: left;
             width: 100%;
             background-color: red;
         }
 
         .left {
             float: left;
             width: 200px;
             margin-left: -100%;
             background-color: yellow;
             position: relative;
             left: -200px;
         }
 
         .right {
             float: left;
             width: 200px;
             margin-left: -200px;
             background-color: green;
             position: relative;
             right: -200px;
         }
     </style>
 </head>
 <body>
 <header>header</header>
 <div class="wrap">
     <div class="middle">middle</div>
     <div class="left">left</div>
     <div class="right">right</div>
 </div>
 <footer>footer</footer>
 </body>
 </html>

分步解析
1: middle、left、right三个元素都设置左浮动
2: left元素设置margin-left:-100%则left元素会和middle元素在一行显示并左对齐
3: right元素设置margin-left:-200px则right元素右边和middle元素右边在一行对齐,此时如果设置margin-right:-200px则right左边和middle右边在一行对齐,此时就会超出一屏,不符合需求
4: left、right元素会覆盖在middle元素上,所以给wrap元素设置padding: 0 200px再通过relative相对定位方式把两边元素移动到两侧

给middle元素添加padding可以吗?
去除wrap容器的padding:0 200px属性和left、right元素的相对定位,而给 middle 元素添加以下属性也可以

  padding: 0 200px;
  box-sizing: border-box;

但是如果需要要给middle元素添加背景图、背景色,那两边元素就会遮挡它,不便于展示,所以采用的相对定位方式

优点
优先渲染主内容区域,不需要添加额外的dom节点
缺点
当middle元素宽小于left元素宽度时,布局混乱
因为left元素设置margin-left:-100%,这里的100%是基于父元素内容宽度的100%,因middle也设置了宽度width: 100%,所以也可以说是基于
middle元素的宽度。当middle元素大于等于left元素时,left总宽度 = 200 + (-(大于200)) < 0 ,则布局不混乱
当middle元素小于left元素时,left总宽度 = 200 + (-(小于200)) > 0,因middle占满了一行,只有宽度小于等于0的元素才能和它同一行,此时
left元素总宽度大于0,则left元素只能在第二行显示。

right元素宽度对布局有没有影响?
没有,因为right元素设置的宽度和margin-left值相同,所以right总宽度始终等于0,所以在没有相对定位的情况下,right元素的右边始终和middle元素右边对齐

注意
圣杯布局需要设置body的最小宽度,否则在middle元素小于left元素宽度时,布局会混乱,
body最小宽度 = left宽度 + middle最小宽度(left宽度) + right宽度
这里需要设置为600

  body {
     min-width: 600px;
  }

双飞燕布局

中间宽度自适应,两边内容定宽,中间内容优先渲染

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>双飞燕布局</title>
     <style type="text/css">
         * {
             padding: 0;
             margin: 0;
         }
 
         header, footer {
             height: 20px;
             background: pink;
         }
 
         .wrap {
             overflow: hidden;
         }
 
         .middle {
             float: left;
             width: 100%;
             background-color: red;
         }
 
         .middle-wrap {
             margin: 0 200px;
             background-color: purple;
         }
 
         .left {
             float: left;
             width: 200px;
             margin-left: -100%;
             background-color: yellow;
         }
 
         .right {
             float: left;
             width: 200px;
             margin-left: -200px;
             background-color: green;
         }
     </style>
 </head>
 <body>
 <header>header</header>
 <div class="wrap">
     <div class="middle">
         <div class="middle-wrap">middle</div>
     </div>
     <div class="left">left</div>
     <div class="right">right</div>
 </div>
 <footer>footer</footer>
 </body>
 </html>

分步解析
1: middle、left、right三个元素都设置左浮动
2: left元素设置margin-left:-100%则left元素会和middle元素在一行显示并左对齐
3: right元素设置margin-left:-200px则right元素右边和middle元素右边在一行对齐,此时如果设置margin-right:-200px则right左边和middle右边在一行对齐,此时就会超出一屏,不符合需求
4: left、right元素都是覆盖在middle元素上显示,为了避免middle元素内容被遮挡,则给middle元素内又添加了一层,通过给middle-wrap元素设置margin左右外边距解决遮挡问题,

优点
优先渲染主内容区域,通用性强,不需要设置body最小宽度
缺点
dom多了一层,增加渲染树生成计算量

提示
虽然双飞翼布局不需要设置body最小宽度,但建议也设置上。

绝对定位-三栏布局

 <!DOCTYPE html>
 <html lang="en">
 <head>
     <meta charset="UTF-8">
     <title>绝对定位三栏布局</title>
     <style type="text/css">
 
         header, footer {
             height: 20px;
             background: pink;
         }
 
         .wrap {
             position: relative;
         }
 
         .middle {
             height: 20px;
             margin: 0 200px;
             background-color: red;
         }
 
         .left {
             width: 200px;
             height: 20px;
             background-color: yellow;
             position: absolute;
             top: 0;
             left: 0;
         }
 
         .right {
             width: 200px;
             height: 70px;
             background-color: green;
             position: absolute;
             top: 0;
             right: 0;
         }
     </style>
 </head>
 <body>
 <header>header</header>
 <div class="wrap">
     <div class="middle">middle</div>
     <div class="left">left</div>
     <div class="right">right</div>
 </div>
 <footer>footer</footer>
 </body>
 </html>

虽然可以实现三栏布局,但缺点是两侧left、right元素高度无法撑起wrap容器总高度,而圣杯布局和双飞翼布局都可以撑起高度。
如图右侧right元素无法撑起总高度
在这里插入图片描述

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值