前端开发如何更好的避免样式冲突?级联层(CSS@layer)

这篇具有很好参考价值的文章主要介绍了前端开发如何更好的避免样式冲突?级联层(CSS@layer)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者:vivo 互联网前端团队 - Zhang Jiqi

本文主要讲述了CSS中的级联层(CSS@layer),讨论了级联以及级联层的创建、嵌套、排序和浏览器支持情况。级联层可以用于避免样式冲突,提高代码可读性和可维护性。

一、什么是级联层(Cascade Layers)?

1.1 级联层的官方定义

我们参看Cascading and Inheritance Level 5(13 January 2022) 中6.4节所述:

级联层提供了一种结构化的方式来组织和平衡单个起源中的问题。单个级联层内的规则级联在一起,不与层外的样式规则交错。

开发者可以创建层来表现元素默认值、第三方库、主题、组件、覆盖和其他样式问题,并且能够以显式方式重新排序层级,而无需更改每个层内的选择器或特异性,或依赖源顺序来解决跨层的冲突。

单纯看官方定义和概括可能比较晦涩,下面我们会结合案例来说清楚。

1.2 级联层为了解决什么问题?

简而言之:级联层的出现就是为了使 CSS 开发者可以更简单直接地控制级联。

我们来假设日常开发中的一个场景,从场景去理解级联层在解决什么问题。

如下图:

 

 

我们原来的'display'文案是红色,当我们引入了一个第三方组件库,第三方库中有以下样式。

/* 开发者样式 */
  .item {
    color: red;
  }
 
/* 第三方库 */
  #app .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    padding: 0.5em;
    width: 120px;
  }

就会导致'display'文案变成绿色。

我们想要将'display'文案的颜色由绿色改成红色一般的手段是增加选择器特异性(优先级)。比如在开发页面中对开发者样式进行修改:

/* 开发者样式 */
  #app div.item {
    color: red;
  }
 /* 第三方库 */
  #app .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    padding: 0.5em;
    width: 120px;
  }

或者借助级联中出场顺序对优先级的影响在用户页面中重写

/* 第三方库 */
  #app .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    padding: 0.5em;
    width: 120px;
  }
 /* 开发者样式 */
  #app .item {
    color: red;
  }

 效果如下:

 

 

再举个例子:

比如有可能第三方组件写了

a { color: blue; }

那项目开发中由于引入这个第三方组件 就会导致样式污染,因为第三方库的样式往往都在项目设置的通用样式比如common.css后加载。

如果后面想在代码中覆盖某些属性,使用高特异性选择器的语句就可能会导致问题。然后因为有问题就会选择更高特异性的择器的语句或使用!important,这会使代码变得冗长也可能会带来副作用。低特异性选择器的语句很容易被后面出现在代码中的语句覆盖。在自己的代码之后加载第三方 CSS 时特别会出现这种问题。

所以级联层就是为了解决以上场景出现的,级联层在级联中的的位置是在内联样式和选择器特异性之间。当有些css声明就是设置要低优先级且不受选择器特异性影响那么使用级联层再合适不过。

运用级联层解决第一个日常开发场景痛点的css代码如下:

/* 排序层 */
@layer reset, lib;
/* 通用样式 */
@layer reset {
  #app .item {
    color: black;
    width: 100px;
    padding: 1em;
  }
}
/* 第三方库样式 */
/*我们将第三方库的样式全部放到lib层*/
/*这里一般使用@import导入的方式*/
/*为了示例简单我们简化了操作*/

@layer lib {
  #app .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    width: 130px;
  }
}
/* 开发者样式 */
.item {
  color: red;
}

为了知道为什么上面的css代码能解决冲突问题,更好地理解级联层的作用,理解一些现象背后的根因,了解级联层和级联的关系,我们继续往下看。

二、理解级联层的前提——级联(cascade)

2.1 什么是级联?

CSS中有两个重要的基础规则,一个是继承,一个是级联。

继承

指的是类似 color,font-family,font-size,line-height 等属性父元素设置后,子元素会继承的特性。

级联

可以简单理解为是CSS 用来解决要应用于元素的具体样式的算法。也就是基于一些优先级排序输出给给定元素上属性值一个级联值。级联值是级联的结果。

2.2 当前级联的排序标准

我们参看Cascading and Inheritance Level 5(13 January 2022) 中6.1节,

相比于Cascading and Inheritance Level 4(14 January 2016) 中的定义有明显变化。

