mengtuifrontend / Blog

芦叶满汀洲,寒沙带浅流。二十年重过南楼。柳下系船犹未稳,能几日,又中秋。 黄鹤断矶头,故人今在否?旧江山浑是新愁。欲买桂花同载酒,终不似,少年游。
18 stars 5 forks source link

CSS 世界 —— 流的破坏和保护 #28

Open shenxuxiang opened 5 years ago

shenxuxiang commented 5 years ago

流的破坏和保护

魔鬼属性 float

float 属性设计的目的就是为了实现文字环绕效果。这种文字环绕,主要就是指文字环绕图片显示的效果。所以 float 并不是用来实现复杂的页面布局的,况且,使用 float 会带来一些意想不到的结果。例如 导致父元素的高度塌陷。

float 具有哪些特性

包裹性

这里的包裹性由两部分组成:“包裹” 和 “自适应性”。也就是说 float 元素的宽度就是 border-box(包裹),同时这个宽度总是小于等于父容器的宽度(自适应)。但是有一种情况比较例外,就是 float 元素内部都是一连串的数字或英文字母,那么这个时候元素的宽度就会超过父容器的宽度

  <div class="demo">
    <span>xsdhdfdsfdsfdsfdsfdsfdsfdsfsdfdsfdsfdsfdsfdsfdsfg</span>
  </div>
  .demo {
    width: 200px;
    height: 100px;
    margin: 30px;
    font-size: 14px;
    line-height: 1.5;
    border: 1px solid #ddd;
  }
  .demo span {
    float: left;
  }
  <div class="demo">
    <img src="./static/img/timg.jpg" alt="" height="50">
    <span>对双方都十分舒服的沙发舒服的沙发都十分的是非得失</span>
  </div>
  .demo {
    width: 200px;
    height: 100px;
    margin: 30px;
    font-size: 14px;
    line-height: 1.5;
    border: 1px solid #ddd;
  }
  .demo span {
    float: left;
  }
块状化并格式化上下文

会将元素的 display 变成 block 或者 table

破坏文档流

会将元素从正常的文档流中脱离,float 元素的布局和正常元素布局是一样的,但是不会占据空间位置

  <div class="demo">
    <div style="height: 50px; background: #ccc"></div>
    <div class="float"></div>
  </div>

  <div class="demo">
    <div class="float"></div>
    <div style="height: 50px; background: #ccc"></div>
  </div>

第一个 demo 中,float 元素在正常元素的后面,表现为 float 在下面,和正常布局一样 第二个 demo 中,float 元素在正常元素的前面,表现为 float 和正常元素重合了,这是因为 float 元素不占据流的空间位置导致的。

没有任何 margin 合并

float 作用机制

我们知道 float 属性设计的目的就是为了实现文字环绕效果。但是又该如何实现这种效果呢??父元素的高度塌陷??对,就是这个特性。但这只是其中的一个,还有另外一个条件,我们先看看下面的 demo

  <div>
    <img src="./static/img/timg.jpg" alt="" class="float">
  </div>
  <p>房间划分为花椒粉胡椒粉看韩剧晚饭后恢复可望恢复肌肤健康护肤课和我分开和晚饭健康无烦恼接口和方法尽快恢复健康护肤</p>

“高度塌陷” 只是让跟随的内容可以和浮动的元素在一个水平线上,但这只是实现 “环绕效果” 的条件之一,想要实现正真的 “环绕效果”,就需要另外一个条件 “行框盒子和浮动元素的不可重叠性”,也就是 “行框盒子如果和浮动元素的垂直高度有重叠,则行框盒子在正常定位状态下只会跟随浮动元素,而不会发生重叠”

  <div class="demo">
    <div class="float">
    </div>
    <div style="background: #ccc">sdhjfhfh搜附近的健身房回复是否会尽快回复空间划分双方还将恢复健康回复快回复快回复客户</div>
  </div>
  .demo {
    width: 200px;
    height: 100px;
    margin: 30px;
    font-size: 14px;
    line-height: 1.5;
    border: 1px solid #ddd;
  }
  .float {
    float: left;
    width: 100px;
    height: 40px;
    background: #f80;
    opacity: .1;
  }

从上面的这个 demo 的表现来看,完全符合 “行框盒子和浮动元素的不可重叠性”,同样实现了文字环绕。 注意: 只有行框盒子和浮动元素不发生重叠,行框盒子外部的父元素 (“块级元素”)完全和浮动元素重叠了。

