zoukankan      html  css  js  c++  java
  • 遇见未知的CSS

    摘录自《CSS核心技术详解》

    1.1 CSS中你可能会疑问的几个问题

    1.1.1 在CSS中为什么要有层叠

    在CSS中可能会有多个样式表同时影响同一个元素的某个属性,设计这个功能的主要原因有两个,解决模块化和作者、用户、用户代理样式冲突。

    • 模块化

    一个页面中的样式可以拆分成多个样式表,代码如下。

    @import url(style/base.css);
    @import url(style/layer.css);

    但这种方式也会随之产生一个问题,即如果对某个元素的同一个属性设置样式,到底应用谁的呢?

    • 作者/用户/用户代理

    当作者(写代码的人)和用户(浏览页面的人),以及用户代理(一般指浏览器)都能更改样式表时,也会产生同样的问题:究竟用谁设置的样式,因此CSS层叠机制就显得格外重要。

    1.1.2 为什么“@import”指令需要写在样式表的开头

    代码如下。

    @import url(style/layer.css);
    body{
      background-color:red;
    }

    “@import”指令之所以需要写在样式表的开头,是因为这样可以使后面的样式能更好地层叠导入进来的样式。

    1.1.3 当CSS值为0时为什么可以省略单位

    因为当CSS值为0时,任何单位的结果都是一样的,就像数学中的0乘以任何数都得0。

    1.1.4 margin垂直外边距折叠的意义是什么

    margin垂直外边距折叠的特性主要来自传统排版,举个例子,代码如下。

    <style>
      body,ul,li{
        margin:0;
        padding:0;
      }
      ul{
        list-style:none;
      }
      ul>li{
        margin:20px 0;
      }
    </style>
    <ul>
      <li>1111111111</li>
      <li>2222222222</li>
      <li>3333333333</li>
    </ul>

    效果如图 1.1

    从图1.1中可以看到3行数字的垂直外边距都是一样的。如果没有这个特性,第一行数字与下面两行数字的外边距就不一样了,因为我们给每个li都设置了一个上下外边距,假如没有外边距折叠,那么第1个li的下边距加上第2个li的上边距,就是两倍的间距了,但是第一个li上面没有其他元素,所以它只有一个上边距,最终导致的结果就是,第1个li和后面的几个li的外边距不一样,这显然不是我们所希望的。而margin外边距折叠功能正是要在这种情况下,让格式可以好看一点。

    1.1.1 CSS层叠规则

    在介绍CSS层叠规则之前首先举个例子,代码如下。

    <style>
      .box{
        color:red;
        font-size:18px;
      }
    </style>
    <div class="box">
      <a href="#">层叠</a>
    </div>

    结果如图1.2所示:

    按理说颜色是可以继承的,那么为什么a标签的颜色没有变成红色呢?审查一下元素,如图1.3所示。

    从图1.3中可以看到继承的颜色被划掉了,出现这个问题的原因是浏览器对a标签设置了默认样式,将继承的样式层叠了,因为继承的样式权重最小。下面介绍CSS关于层叠规则是怎么计算的。

    在CSS中一个样式可能会来自不同的地方,分别是作者,用户以及用户代理。那么问题来了,如果在这几份样式中,他们对同一个元素的同一个属性做了不同的操作,那么用户代理应该如何处理这段CSS呢?举个例子,代码如下。

    /* 作者 */
    .box{
      color:red;
    }
    /* 用户代理 */
    .box{
      color:green;
    }
    /* 用户 */
    .box{
      color:pink;
    }

    可以看到用户代理以及用户的代码和作者写的样式起冲突了,而CSS的层叠规则就是为了解决这些问题的,以下是一些CSS层叠规则。

    在层叠中每个样式规则都有一个权重值,当其中几条规则同时生效时,权重值最大的规则优先。一般来说作者指定的样式权重值高于用户样式权重值,用户样式权重值高于客户端(用户代理)权重值。

    在层叠顺序中,以下权重值从小到大。
    1. 用户代理样式
    2. 用户一般样式
    3. 作者一般样式
    4. 作者重要样式(!important)
    5. 用户重要样式(!important)
    6. 如果是两个样式来自同一个地方,如都来自作者,并且它们的样式声明同样重要,则根据特异度来计算,特异度高的会覆盖特异度低的
    7. 如果特异度也相同,则越往后的样式优先级越高
    !important声明规则

    !important声明的样式比一般声明优先级高,并且用户设置的!important比作者设置的!important优先级高。这样做的原因是为了方便用户实现一些特殊的要求,例如页面字体大小的调整等。

    下面举一个!important规则的例子,代码如下。

    <style>
      .box{
        color:red !important;
      }
      .box{
        color:green;
      }
    </style>
    <div class="box">!important</div>

    在正常情况下,后一个“color:green”会层叠前一个“color:red”,但这里我们给“color:red”设置了!important规则,所以前一个优先级高。

    选择器特异度的计算
    1. 如果一个声明出现在元素的style属性中,则将a计为1
    2. b等于选择器中所有id选择器加起来的数量和
    3. c等于选择器中所有class选择器和属性选择器,以及伪类选择器加起来的数量和
    4. d等于选择器中所有标签选择器和伪元素选择器加起来的数量和

    将a、b、c、d这4个数字连接起来(a-b-c-d)就组成了选择器的特异度。一段特异度的计算,如下所示。

    .box{}           /* a=0 b=0 c=1 d=0 特异度 = 0,0,1,0 */
    .box div{}       /* a=0 b=0 c=1 d=1 特异度 = 0,0,1,1 */
    #nav li{}        /* a=0 b=1 c=0 d=1 特异度 = 0,1,0,1 */
    p:first-line{}   /* a=0 b=0 c=0 d=2 特异度 = 0,0,0,2 */
    style=""         /* a=1 b=0 c=0 d=0 特异度 = 1,0,0,0 */

    它们的比较顺序是先比较a,如果a的值都相同,那么接着比较b、c、d的值,谁的数大则优先级就越高。

    在使用CSS选择器时,你需要注意以下两点。

    • 继承的优先级最低,没有特异度;
    • 结合符(如+、>等)及通用选择符(*)特异度为0。

    因此,可以知道之前a标签color属性为什么没有被应用了,因为继承的优先级最低。

    1.1.6 CSS的命名

    在代码复用时,也许你写过类似以下这样的代码,代码如下

    size-10{
     font-size:10px;
    }

    虽然这段代码看起来没什么问题,但如果考虑到可维护性,那就有很大问题了。假如有一天你不想用10px,想改成12px,也许你会想再加一个class就行了,修改后的代码如下

    size-10{
        font-size:10px;
    }
    size-12{
        font-size:12px;
    }

    但那些页面中原本用的size-10的class都得修改成size-12,所以不建议这么修改代码。笔者建议用语义的方式命名,代码如下

    .size-small{
      font-size:12px;
    }

    这样写代码的好处是当需要调整字体大小时,只需修改一处,而不必修改添加到元素上的class。也就是说不要按照显示的效果命名,而是根据这个class的用意命名。

    1.2 CSS的一些技巧

    1.2.1 使用pointer-events控制鼠标事件

    可以用CSS中的pointer-events来控制元素什么时候响应鼠标事件,比较常用的一个场景是获取验证码,如图1.4所示。

    图1.4 获取验证码

    当用户单击“获取验证码”按钮后,需要等待60秒才能再次单击“重发验证码”按钮,在这种情况下,就可以尝试用pointer-events实现禁用鼠标单击事件。在pointer-events属性中有一个none值,将pointer-events的值设置成none就不会响应鼠标事件了。举一个获取验证码的例子,代码如下。

    <style>
        a{
            color:red;
        }
        .disable{
            pointer-events:none;
            color:#666;
        }
    </style>
    <a href="javascript:;" id="btn">发送验证码</a>
    <script>
        var oBtn = document.getElementById('btn');
        oBtn.onclick = function(){
            oBtn.classList.add('disable');
            setTimeout(function(){
                oBtn.classList.remove('disable');
            },3000)
        };
    </script>

    如果看不懂这段代码也没关系,将这段代码复制下来即可。这段代码的意义就是定义了一个鼠标事件禁用的class,单击“发送验证码”按钮后加上刚刚定义的.disable,3秒以后再将这个class去掉。默认情况下的按钮,如图1.5所示

    图1.5 默认情况下

    单击此按钮后,在3秒内不会再次响应单击事件。

    pointer-events除了可以实现此功能之外,还有很多用处,比如实现a标签禁止页面跳转,提高网页性能,用户在滚动页面时可能会不小心碰到一些元素上绑定的事件,这些事件就会被触发,从而浪费资源,但如果在页面滚动时给body加上pointer-events:none;属性,那么就避免了这个问题。

    pointer-events还有一个妙用,比如将一个遮罩层元素的属性设置为pointer-events:none;,这样就可以单击到遮罩层后面的内容,如图1.6所示。

    图1.6 运用了pointer-events以后

    如图1.6所示可以看到选中了遮罩层后面的内容,但需要注意的是,pointer-events:none只是用来禁用鼠标的事件,通过其他方式绑定的事件还是会触发的,比如键盘事件等。另外,如果将一个元素的子元素pointer-events设置成其他值,如auto,那么当单击子元素时,还是会通过事件冒泡的形式触发父元素的事件。

    1.2.2 玩转CSS选择器
    1. 当父元素只有一个子元素时会被选中,代码如下
    <style>
        div:first-of-type:last-of-type{
            color:red;
        }
    </style>
    <div>123</div>

    当只有一个div元素时,效果如图1.7所示。当有多个div时不会被选中,效果如图1.8所示。

    图1.7 当只有一个div时

    图1.8 当有多个div时

    当然更简单的方法是直接用CSS3中的结构性伪类选择器,当父元素只有一个子元素时会被选中,如下:

    :only-child

    不妨去试试。

    2.当父元素有多个子元素时,选中第1个
    <style>
        div:not(:last-of-type):first-of-type{
            color:red;
        }
    </style>
    <div>11111</div>

    只有一个子元素时,不会被选中,效果如图1.9所示。当有多个子元素时,它会选中第一个,效果如图1.10所示。

    图1.9 只有一个子元素时

    图1.10 当有多个子元素时

    当然,如果有多个子元素时,也可以选择其中任意一个子元素,但最后一个是选中不了的,因为我们已经用“:not”否定了最后一个元素。如果想要摆脱这种限制,可以使用下面这种方案,代码如下。

    :not(:only-child)

    以有多个子元素时选中最后一个子元素为例,代码如下

    <style>
        div:not(:only-child):last-of-type{
            color:red;
        }
    </style>
    <div>11111</div>
    <div>22222</div>
    <div>33333</div>

    当一个父元素有多个子元素时,最后一个元素会被选中,效果如图所示。

    案例

    合理使用这些选择器可以做很多事情,比如当只有一个子元素时,可以让它居中显示,如果有多个子元素时,可以让它水平排列,代码如下

    <style>
       .box div{
            100px;
            height:100px;
            border:1px solid red;
            margin:0 auto;
       }
       .box div:not(:only-child){
            float:left;
            margin-left:20px;
       }
    </style>
    <div class="box">
        <div></div>
    </div>

    当只有一个子元素时,这个div就会被居中显示,如下图1.12

    图1.12 当只有一个子元素时,这个div就会被居中显示

    当有多个子元素时,效果如图所示

    1.2.3利用padding实现元素等比例缩放

    padding和margin有一个很奇怪的特点,它们的上下外边距的百分比是根据父元素的宽度来计算的。举个例子,代码如下。

    <style>
       .box{
            100px;
            height:10px;
       }
       .box div{
            100%;
            padding-bottom:100%;
            background-color:red;
       }
    </style>
    <div class="box">
        <div></div>
    </div>

    效果如图1.14

    图1.14 padding、margin上下外边距的百分比

    在此例子中可以看到 div 的宽度和高度都是 100px。如果根据父元素的高度来计算,那么div 的高度最终应该是 10px,而不是 100px,因此,若需要实现一个等比例的元素,就可以利用这个特性,但如果使用这种方式,还需要解决另外一个问题,就是如果直接在子元素div中写入内容,那么高度会被“撑开”,那就不是等比例了。代码如下。

    <div class="box">
        <div>padding-bottom</div>
    </div>

    若在div中加入一段文字,那么高度就不再是等比例了,效果如图1.15所示。

    图1.15 在div中加入一段文字后的高度

    但是可以将代码进行修改,修改后的代码如下。

    <style>
       .box{
            30%;
            height:10px;
       }
       .box div{
            position:relative;
            overflow:hidden;
            background-color:red;
       }
       .box div::after{
            content:'';
            display:block;
            padding-top:100%;
       }
       .box div span{
            position:absolute;
            left:0;
            top:0;
       }
    </style>
    <div class="box">
        <div>
            <span>图片</span>
        </div>
    </div>

    利用伪元素的padding-top来“撑开”父元素的高,内容通过绝对定位来使用,因为绝对定位的元素是不占位置的,这样一个等比例宽高缩放就完成了。有时这种特性很有用,比如针对下面这个需求,如图1.16所示。

    现在需要将图片等比例缩放,也就是宽和高一样,但图片的宽度是自适应屏幕大小的,img标签在只写宽度不写高度的情况下,高度会自适应宽度。图片没有加载出来之前的情况,如图1.17所示。

    图1.16 需求

    这个需求是这样的,图片等比例缩放,也就是宽和高得一样,但问题是图片的宽度是自适应屏幕大小的,原本很简单因为img标签在只写宽度不写高度的情况下,高度会自适应宽度,但问题不在这,而是如果图片在没有加载出来的情况下,会是这样的,如图1.17

    图1.17 在图片没有加载出来时

    从图1.17可以看到在图片没有加载出来之前高度就没有了,这时利用CSS属性paddding-top就可以解决这个问题,代码如下

    .photo a{
        position:relative;
        float:left;
         calc(33.33% - 1.6rem);
        margin:1.2rem 0 0 1.2rem;
        outline:1px solid #dedede;
    }
    .photo a::before{
        content:'';
        display:block;
        padding-top:100%;
    }
    .photo a img{
        position:absolute;
        left:0;
        top:0;
        100%;
        height:100%;
    }

    使用一个伪元素将高度“撑起来”,而图片通过定位来做。还有一种更简单的做法,就是直接给a标签设置高度,单位使用vw。vw单位是相对于视口(屏幕)宽度的,代码如下。

    .photo a{
        float:left;
         calc(33.33% - 1.6rem);
        height: calc(33.33vw - 1.6rem);
        margin:1.2rem 0 0 1.2rem;
        outline:1px solid #dedede;
    }
    .photo a img{
        display:block;
        100%;
        height:100%;
    }

    宽度怎么设置,高度就怎么设置,就是把百分比换成vw。但是只在自适应方面才能这样用,如果是固定的宽、高,直接设置成一样的就行了,虽然vw可以实现,但兼容性还不是很好。

    1.2.4 calc函数

    在CSS中,如果需要用计算的功能,那么calc函数将非常有用。calc函数允许进行任何长度值的计算,运算符可以是加(+)、减(-)、乘(*)、除(/)等。但需要注意的是,运算符前后都需要保留一个空格,虽然在某些特殊情况下可能不需要,但最好都加上,下面来介绍一些calc函数的使用场景。

    场景一:

    如图1.18所示,图中的内容一旦超过了浮动元素的高,那么这些文本就会与图片左对齐,这种效果并不是我们想要的。我们想要的效果,如图1.19所示。

    图1.18 实际不理想的效果

    图1.19 预期理想的效果

    如果知道图片的宽度,那么解决这个问题也很简单,给这段文本添加一个左边距即可,但如果图片使用的是百分比,那么就无能为力了,而如果使用calc函数可以很好地解决这个问题,代码如下。

    <style>
        .box img{
            50%;
            float:left;
        }
        .box p{
            margin-left:calc(50% + 10px);
        }
    </style>
    <div class="box">
        <img src="psb.jpg" alt="">
        <p>......</p>
    </div>

    利用calc函数更改代码后的效果如图1.20所示

    图1.20 利用calc函数的效果

    场景二:

    有时使用百分比会出现一个问题,如图1.21所示。

    图1.21 使用百分比时可能会出现的问题

    其中CSS代码为

    <style>
        .box img{
            25%;
            margin:20px;
            float:left;
        }
    </style>

    导致这个问题出现的原因是使用了margin值,而代码中的25%并没有减去这个margin值。因此只需要用calc函数减去margin值就可以了,代码如下

    <style>
        .box img{
            calc(25% - 40px);
            margin:20px;
            float:left;
        }
    </style>

    最终效果如图1.22所示

    图1.22 使用calc函数的最终效果图

    场景三:

    如果再结合媒体查询,那么就很容易实现一个响应式的布局,代码如下。

    <style>
        .box img{
            calc(100% / 4 - 40px);
            margin:20px;
            float:left;
        }
        @media (max-600px){
            .box img{
                calc(100% / 2 - 40px);
            }
        }
    </style>

    这段代码表示在屏幕不小于600px时,一行最多可以放4张图片,如果屏幕小于或等于600px时,一行最多只能放两张图片。

    1.3 隐藏元素

    千万不要小看“隐藏”这个技能,多了解一点,就多一种选择。如果你是一个新手,就会发现在本节将出现很多你不认识的属性,它们可能是在CSS 2中就有的属性,也可能是在CSS 3中出现的新属性。

    1. 通过设置0;或height:0;隐藏一个元素
    div{0;}

    div{height:0;}

    一个物体是由宽和高组成的,那么至少这个物体得有宽和高,这种方式的缺点是隐藏不了文字。可以将元素的color设置成与背景色一样的颜色,这样就看不见了。也可以设置成透明色(transparent),但问题是它们的内容还是存在的,所以需要将文字的大小设置成0,代码如下

    div{font-size:0;}
    2. 将元素的opacity:0;设置成0
    div{opacity:0;}

    元素本身还在,只是看不见而已

    div{
        opacity:0;
        filter:alpha(opacity:0);
    }
    3. 通过定位将元素移出屏幕范围
    div{
       position:absolute;
       left:-9999px;
    }

    元素还在,只是超出了屏幕范围,看不见了而已。

    4. 通过text-indent实现隐藏文字效果
    div{text-indent:-999999px;}

    给页面添加LOGO图片,若还想让搜索引擎搜索到,则需要添加这段文字,但如果又不想显示这段文字,就可以使用这个方法。

    5. 通过z-index隐藏一个元素
    <style>
       .box{
            position:relative;
       }
       .box .item{
            position:absolute;
            left:0;
            top:0;
            100px;
            height:100px;
            border:1px solid red;
            z-index:-1;
       }
       .box .item:first-of-type{
            z-index:1;
       }
    </style>
    <div class="box">
        <div class="item">程序员</div>
        <div class="item">设计师</div>
    </div>

    但你会发现文字被“透”上来了,效果如图

    因为默认的背景设置是透明的,并且允许下面的元素“透”上来,想解决这个问题很简单,就是给元素添加一个背景,代码如下。

    .box .item{
            position:absolute;
            left:0;
            top:0;
            100px;
            height:100px;
            border:1px solid red;
            background-color:#fff;
            z-index:-1;
    }

    设置完成后,效果如图

    6. 通过给元素设置overflow来隐藏元素
    div{
        100px;
        height:100px;
        overflow:hidden;
    }

    如果元素超出所设置的宽和高,溢出的部分就会被隐藏。如果想让整个元素隐藏,将元素的宽和高设置成0即可。经常通过这种方式将超出的文字隐藏,代码如下

    <style>
        h2{
            16ch;
            overflow:hidden;
            white-space:pre;
            text-overflow:ellipsis;
        }
    </style>
    <h2>享受一片宁静的天空。</h2>

    当中文超出7个字符以后,文字就会被隐藏,效果如图

    7. 通过visibility将元素设置为不可见
    div{visibility:hidden;}

    虽然元素不可见,但还占位置。

    8. 通过display将元素彻底隐藏
    div{display:none;}

    元素会被隐藏,并且不占位置。

    9. 将元素的背景设置为透明,字体大小设置为0
    div{
        font-size:0;
        background-color:transparent;
    }

    元素还在,只是看不见。

    10. 将元素的max-width或max-height设置为0
    div{max-height:0;}

    div{max-0;}

    这样元素的宽度就只能是0了,但是还有文字溢出的问题,如图1.26所示。

    图1.26 文字溢出

    尽管元素宽度是 0,但文字还是被显示出来了,若想解决这个问题,将文字大小设置成0就可以了,或者使用代码overflow:hidden;如果你仔细看这个效果,会发现它实际上是一个文字竖排的效果,不过对于英文来说,还得设置一个换行属性,换行属性代码如下

    <style>
        h2{
            max-0px;
            word-break:break-all;
        }
    </style>
    <h2>享受一片宁静的天空AAA</h2>

    效果如图1.27

    图1.27 通过设置word-break:break-all;解决英文不换行问题

    11. 通过transform的translate函数来隐藏一个元素
    div{transform:translate(-99999px);}

    left:-99999px;原理一样,把元素移出屏幕可视区。

    12. 将元素的缩放设成0
    transform:scale(0);

    看不见我,看不见我。

    13. 让元素重叠
    div{transform:skew(90deg);}

    元素重叠了,类似width等于0。

    14. 设置margin负值
    div{margin-left:-999999px;}

    将元素移出屏幕可视区

    15. 将元素裁剪
    -webkit-clip-path:polygon(0px 0px,0px 0px,0px 0px,0px 0px);

    完,带上愉快的心情,踏上CSS之旅。

  • 相关阅读:
    移植spdylay到libcurl
    用到的C++标准库
    libcurl底层调用逻辑
    socket编程
    linux的一些机制Signal, Fork,
    openssl 编程
    对称加密,非对称加密
    ajax提交整个form表单
    一道基础的for语句js编译过程
    怎样将浏览器一句话变为文本编辑器
  • 原文地址:https://www.cnblogs.com/libin-1/p/6837915.html
Copyright © 2011-2022 走看看