最重要的变化就是增加了级联层。由此级联排序变成:

  1. 起源和重要性(Origin and Importance)

  2. 上下文(Context)

  3. 样式属性(Element-Attached Styles)

  4. 层(Layers)

  5. 特异性(Specificity)

  6. 出场顺序(又名源代码顺序)(Order of Appearance)

浏览器在确定最终元素样式呈现的时候,会依据这些准则按照优先权从高到低排序,并且会一个一个的检查,直到确定最终样式。

2.3 级联起源(Cascading Origins)

2.3.1 三个核心起源

css中每个样式规则有三个核心起源,它决定了它进入级联的位置,理解起源优先级是理解级联的关键。

  • 用户代理来源(浏览器内置样式)

  • 用户来源(浏览器的用户设置 )

  • 作者来源(Web开发者)

2.3.2 起源的优先级

Css声明的起源取决于它来自哪里,重要性在于它是否用!important声明。

各种起源的优先级按降序排列:

  1. 过渡

  2. 重要的用户代理

  3. 重要用户

  4. 重要作者

  5. 动画

  6. 普通作者

  7. 普通用户

  8. 普通用户代理

越靠前来源的声明优先级越高。过渡和动画我们可以暂时忽略。

2.4 熟悉又陌生的 !important

通常作为开发者,!important会被我们视为一种增加特异性的方法,用以覆盖内联样式或特异性较高的选择器。

但是!important设计出来的初衷是作为整体级联中的一个特性,来平衡开发者、用户设置和浏览器内置之间对css优先级的影响能力。

默认情况下三者的优先级是:作者来源> 用户来源>用户代理来源(可以参看上文起源优先级中6-8的排序)。但是当css声明添加!important之后会使它们的优先顺序颠倒(参看上文起源优先级中2-4的排序)。

如果站在浏览器和用户的角度看!important提供了在必要时重获优先级控制权的能力,而非只是简单的增加特异性。

举个例子:

浏览器默认样式表包含我们开发者无法覆盖的重要样式。

浏览器对具有'hidden'类型的input输入框设置了默认的展示属性并且将其声明为重要。

input[type=hidden i] { display: none !important; }

看下面两张图例:

第一张可以看出我们对具有'hidden'类型的input输入框的展示属性设置成了显示并且声明为重要

 

第二张是样式最终计算结果:隐藏

从上面的浏览器表现可以看到我们作为开发者在作者样式表中设置的规则没能覆盖用户代理样式表中的相同规则。

这验证了上面说的:在级联中!important会颠倒三大核心起源默认优先顺序

验证的过程中还发现了一个chrome控制台这边的bug,看上面的第一张图例:没生效的规则不划删除线,生效的反而划删除线了。

再看一个官方文档的例子加强一下理解:

图片来源:w3.org

 

font-size的值最终是‘12pt ’

因为作者样式表中添加!important的规则优先权高于用户样式表中普通规则。

text-indent的值最终是‘1em’

因为虽然两个样式表都标注了!important,但是标注!important用户声明优先级大于标注!important作者声明。

2.5 一张图带你理解级联

下图可以帮助我们直观的理解级联以及级联层在级联中的位置:

图片来源:css-tricks

我们会发现平时操作最多的选择器特异性(selector specificity)只是级联中的一小部分。也轻松地理解了为什么内联样式优先级天然高。同时我们会发现!important在级联中有特殊地位。他穿插在级联规则的各个阶段并能颠倒优先级。

三、级联层(CSS@layer) 使用探索

3.1 @layer 是什么?

我们来看MDN上的定义:

The @layer CSS at-rule is used to declare a cascade layer and can also be used to define the order of precedence in case of multiple cascade layers.

也就是说 @layer 这个at-rule(AT规则) 用于声明级联层(cascade layer),也能用于定义多个级联层的优先级。

At-rules 是什么?

At-rules是指导 CSS 如何表现的CSS 语句。它们以 at 符号 ' @' ( U+0040 COMMERCIAL AT) 开头,后跟一个标识符,包括下一个分号 ' ;' ( U+003B SEMICOLON) 或下一个CSS 块之前的所有内容。

 

我们开发常见的at-rule有@charset、@media、@font-face 、@keyframes 等。

3.2 @layer的句法规则

@layer的句法如下:

@layer layer-name {rules}
@layer layer-name;
@layer layer-name, layer-name, layer-name;
@layer {rules}

3.3 如何创建级联层

可以通过多种方式创建级联层。

