CSS世界

流的破坏与保护

Posted on 2019-02-13,10 min read

前言

流的破坏和保护,可能大家一想到的就是floatclear,并且认为float的出现就是为了解决布局问题的,但实际上这并不是它的本意,它的本质是为了实现文字环绕效果,即文字环绕图片显示的效果,很显然,从float的设计初衷来看,当下哪些漫天飞舞的浮动属性完全是滥用了。

float的特性

  • 包裹性
  • 块状化并格式化上下文
  • 破坏文档流
  • 没有任何margin合并

一旦元素的float的属性值不为none,则display的计算值就是blocktable,所以不要出现设置浮动后还设置display:block这样的组合,下面是常见的floatdisplay转换表:

float的天然克星clear

一般我们设置浮动属性后,都会设置clear属性清楚浮动造成后面的元素的影响,clear属性的官方解释就是:元素盒子的边不能和前面的浮动元素相邻。下面我们来看一个例子:

HTML:
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
CSS:
li{
    width:20px;height:20px;
    margin:5px;
    float:left;
}
li:nth-of-type(3){
    clear:both;
}

效果:

  • 这里的第三个设置清楚浮动,并且是both,讲道理,li显示应该是3行,但实际显示的却是两行,原因在于,clear属性是让自身不能和前面的浮动元素相邻,注意这里的"前面的"三个字,也就是clear属性对后面的元素是不闻不问的,因此才显示两行而不是三行。更进一步,考虑到float属性不是left就是right,不可能同时存在,同时由于clear属性对“后面的”浮动元素不闻不问,因此设置clear:right有效的时候,必然clear:left必然无效,也就是此时的clear:left等同于设置clear:both,因此,在平时使用的过程中,直接使用both属性就好。

    clear属性只有块级元素才有效,而::after等伪元素默认都是内联水平,这就是借助于伪元素清除浮动元素影响需要设置display属性值的原因。

    .clear:after{
        content:"";
        display:block;//也可以是table,list-item
        clear:both;
    }
    

    CSS世界的结界——BFC

    BFC全称为block formatting context,中文名为“块状格式化上下文”,相对应的还有IFC,也就是“内联格式化上下文”,本节主要研究BFC。
    关于BFC的特性,可以将其称为“css世界的结界”,有点类似于神话中的结界一样,结界内的元素无论怎么翻江倒海,都不可能影响结界外的元素,所以BFC元素不可能发生margin重叠,因为重叠会影响到外面的元素,BFC元素也可以清除浮动的影响。

    常见触发BFC的情况:

    • <html>根元素;
    • float的值不为none;
    • overflow的值为auto、scrollhidden;
    • display的值为table-celltable-captioninline-block中的任何一个;
    • position的值不为relativestatic

    overflow的不兼容

    直接上代码:

    HTML:
    <div class="box">
        <img src="1.jpg" width="256" height="192">
    </div>
    CSS:
    .box {
        width: 200px; height: 80px;
        margin: auto;
        padding: 10px;
        border: 10px solid;
        overflow: hidden;
    }
    

    当鼠标向下滚动的时候,chrome变现与其他浏览器表现不一致,具体表现在chrome浏览器下面会有10px的空白,IE和火狐则没有。

    chrome浏览器
    IE浏览器

    原理则是在chrome浏览器下,如果容器可滚动(假设是垂直滚动),则padding-bottom也算在滚动尺寸之内,IE和火狐则会忽略padding-bottom。所以为了减少不必要的麻烦,尽量避免滚动容器设置padding-bottom值。

    overflow的依赖样式

    我们常用的单行文本溢出显示点点效果,虽然核心技术是text-overflow:eliipsis,但是要想实现这种效果,必须申明以下3个:

    .ell{
        text-overflow:ellipsis;
        white-word:nowrap;
        overflow:hidden;
    }
    

    无依赖绝对定位

    包含快这个概念简单解释就是元素用来计算和定位的一个框。下面是包含快的常用计算规则:

    • 根元素(很多场景下可以看成是)被称为“初始包含快”,其尺寸等同于浏览器可视窗口的大小。
    • 对于其他元素,如果该元素的positionrelative或者static,则包含快由最近的块容器祖先盒的content box边界组成。
    • 如果元素position:fixed,则包含快是初始包含快。
    • 如果元素position:absolute,则包含快由最近的position不为static的祖先元素建立,具体规则如下;

    如果该祖先元素是纯inline元素,则规则略微复杂:

    • 假设给内联元素的前后各生成一个宽度为0的内联盒子(inline box),则这两个内联盒子的padding box外面的包围盒就是内联元素的“包含快”;
    • 如果该内联元素被跨行分割了,那么“包含快”是未定义的,也就是css2.1规范 并没有明确定义,浏览器自行发挥。
      否则,“包含快”有该祖先的padding box边界形成。

    如果没有符合条件的包含快,则“包含快”就是“初始包含快”。

    思考这样一个问题:一个绝对定位元素,没有任何left/top/right/bottom属性设置,并且其祖先元素全部都是非定位元素,其位置在哪里?

    很多人都认为是浏览器窗口的左上方,实际上,还是当前位置,不是浏览器的左上方。

    考虑下面这样一个例子:

    下图左上角需要一个TOP1的图像标志,请问如何布局?
    想必大多数都是这样的:

    .father{
        position:relative;
    }
    .shap{
        positiong:absolute;
        top:0;left:0;
    }
    

    实际上只需要一行代码就可以了,不信?点击demo测试即可。

    .shap{
        positiong:absolute;
    }
    

    看到没有,这种不需要position:relative或者其他属性就可以实现,我们把这种没有left/top/right/bottom属性值的绝对定位简称为“无依赖绝对定位”,我们还可以将其运用在表单验证提示语中。
    有下图的一个表单psd文稿:

    一般来说在注册的时候客户端都需要验证一番,从而减少用户出错,验证提示信息都是放在填写表单每一个行的后面,假设提示文字内容元素的类名是remark,则有css代码如下:

    .remark{
        position:absolute;
        margin-left:10px;
    }
    

    详细demo可点击查看。

    重新认识clip属性

    很多人都不知道css中还有就地剪裁属性,其基本语法为:

    clip:rect(top,right,bottom,left)

    当然其生效的前提是元素必须会绝对定位或者固定定位,也就是position的属性值必须是absolute或者fixed

    其主要运用在两个重要的场景。

    1.fixed固定定位的剪裁
    对于普通元素,我们想要对齐进行剪裁,我们可以利用语义更明显的overflow属性,但是对于position:fixed元素,overflow属性往往就是失效了,因为固定定位的包含块是根元素,所以这时候clip属性就可以大展身手了。例如:

    .fixed-clip{
        position:fixed;
        clip:rect(30px 200px 20px 10px);
    }
    

    2.最佳可访问性隐藏
    所谓“可访问性隐藏”,指的是虽然肉眼看不见,但是其他辅助性设备却能够识别和访问的隐藏。

    比如,很多网站为了SEO优化,往往会在自己的网站的标识,即logo旁边使用标签写上自己网站的名词,代码如下:

    <a href="/" class="logo">
        <h1>hello world!</h1>
    </a>
    

    如何隐藏标签中的文字,一般有以下技术选型:

    • 最简单的是display:none或者visibility:hidden,但是屏幕阅读器会忽略这里的文字。
    • text-indent是稍微好一点的中策之计,但是缩进太大,屏幕阅读器也会忽略。
    • color:transparent移动端上策之选,但是桌面端却是中策之选,毕竟ie8并不支持透明颜色。
    • clip隐藏测试最佳实践,移动桌面支持都良好。
    .logo h1{
        positiong:absolute;
        clip:rect(0 0 0 0);
    }
    

    absolute的margin:auto居中

    实现一个元素的水平垂直居中,我们常用的便是这样:

    .el{
        width:400px;
        height:400px;
        position:absolute;
        left:50%;
        right:50%;
        margin-left:-200px;
        margin-top:-200px;
    }
    
    

    兼容奇好,IE7也支持,但是明显有一个缺点,margin和元素的宽高耦合了。
    第二个方案则是通过transform实现:

    .el{
        width:400px;
        height:400px;
        position:absolute;
        left:50%;
        right:50%;
        transform:translate(-50%,-50%);
    }
    

    这里的耦合问题解决了,但是百分比的transform会让iOS微信闪退,这里也不推荐。
    第三种就是最佳实践了:

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

    通过margin自动平分,可以说最佳了,但是不兼容IE8,所以视情况而定吧。

    参考自《css世界》

    作者:落叶卢生
    链接:https://luoyelusheng.com/post/流的破坏与保护
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    下一篇: 盒尺寸四大家族→