还有一种情况就是 “父元素的高度塌陷”,那么如果我们设置父元素的 height 呢,不就可以避免这种情况了吗??答案是:可以的,但是必须要保证父元素的高度必须完全大于等于 float 的元素,否则还是没有办法避免

  <div style="height: 35px;">
    <img src="./static/img/timg.jpg" alt="" class="float">
  </div>
  <div>房间划分为花椒粉胡椒粉看韩剧晚饭后恢复可望恢复肌肤健康护肤课和我分开和晚饭健康无烦恼接口和方法尽快恢复健康护肤</div>

上面的 demo 就完全解释了这中现象

浮动参考

有种情况,就是和浮动元素相邻的是 "内联元素" 的时候,而且内联元素还存在换行的情况,那么这个时候 float 元素如何定位??

  <div style="height: 35px;">
    房间划分为花椒粉胡椒粉看韩剧晚饭后恢复可望恢复肌肤健康护肤课和我分开和晚饭健康无烦恼接口和方法尽快恢复健康护肤
    <span class="float">xxxx</span>
  </div>

  <div style="height: 35px;">
    <span class="float">xxxx</span>
    房间划分为花椒粉胡椒粉看韩剧晚饭后恢复可望恢复肌肤健康护肤课和我分开和晚饭健康无烦恼接口和方法尽快恢复健康护肤
  </div>

在 CSS 世界中, float 元素的 “浮动参考” 是 “行框盒子”,也就说 float 元素在当前 “行框盒子” 内定位。在强调一遍,是 “行框盒子”,不是外面的包含块盒子之类的东西,因为 CSS 浮动设计的初衷仅仅是实现文字环绕效果。

clear

官方对 clear 的解释是: 元素盒子的边不能和前面的浮动元素相邻。

对于设置了 clear 属性的元素只是对自身产生影响,而不是让其他的元素如何如何

  <div style="height: 200px;">
    <div class="float">1</div>
    <div class="float">2</div>
    <div class="float clear">3</div>
    <div class="float">4</div>
    <div class="float">5</div>
    <div class="float">6</div>
    <div class="float">7</div>
    <div class="float">8</div>
  </div>
  .float {
    float: left;
    width: 50px;
    height: 40px;
    background: #f80;
    opacity: 1;
    margin-left: 10px;
  }
  .clear {
    clear: both;
  }

上面的这个 demo 表现为两行显示,第三个元素设置了 clear。但是这只能让自身不能和前面的浮动元素相邻,注意这里 “前面的” 三个字,也就是说,他对后面的浮动元素是不影响的。

clear 属性只有在块级元素中才能有效,而 ::after 等伪元素默认都是内联水平,这就是为什么需要借助伪元素清楚浮动时需要设置 display: table | block 的原因。

BFC 会计格式化上下文

如果一个元素具有 BFC,那么它内部的子元素再怎么翻江倒海,都不会影响到外部的元素。所以,BFC 元素是不可能发生 margin 合并的,应为 margin 的合并会影响到外面的元素;BFC 元素还可以用来清除浮动的影响,因为如果不清楚,字元素浮动,则父元素高度塌陷,也会影响到外面元素的布局。

哪些情况会触发我 BFC 呢?

我们在之前的章节就已经使用过 BFC 了。比如说 双飞翼布局/左边自适应/右边自适应

  <div style="height: 100px; background: #455">
    <img src="./img/timg.jpg" alt="" style="width: 100px; float: right">
    <div style="overflow: auto; background: #ccc">左边自适应</div>
  </div>

  <div style="height: 100px; background: #455">
    <img src="./img/timg.jpg" alt="" style="width: 100px; float: left">
    <div style="overflow: auto; background: #ccc">右边自适应</div>
  </div>

overflow

了解 overflow-xoverflow-y

注意: 如果 overflow-x、overflow-y 属性值中有一个是 visible,而另一个是 scroll/hidden/auto 其中的一个 。则 visible 的样式就会变成 auto。也就是说,除非 overflow-x | overflow-y 的属性值都是 visible,否则 visible 会当成 auto 来解析。

简单说就是,永远不可能实现一个方向溢出剪切或者滚动,另一个方向内容溢出显示的效果

  ::-webkit-scrollbar { // 血槽宽度 
    width: 8px;
    height: 8px;
  }
  ::-webkit-scrollbar-thumb { // 滚动条样式
    background: rgba(0, 0, 0, .3);
    border-radius: 6px;
  }
  ::-webkit-scrollbar-track { // 背景槽样式
    background: #ddd;
    border-radius: 6px;
  }

  // 实现多行的 ...
  .clamp {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }

  // 实现单行的 ... 
  .clamp {
    font-size: 14px;
    text-overflow: ellipsis;
    white-space: nowrap;
    overflow: hidden;
  }

overflow 与 锚点定位

锚点定位有两种情况