第一种方法是:创建命名的级联层,其中包含该层的 CSS 规则,如下所示:

@layer green {
  .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    padding: 0.5em;
    width: 120px;
  }
}
 
@layer special {
  .item {
    color: rebeccapurple;
  }
}

第二种方法是:创建一个命名的级联层而不分配任何样式。这可以是单层,如下所示:

@layer green;

可以一次定义多个层,如下:

@layer green, special

一次定义多个层有什么好处呢?

因为声明层的初始顺序决定了层的优先级。与声明一样,如果在多个层中找到声明,最后定义的层声明将最终生效。看下面代码:

@layer green,special;
 
@layer green {
  #app .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    padding: 0.5em;
    width: 120px;
  }
}
@layer special {
  .item {
    color: rebeccapurple;
  }
}

效果如下图:

special层中item样式规则将被应用即使它的特异性低于 green层中的规则。这是因为一旦层顺序定义完成,就会忽略选择器特异性

同样也会忽略出现的顺序:

我们声明层名称并设置它们的顺序后,可以通过重新声明名称来将 CSS 规则添加到图层。然后将样式附加到层,并且层顺序不会更改。比如如下代码虽然@layer green重新声明了并在文件后方但是由于顺序一开始已经设置所以字体颜色还是紫色:

@layer green,special;
 
@layer special {
  .item {
    color: rebeccapurple;
  }
}
 
@layer green {
  .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    padding: 0.5em;
    width: 120px;
  }
}

效果如下:

忽略选择器特异性和代码出现顺序可以让我们创建更简单的 CSS 选择器,并使代码优雅,因为不必确保选择器具有足够高的特异性来覆盖其他css规则,只需要确保它出现在后面的层中。

第三种方法是:创建一个没有名称的级联层。例如:

@layer {
  .item {
    color: black;
  }
}

这将创建一个匿名级联层,该层功能与命名层相同。但是使用匿名层有如下缺点:

  1. 可读性较差:匿名层没有名称,会导致样式表不易阅读和理解。特别是在大型项目中,可能会出现样式不断增加,难以跟踪和管理的问题。

  2. 难以扩展:如果稍后想要更改特定样式或组合,也会很难找到特定的代码块。

  3. 不可复用性:匿名层中的样式不能在其他地方重复使用或引用。这样会使样式表更难以管理和维护。

平时我们尽量避免使用匿名层。但当我们是样式库的作者,并想将某些css代码不被使用者修改可以借助匿名层做到这一点

第四种方法是:使用@import。CSS 原生支持 @import 导入其他 CSS 文件。

@import url(index.css) layer(index);

同时,也支持匿名引入,例如:

@import url(index.css) layer;

我们在使用@import时候需要放在除@charset之外的样式规则前,否则无法导入。

可能的第五种方式仍在讨论中:通过元素上的属性。请参阅[css-cascade] Provide an attribute for assigning ato a cascade layer #5853。

3.4 层的嵌套规则

图层可以嵌套。例如:

@layer base {
  p { max-width: 70ch; }
}
 
