我正在 Angular 中构建一个 UI 库,并且经常指定要使用通用类设置样式的元素,例如
.slider
或 .form-control
。我遇到的问题是,有时消费者(使用该库的人)对自己的元素使用相同的类,当他应用样式时,它会无意中破坏库的 UI。
Angular 确实提供了作用域类,所以如果我有这样的风格:
.form-control { line-height: 2em; }
然后在运行时,Angular 修改它以动态添加组件特定属性:
.form-control[ng_content0] { line-height: 2em; }
并且因为该属性是动态添加到元素本身的,所以我的样式不会溢出并影响使用该库的客户端的元素。
太好了。但是我该如何防止逆转呢?基本上,当存在类名冲突时,我如何以一种限制消费者破坏事物的方式使用 CSS?我唯一想过的就是在所有类名前加上前缀。某种简陋的命名空间:
.mylib_form-control { line-height: 2em; }
什么是正确的做法?
基本上,我如何以一种限制消费者的方式使用 CSS 当类名冲突时破坏东西?
我认为更重要的是尝试防止类名冲突,而不是处理发生冲突时发生的情况。如果存在冲突,假设选择器具有相同的 specificity 最后定义的样式将获胜。因此,取决于消费者是在他们自己的样式之前还是之后添加您的库,这将影响适用的冲突规则。如果您认为您的库非常重要,您可以将 !important 添加到所有库样式中。这是个坏主意。你应该尽量避免冲突。
你也许可以为你所有的类添加一个前缀,比如
beetle-ui
我会假设消费者没有任何以此开头的类。
你可以做一些像语义 UI 这样的事情,并且要让 HTML 元素采用库的样式,它的类列表中必须有类
ui
。然后你所有的选择器看起来像:
.ui.input {
}
.ui.header {
}
相应的 HTML 类似于:
<input class="ui input" />
我会像我的第一个例子那样做一些事情,并使用 BEM 并使用 SASS 定义我的 CSS,这样我的语法可以更清晰一些,并从前缀中受益。
.beetle-ui-form {
background-color: grey;
&__input {
outline: red;
}
}
这会生成如下 CSS:
.beetle-ui-form {
background-color: grey;
}
.beetle-ui-form__input {
outline: red;
}
根据我的经验,构建组件库依赖于在易于定制和保护组件库样式之间取得平衡。 我会说对于图书馆来说,使用前缀几乎总是一个好主意。 我也同意 ryanm 的观点,使用
!important
不是一个好主意,它在大多数情况下不允许自定义任何样式。
在我的案例中,库是一些使用它的项目的关键/核心部分。 这就是为什么我和我的同事决定使用 Sass 来设计样式,并方便地将我们所有的类选择器嵌套在父 ID 选择器中,这样可以提高特异性,但不会为我们做太多额外的工作。
此外,当我们为我们的组件设置文本样式时,我们尝试将样式设置得尽可能低,例如,如果我想使用类
<a>
为 div
内的所有 myParentName
标签设置样式,我会这样做:
.myParentClass a {
color: red;
}
代替
.myParentClass {
color: red;
}
除此之外,我们创建了一份仅包含大约 5 点的简短文档,以帮助开发人员使用我们的库,这样他们就不会无意中覆盖任何样式,而是有意覆盖。 因此,警告他们可能是个好主意,例如在某些情况下不要使用像下面这样的选择器,因为它们可能会影响库样式:
.myParentElement > div,
.myParentElement *