锚点定位也可以发生在普通的元素中,而且定位发生的行为是 “由内而外” 的。

  <div style="overflow: auto; height: 150px; border: 1px solid #ddd">
    <div style="height: 300px; background: red"></div>
    <div id="title">title</div>
  </div>
  <a href="#title">title</a>

“由内而外” 的意思是,如果我们点击了 title 按钮,<div> 元素内部先开始滚动,当元素 title 滚动到父元素可视区顶部的位置的时候,文档开始滚动,滚动到 title 元素的上边缘和屏幕上边缘对齐,这个时候就完成了。

注意: 元素设置了 overflow: hidden 也是可以 “滚动” 的,只是这个时候无法手动滑动滚动,而只能通过 JS 控制,或者锚点定位。

下面这个 demo 就是通过锚点实现的,每次定位都要滚动到可视区顶部。

  <div class="wrapper">
    <div class="list" id="list_1">1</div>
    <div class="list" id="list_2">2</div>
    <div class="list" id="list_3">3</div>
    <div class="list" id="list_4">4</div>
  </div>
  <a href="#list_1">1</a>
  <a href="#list_2">2</a>
  <a href="#list_3">3</a>
  <a href="#list_4">4</a>
  .wrapper {
    width: 300px;
    height: 200px;
    background: #ccc;
    white-space: nowrap;
    overflow: hidden;
    font-size: 0;
  }
  .list {
    font-size: 14px;
    display: inline-block;
    width: 100%;
    height: 200px;
    background: #666;
  }

使用下面这种方式就可以完全避免上面的问题了

  <div class="wrapper">
    <div class="list">
      <input type="text" class="input" id="list_1">
      1111
    </div>
    <div class="list">
      <input type="text" class="input" id="list_2">
      2222
    </div>
    <div class="list">
      <input type="text" class="input" id="list_3">
      3333
    </div>
    <div class="list">
      <input type="text" class="input" id="list_4">
      4444
    </div>
  </div>
  <label for="list_1">1</label>
  <label for="list_2">2</label>
  <label for="list_3">3</label>
  <label for="list_4">4</label>
  .wrapper {
    width: 300px;
    height: 200px;
    background: #ccc;
    white-space: nowrap;
    overflow: hidden;
    font-size: 0;
  }
  .list {
    font-size: 14px;
    display: inline-block;
    width: 100%;
    height: 200px;
    background: #666;
    position: relative;
  }
  .input {
    width: 100%;
    border: none;
    outline: none;
    padding: 0;
    position: absolute;
    clip: rect(0 0 0 0);
  }

position: absolute

absolutefloat 同时存在时,float 属性就会失效。而且没有任何理由 absolutefloat 同时使用。

absolutefloat 存在很多共性,可以说是一对兄弟属性

absolute 的包含块

对于设置了绝对定位的元素而言,其 “包含块” 就是相对于第一个设置了 position 不为 static 的祖先元素计算的。实际上,“包含块” 应用的很多,不仅仅存在于绝对定位中

absolute 包含块有几个明显的差异

无依赖绝对定位

一个绝对定位元素,没有任何 left/top/right/bottom 属性设置,并且其祖先元素全部都是非定位元素,其位置在什么地方??

absolute 是非常独立的 CSS 属性值,其样式和行为表现不依赖其他任何 CSS 属性就可以完成

  <div style="width: 300px; height: 250px; background: url(./img/timg.jpg) no-repeat">
    <img src="./img/timg.jpg" alt="" style="height: 50px; position: absolute;">
  </div>

上面的这个 demo 中 img 元素就处于左上角顶部位置

absolute 定位效果实现完全不需要父元素设置 position 就可以实现。我们把这种没有设置 left/right/top/bottom 属性值的绝对定位称为 “无依赖绝对定位”。很多场景下,“无依赖绝对定位” 要比使用 left/top 之类属性定位适用和强大。其除了代码简洁外,还有一个很棒的特性就是 “相对定位特性”。

  <div class="wrapper">
    <div class="item">
      <label class="left">
        <span class="red-icon">*</span>
        邮箱
      </label>
      <div class="right">
        <input type="text" class="input">
        <span class="remark">xxxooo</span>
      </div>
    </div>

    <div class="item">
      <label class="left">
        <span class="red-icon">*</span>
        密码
      </label>
      <div class="right">
        <input type="password" class="input">
        <span class="remark">xxxooo</span>
      </div>
    </div>

    <div class="item">
      <label class="left">
        <span class="red-icon">*</span>
        手机号码
      </label>
      <div class="right">
        <input type="password" class="input">
        <span class="remark">xxxooo</span>
      </div>
    </div>
  </div>
  .wrapper {
    width: 300px;
    margin: 20px auto 0;
  }
  .item {
    height: 34px;
    font-size: 14px;
    line-height: 34px;
  }
  .item + .item {
    margin-top: 10px;
  }
  .left {
    float: left;
    width: 70px;
  }
  .red-icon {
    position: absolute;
    width: 20px;
    margin-left: -20px;
    text-align: center;
    color: red;
  }

  .right {
    overflow: hidden;
  }
  .input {
    display: inline-block;
    width: 95%;
    height: 34px;
    box-sizing: border-box;
    line-height: 20px;
    padding: 6px 5px;
    border: 1px solid #ddd;
    border-radius: 4px;
    background: #fff;
    outline: none;
    -webkit-appearance: none;
    vertical-align: top;
  }
  .remark {
    position: absolute;
    color: red;
    margin-left: 20px;
  }