@layer framework {
  @layer base {
    p { margin-block: 0.75em; }
  }
 
  @layer theme {
    p { color: #222; }
  }
}

生成的层可以表示为一棵树:

1.base

  • framework

  • base

2.theme

或可以用扁平列表表示

  1. base

  2. framework.base

  3. framework.theme

要将样式附加到嵌套层,您需要使用以下全名来引用它:

@layer framework {
  @layer default {
     p { margin-block: 0.75em; }
  }
 
  @layer theme {
    p { color: #222; }
  }
}
 
@layer framework.theme {
  /* 这些样式会被添加到framework层里面的theme层 */
  blockquote { color: rebeccapurple; }
}

看效果:

3.5 层的排序规则

级联层按照它们声明的顺序排序。第一层优先级最低,最后一层优先级最高。但是,未分层的样式具有最高优先级:

/* 未分层 */a { color: green; }
@layer layer-1 { a { color: red; } }
@layer layer-2 { a { color: orange; } }
@layer layer-3 { a { color: yellow; } }

优先级顺序如下:

  1. 未分层样式

  2. layer-3

  3. layer-2

  4. layer-1

看下图示例:

层可以在一个地方被定义图层(以建立图层顺序),然后在任何地方添加样式

/* 定义在一个地方 */
@layer my-layer;
/* 其他样式*/
...
/* 在某个地方添加样式 */
@layer my-layer { a { color: red; } }

3.6 加上!important之后的排序规则

/* 未分层 */ a { color: green !important; }
@layer layer-1 { a { color: red !important; } }
@layer layer-2 { a { color: orange !important; } }
@layer layer-3 { a { color: yellow !important; } }

任何加上重要声明的样式都以相反的顺序应用

优先级顺序如下:

  1. !important layer-1

  2. !important layer-2

  3. !important layer-3

  4. !important 未分层样式

看下图示例:

这里我们看到对应规则在chrome浏览器的显示是正确的。但是在开发者控制台中的样式一栏规则显示有问题。应该是chrome浏览器开发者控制台的bug。

3.7 嵌套层的排序规则

@layer layer-1 { a { color: red; } }
@layer layer-2 { a { color: orange; } }
@layer layer-3 {
  @layer sub-layer-1 { a { color: yellow; } }
  @layer sub-layer-2 { a { color: green; } }
  /* 未嵌套 */ a { color: blue; }
}
/* 未分层 样式 */ a { color: black; }

优先级顺序如下:

  1. 未分层 样式

  2. layer-3

    -layer-3 未嵌套

    -layer-3 sub-layer-2

    -layer-3 sub-layer-1

  3. layer-2

  4. layer-1

3.8 媒体查询对层排序的影响

以下层顺序将取决于匹配的媒体条件

例如:

@media (min-width: 600px) {
   @layer layout {
     .item {
       font-size: x-large;
     }
   }
 }
 
@media (prefers-color-scheme: dark) {
  @layer theme {
     .item {
        color: red;
     }
   }
}

如果两个媒体查询的规则中匹配一个那么对应的级联层生效。如果两者都匹配,那么图层顺序将为layout, theme都生效。如果两个都不匹配则不定义层。下图是两者都匹配的场景。

四、现在就能使用级联层吗?

4.1 目前浏览器支持程度

 

图片来源:developer.mozilla.org

目前所有现代浏览器均已经支持 @layer 规则。所有浏览器厂商都支持的特性未来一定比较实用。

4.2 W3C 鼓励可以作为日常使用

SS 的标准化流程由 W3C Cascading Style Sheets Working Group (CSSWG)——W3C层叠样式列表小组以及独立CSS专家组成。W3C 本身并不制定标准,而是作为一个论坛式的平台,接收来自小组成员的提交,并通过会议来商讨制定标准,所有的提交以及讨论都是公开透明的,可以在 W3C 网站上看到会议的记录,可以简单分为4个大阶段:

  • 工作草案( WD )

  • 候选人推荐( CR )

  • 提议的建议( PR )

  • W3C 推荐( REC )

下图可以帮助理解:

图片来源:w3.org

W3C 通过状态码表示规范的成熟度。成熟度从低到高排序如下图。

图片来源:w3.org

再看下图:包含layer概念的标准讨论已经到达CR阶段。

图片来源:w3.org

W3C 鼓励从 CR阶段的标准 开始可以作为日常使用。

五、总结

最后,我们回到通过级联层如何解决“引入了一个第三方组件库导致样式覆盖“的问题上。

css代码如下:

/* 排序层 */
@layer reset, lib;
/* 通用样式 */
@layer reset {
  #app .item {
    color: black;
    width: 100px;
    padding: 1em;
  }
}
/* 第三方库样式 */
/*我们将第三方库的样式全部放到lib层,这里一般使用@import导入的方式,为了示例简单我们简化了操作*/
@layer lib {
  #app .item {
    color: green;
    border: 5px solid green;
    font-size: 1.3em;
    width: 130px;
  }
}
/* 开发者样式 */
.item {
  color: red;
}

我们将第三方库的样式全部放到lib层,将需要重置的一些样式放到reset层,自己开发的样式不放入层中(当然你也可以放入到一层然后排序在最后)。由此我们实现了样式的分层解决了第三方组件库导致样式覆盖的问题,而且做到开发者样式简单不冗长。

效果如下:

级联层(CSS@layer)已经历概念提出到到浏览器全面支持的阶段。也许在不久的将来大家都会普遍使用它,期望本文能给大家带来一定帮助。

参考资料:

  1. CSS Cascading and Inheritance Level 5

  2. A Complete Guide to CSS Cascade Layers

  3. The Future of CSS: Cascade Layers (CSS @layer)

  4. CSS必学基础:理解CSS中的级联规则

  5. 详解日后定会大规模使用的CSS @layer 规则

  6. W3C Process Document

  7. Cascade Layers Explainer文章来源地址https://www.toymoban.com/news/detail-464229.html

