• 你可能不知道的CSS


    前言

    也许有人会说,都快 2019 年了怎么还读 css2.1 规范。一方面,现在最新的 css (core) 规范是 CSS2.2(以下截图来自 https://www.w3.org/TR/CSS/ ),又因为 CSS2.1 有中文的版本,并且和 CSS2.2 规范差异性不是很大,基于偷懒的目的最终选择阅读了 CSS2.1 规范。

    记得面试的时候,面试官说 “你的 JavaScript 掌握得比大多数人好很多,但你的 CSS 还需要再加强”。今年六月毕业后,我正式成为一名前端工程师,阅读 CSS 规范也因此进入自己今年的 TODO list 中。

    前后花了两个月的零散时间,在上周我终于完成了阅读,对 CSS 的理解也稍微更系统全面了一些。在自己阅读的过程中,有些感觉是大家平常容易忽视,但有可能用到或是本身比较有趣的小知识点,便以此为主题,在此基础上适当扩展,整理了一篇文章和大家分享。

    只要一杯咖啡的时间,一起来回顾一下规范里那些可能不太能引起你注意的地方吧。

    阅读愉快,请多指教。

    关键字、属性和标识符

    以 - 或 _ 开头的关键字和属性名是为特定供应商扩展保留的。

    CSS 中标识符只能包含字符 [a-zA-Z0-9]、ISO10646 字符中 U+00A0 及之后的字符,以及 - 和 _,不能以 1 个数字、2 个连字符、或者后面跟着数字的连字符开头。

    这也意味着,选择器可以是中文的(虽然并不推荐)。

    <style>
    .中文 {
        color: red;
    }
    </style>
    ....
    <p class="中文">这是一段中文选择器文本。</p>

    此时,<p> 标签内的文字将变为红色。

    @import

    用户代理必须忽略所有出现在块内部,或者在除 @charset 和 @import 规则外任何无法忽略的语句后面的 @import 规则。

    这也意味着,@import 规则必须先于除@charset 和其它的 @import 规则外的所有规则。

    @import "subs.css"
    h1 { color: blue; }
    @import "list.css"

    上述代码中,第二个 @import 语句是非法的,解析器将会忽略这条规则。

    另外,@import 规则可以加上媒体查询类型,表示只在满足某个媒体类型时引入样式表。

    @import "landscape.css" screen and (orientation:landscape)

    编码和 @charset

    当一个样式表被嵌进其它文档时,比如 html 中的 style 元素或者 style 属性,样式表会共享整篇文档的字符编码。

    如果一个样式表处于一个独立文件中,则按下列顺序(从最高优先级到最低)确定样式表的字符编码:

    1. HTTP 协议中 Content-type 字段的 charest 参数
    2. 文件的 BOM 编码或 @charset
    3. <link charset=""> 或者来自链接机制的其它元数据
    4. 要引入的样式表或者文档的字符集
    5. 假定为 UTF-8

    使用 @charset 规则的编写者必须把该规则放在样式表的开头,前面不允许有任何字符。用户代理必须忽略任何不在样式表开头的 @charset 规则。

    :first-letter 伪元素

    :first-letter 伪元素选择一个块的第一行(第一个格式化行块)的第一个字母(或数字),如果这一行中在它前面没有跟着任何其它内容(例如图片或者 inline table)的话。表格单元或者inline-block 元素的首字母不能作为其祖先元素的首字母。

    <style>
    .description:first-letter {
        color: white;
    }
    </style>
    
    <p class="description">“some text”</p>
    <p class="description">some text</p>
    <p class="description"><img src="" />some text</p>

    实际效果如图:

    :before 与 :after 伪元素

    :before 和 :after 伪元素会从文档树中它们附着的元素上继承所有可继承的属性。对于不可继承的元素,将取其初始值。

    用法示例:

    p { color: red; display: block; }
    p:before { content: 'T'; }

    如上例,此时,:before 伪元素将呈现红色。因为 display 属性不可继承,将取其初始值 inline。

    扩展:伪元素的单冒号和双冒号

    CSS3 选择器草案中区分了伪元素和伪类(CSS-Selectors Level 4),伪类仍以一个引号开头,伪元素则以两个引号开头。对于 CSS1 和 CSS2 中存在的 :before、:after、:first-line 和 :first-letter 伪元素,用户代理必须同时支持它们单引号和双引号的形式,对于其它新引入的伪类,用户代理将不支持其单引号的形式。

    选择器与层叠

    选择器中,文档语言元素名的大小写敏感性取决于文档语言,例如在 html 中元素名是大小写不敏感的,而在 XML 中元素名是大小写敏感的。

    层叠顺序

    样式表可能有 3 种不同的来源:编写者、用户和用户代理(如浏览器)。

    为了找出一个元素或属性组合的值,用户代理必须按照下列(步骤)排序:

    1. 找出目标媒体类型下,所有适用于该元素和目标属性的声明
    2. 根据重要性(@important)规则和来源排序,优先级从低到高为:

      • 用户代理声明
      • 用户常规声明
      • 编写者常规声明
      • 编写者重要声明
      • 用户重要声明
    3. 相同重要性和来源的规则根据选择器的特殊性(specificity)排序,更特殊的选择器将重写一般的。伪元素和伪类被分别算作常规元素和类
    4. 最后,根据指定顺序排序:如果两个声明的权重,来源和特殊性都相同,后制定的生效。@import引入的样式表中的声明被认为在样式表自身的所有声明之前

    计算选择器的特殊性(specificity)

    一个选择器的特殊性(a-b-c-d)根据下列规则计算(a到d权重依次递减):

    • 如果声明来自一个 style 属性而不是一条选择器样式规则,算1,否则就是0(=a)
    • 计算选择器中 ID 属性的数量(=b)
    • 计算选择器中其它属性和伪类的数量(=c)
    • 计算选择器中元素名和伪元素的数量(=d)
    * {} /*a=0, b=0, c=0, d=0*/
    li {} /*a=0, b=0, c=0, d=1*/
    .description {} /*a=0, b=0, c=1, d=0*/
    *[rel=up] {} /*a=0, b=0, c=1, d=0*/
    #element {} /*a=0, b=1, c=0, d=0*/
    style="" /*a=1, b=0, c=0, d=0*/

    也就是说,尽管 #p123 比 [id=p123] 选中的对象相同,但ID 选择器比属性选择器拥有更高的特殊性。

    补充

    之前看过一些博客,在提到层叠的特殊性的时候,用 1000, 100, 10, 1 的权重去描述上述的 a-b-c-d 的计算方式。实际上这并不准确。我们可以通过简单的实验推翻上述的说法。

    如下例,我们定义了类名为 zero 的 div,里面嵌套了十层 div,最内的一层指定了 id 为last。如果按照10倍递增的算法,嵌套十一层的 class 的特殊性为 110,使用一个 id 的特殊性为 100,背景呈现黑色。如果按照 a-b-c-d 的算法,使用前者的特殊性为 0-0-11-0,后者特殊性为 0-1-0-0,背景将呈现红色。

    通过观察连用十一个 class 和一个 id 的表现,即可得出结论。

    <style>
    #last {
        background: red;
    }
    .zero .one .two .three .four
    .five .six .seven .eight
    .nine .ten {
        background: black;
        height: 100px;
         100%;
    }
    </style>
    <div class="zero">
        <div class="one">
            <div class="two">
                <div class="three">
                    <div class="four">
                        <div class="five">
                            <div class="six">
                                <div class="seven">
                                    <div class="eight">
                                        <div class="nine">
                                            <div class="ten" id="last"></div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    如图所示,背景呈现红色,所以 1000, 100, 10, 1 的计算方式是不准确的。

    不过,由于实现上的问题,可能会存在有限多个 class 优先级比一个 id 高的情况。张鑫旭在12年分享过一篇《有趣:256个class选择器可以干掉1个id选择器》。主要是因为写这篇文章的时候有些浏览器使用了8位计数器对 class 的数量进行计算,当 class 达到256个时由于发生进位将会出现权重比 id 高的情况。之后的浏览器使用了更高位数的计数器,理论上仍可能存在边界值,但将很难达到。

    content 中的 attr 属性

    content: attr(X)

    attr(X)函数返回一个字符串,字符串的值为该选择器选中对象的 X 属性的值。如果该对象没有 X 属性,则返回一个空字符串。

    用法示例:

    p:after { content: ", " attr(data-name); }
    <data-name="Thorn">Hello</p>

    此时将会渲染出 “Helo, Thorn”。

    计数器

    计数器使用大小写敏感的标识符。自动编号通过 counter-increment 和 counter-reset 属性控制。

    如果给同一个计数器指定了多次 counter-reset 或者 counter-increment 的值,计数器的每次重置或递增会按指定的顺序处理。

    /* 第二个 section 省略了重置的值,会被置默认值 0, section 将先重置为 2,最终重置为 0 */
    h1 { counter-reset: section 2 section; }
    
    /* 第一个 section 省略了递增的值,会被置默认值 1, section 先递增 1, 再递增 2, 相当于递增 3*/
    h1 { counter-increment: section section 2; }

    另外,counter-reset 属性遵循层叠原则,如果要同时重置两个计数器,它们必须同时指定。

    h1 { counter-reset: section 0 image 0; }
    
    /* 下面的写法会发生层叠导致只有一个计数器生效 */
    h1 { counter-reset: section 0; }
    h1 { counter-reset: image 0; }

    嵌套计数器与作用域

    计数器是自嵌套的,如果重置一个位于后代元素或伪元素的中的计数器,则会自动创建一个新的计数器实例。计数器的作用域从文档中具有 “counter-reset + 该计数器” 的第一个元素开始,包括该元素的后代和后续兄弟及其后代,但不包括处于同名计数器作用域中的任何元素。

    <style>
    ol {
        counter-reset: section;
        list-style-type: none;
    }
    li:before {
        counter-increment: section;
        content: "第" counters(section, ".") "章";
    }
    </style>
    <ol>
        <li>item</li>   <!--第1章-->
        <li>            <!--第2章-->
            <ol>
                <li>item</li> <!--第2.1章-->
            </ol>
        </li>
        <li>item</li>   <!--第3章-->
    </ol>

    效果如图所示

    display:none 的元素中的计数器

    一个 display 值设置为 none 的元素不会让计数器递增或重置,无法生成的伪元素也不会让计数器递增或重置,然而 visibility 被设置 hidden 的元素会让计数器递增或重置。

    列表

    一个具有display: list-item 的元素会为该元素的内容生成一个主块盒,还可能生成一个标记盒作为可视化指示,说明该元素是一个列表项。

    background 属性只适用于主盒,外部的标记盒是透明的。(不过,如果将 list-style-position 的值设置为 inside 的话,由于标记盒的背景是透明的,主盒设置的背景将会透过来,视觉上也相当于同时给主盒和标记盒加上了背景)。

    背景

    根据盒模型,背景指的是内容,内边距和边框区的背景。边框颜色和样式可以通过边框属性来设置,而外边距总是透明的。

    <style>
    .transparent-border {
        border: 10px solid rgba(0, 0, 0, 0);
        color: white;
        background: blue;
    }
    </style>
    
    <p class="transparent-border">将 border 的颜色设置为透明时,背景的颜色将透过来。</p>

    背景属性是不可继承的,但因为 background-color 的初始值为 transparent,父级盒的背景将透过来。

    另外,当同时设置 background-image 属性和 background-color 属性时,如果图像可用则将被渲染在背景色之上。这也意味着,在图像的透明部分,背景色是可见的。

    轮廓(outline)

    outline 与 border 的区别:

    • outline 不占空间,显示或隐藏不会导致重排或者溢出
    • outline 可以不是矩形的
    • 所有方向的 outline 都相同,与 border 相比,不存在 outline-top 或 outline-left 属性
    • 如果元素被拆分成了多行,与 border 相比,outline 在行框的开始或者结束出不是断开的,而是总会尽量完全连接起来(效果如下图)
    • 因为 outline 不影响格式化,它可能会与页面上的其他元素重叠

    outline-width 与 background-width 接受相同的值(hidden 除外)。

    outline-style 与 background-style 接受相同的值(hidden 除外)。

    outline-color 与 background-color 接受相同的值。此外 outline-color 还可以设置为 invert,用来对屏幕的像素取反色(但不是所有浏览器都支持该属性)。

    vi设计http://www.maiqicn.com 办公资源网站大全https://www.wode007.com

    默认样式

    在不指定字体大小的情况下,标题字号略粗于常规字体,h4 的字体大小和常规字体大小相同,h5 和 h6字体略小于常规字体。

    h1, h2, h3, h4, h5, h6 { font-weight: bolder; }
    h1 { font-size: 2em; margin: .67em 0; }
    h2 { font-size: 1.5 em; margin: .75em 0; }
    h3 { font-size: 1.17em; margin: .83em 0; }
    h4 { margin: 1.12em 0; }
    h5 { font-size: .83em; margin:1.5em 0; }
    h6 { font-size: .75em; margin: 1.67em 0; }

  • 相关阅读:
    Android传递中文参数方法(之一)
    配置类与yaml
    修改ip失败,一个意外的情况处理方法
    oracle 自增序列与触发器
    Excel导入数据带小数点的问题
    数据库null与空的区别
    小米手机无法打开程序报错Unable to instantiate application com.android.tools.fd.runtime.BootstrapApplication的解决办法
    gradle类重复的问题解决方法
    windowSoftInputMode属性讲解
    android studio 的配置
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/13761200.html
Copyright © 2020-2023  润新知