注意: 上面的 input 宽度不能占满父容器,否则 remark 元素就会换行

进一步深入讨论 “无依赖绝对定位”

虽然说元素 position: absolute 后的 display 计算值都是块状的,但是其定位的位置和没有设置 position: absolute 时候的位置相关。

  <h1>
    标题
    <span class="follow">span</span>
  </h1>
  <h1>
    标题
    <div class="follow">div</span>
  </h1>
  .follow {
    position: absolute;
  }

上面两个差别在于 “标题” 后面跟随的一个是 内联元素,一个是 块状元素。这个时候 span 显示在 “标题” 后面,div 显示在 “标题” 的下一行。

虽然此时无论是内联还是块级元素,display 计算值都是 bloc。但是它们的位置和没有设置 position: absolute 的时候一样,一个在前面一个在下面。

absolutetext-align
  <div style="height: 200px; background: #ccc; text-align: center">
    <img src="./img/timg.jpg" alt="" style="height: 100px; position: absolute">
  </div>

实例中的图片确实收到了 text-align 的影响,但并不是 text-alignabsolute 元素直接发生关系。其实这个时候 text-align 作用的是 “幽灵空白节点”。致使 “幽灵空白节点” 在容器盒子中居中展示,那么由于 <img> 是跟随 “幽灵空白节点” 的,所以图片的左边缘是和水平中线在一条线上对齐的。

overflowabsolute 元素的剪裁规则就是:绝对定位元素不总是被父级 overflow 属性剪裁,尤其是当 overflow 在绝对定位元素和其包含块之间的时候。

注意:上面的这些限制对 position: fixed 都没有用。因为 fixed 的包含块是 <html>。除非是文档滚动

absoluteclip

clip: rect(20px 30px 40px 50px)

意思就是: 距离画布上边缘 20px 的地方剪切一刀

距离画布左边缘 30px 的地方剪切一刀

距离画布上边缘 40px 的地方剪切一刀

距离画布左边缘 50px 的地方剪切一刀

中间的剪切区域就是最后我们看到的。如果要把一个元素全部剪切掉,参数全部设置为 0 ,就可以了

clip 还有一个好处就是,被剪切掉的元素还可以被爬虫给搜索到,这一点非常适合 SEO 优化。

absolute 流体特性

absolute 遇到 left/right/top/bottom 属性的时候,absolute 元素才能真正变成绝对定位元素。

当我们只设置了一个方向的绝对定位时,另一个方向依然保持 “相对特性”

absolute 的流体特性,当一个绝对定位元素,其对立定位方向属性同时存在时,流体特性就会发生。

  .fixed {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 200px;
    height: 200px;
    margin: auto;
  }

当元素具有流体特性的时候其 margin/border/padding/content 自动充满容器。所以这个时候 margin 设置 auto,就可以使上下左右平分两个方向的剩余空间了,从而实现了 水平垂直居中。

position: relative

虽然说 relative/absolute/fixed 都能对 absolute 的 “包裹性” 以及 “定位” 产生限制,但只有 relative 可以让元素依然保持在正常的文档流中

relative 具有两大特性:一是相对自身;二是无侵入

relative 的定位还有另外两点值得提

注意: relative 在使用时需要注意一个很重的问题,就是设置的元素会产生一个 “层叠上下文”,影响元素在层叠位置展现。所以使用时应该格外注意。

position: fixed

fixed 定位,只说一点。就是“无依赖固定定位”。“无依赖固定定位” 和 “无依赖绝对定位” 相似。

fixed 后的 display 计算值都是块状的,其定位的位置和没有设置 position: fixed 时候的位置一样。

当元素的布局在首屏内,那么当文档滚动时,元素的不会随着屏幕滚动

当元素的布局不在首屏内,那么这个元素不可见,在屏幕之外。