到了这里,关于前端开发如何更好的避免样式冲突?级联层(CSS@layer)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 探讨前后端分离开发的优势、实践以及如何实现更好的用户体验?

    随着互联网技术的迅猛发展,前后端分离开发已经成为现代软件开发的一种重要趋势。这种开发模式将前端和后端的开发工作分开,通过清晰的接口协议进行通信,旨在优化开发流程、提升团队协作效率,并最终改善用户体验。 本文将深入探讨前后端分离开发的优势、实践以

    2024年02月09日
    浏览(44)
  • 【 安全】什么是CSRF攻击?如何避免?开发的时候怎么预防?

    CSRF定义: 跨站请求伪造(英语:Cross-site request forgery)是一种对网站的恶意利用,也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。 CSRF跨站点请求伪造(Cross—Site Request Forgery) 跟

    2024年03月14日
    浏览(88)
  • 【python实操】如何通过简单拖拽直接开发软件,避免手写界面布局

    python学习之路任重而道远,要想学完说容易也容易,说难也难。 很多人说python最好学了,但扪心自问,你会用python做什么了? 刚开始在大学学习c语言,写一个飞行棋的小游戏,用dos界面来做,真是出力不讨好。 地图要自己一点一点画出来,就像这样: 从此讨厌编程,不想

    2024年01月16日
    浏览(89)
  • vue3 + Tailwind Css + Vite 搭建快速开发前端样式环境

    一个功能类优先的 CSS 框架,用于快速构建定制的用户界面。这是来自 TailwindCss 官方定义。 中文网站 Tailwindcss 基于原子化理念,将样式重复性代码降到最小,原本开发最大限度基于类名的声明块不重复,现在Tailwindcss基于单独一句声明不重复。 活跃度 github starts 数量达到

    2024年02月04日
    浏览(69)
  • Vue:多组件样式冲突问题解决

    我们在开发 Vue 项目的时候,会有很多的组件,每个组件里,可能都会写相应的样式,这时候就会出现在父组件引入子组件的时候,同名样式会冲突的问题。从而导致样式出问题。 给 style 标签加上 scoped 属性即可 加上 scoped 之后,这个样式只会作用在当前组件的 html 模板上。

    2024年02月02日
    浏览(39)
  • 如何在CSS中写变量?一文带你了解前端样式利器

    目录 引言 概念 语法 基本用法 使用场景 全局变量 局部变量 ​编辑 媒体查询变量 动态定义 继承变量 自变量 与其他方案的区别 使用方式上 作用域的区别 编译产物 功能及拓展 总结 写在最后 前端的变量写法大致可以分为三大类,分别是CSS-in-JS,CSS预处理器,和CSS原生变量

    2024年02月06日
    浏览(52)
  • 【Git】在idea中多分支开发如何——合并分支、处理冲突

    博主简介: 22级计算机科学与技术本科生一枚🌸 博主主页:是瑶瑶子啦 每日一言🌼: “人间总有一两风,填我十万八千梦” 我当前开发的分支—— hfy 我想将 subject 分支的最新代码拉取合并到 hfy 分支 点击之后会出现界面,有需要你处理的冲突( 冲突的处理的本质就是:你

    2024年04月17日
    浏览(81)
  • Ant的 select选择器和Cascader 级联选择器下拉选框随着页面滑动样式脱离

     在select标签和cascader标签里添加  :getPopupContainer=\\\"(triggerNode:any) = (triggerNode.parentElement)\\\" 即可  

    2024年02月15日
    浏览(39)
  • el-date-picker自定义选择时间&&el-time-select自定义选择时间实现避免时间冲突

    固定十二个月,当月开始时间默认选择月第一天,结束时间默认选择月最后一天; 月份选择只允许选择当前月份 将当月对应的每天按照时间段划分,段数不做限制。 时间段支持任意位置插入(新增)、删除。 每个时间段具有包含属性,同一时刻不允许在两个时间段中出现包

    2024年02月05日
    浏览(45)
  • uniapp开发小程序如何修改picker选中样式及选中字体样式

    需求1:修改选中的样式 需求2:修改选中字体的颜色 indicator-class 设置选择器中间选中框的类名 2.修改选中后字体的样式(重要代码段) //选中字体样式 .pickerSelected { color: #ffffff !important; z-index: 2; } 这边是改造uview的picker组件全部代码

    2024年02月11日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包