是否有基于 CSS 自定义属性创建可主题化组件变体的最佳实践?
Are there best practices for creating themeable component variants based on CSS custom properties?
我目前正在与一个开发大量网络组件的团队合作,这些组件应该是客户公司当前和即将开发的网络应用程序的基础。
我希望这些组件支持颜色主题;第一个用例是支持 暗模式 .
当前方法
我已经在文件中定义了客户的公司设计颜色colorpalette.css
(颜色只是一个例子):
:root {
--color-blue: #004994;
--color-light-blue: #0095db;
--color-light-green: #afca06;
--color-light-grey: #9c9c9c;
--color-green: #51ae31;
--color-grey: #555555;
--color-orange: #f39200;
--color-red: #d40f14;
--color-turquoise: #008c8e;
--color-violet: #b80d78;
--color-yellow: #ffcc00;
--color-white: #ffffff;
--color-black: #000000;
}
我正在确保使用或定义颜色的所有其他文件仅使用此文件中的颜色。这会生成一个文件 colors.css
,我在其中开始为每个主题定义不同的颜色:
@import "./colorpalette.css";
:root {
--bg-color-button: var(--color-light-grey);
--text-color-button: var(--color-black);
--border-color-button: var(--color-grey);
}
:root[data-theme=dark] {
--bg-color-button: var(--color-grey);
--text-color-button: var(--color-white);
--border-color-button: var(--color-light-grey);
}
到目前为止,我对这种方法很满意。
问题
现在我开始添加这些按钮的不同语义版本:.btn-danger
、.btn-success
等,它们应该使用颜色作为传输这些语义的手段。
可能的解决方案 - 两种不同的选择
这里是我不确定要采用哪种方式来实现这一目标的地方,因为我看到了 2 个备选方案:
为这些语义创建新的变量,在它们的名字中携带语义:
:root {
--bg-color-button-success: var(--color-light-green);
--text-color-button-success: var(--color-black);
--border-color-button-success: var(--color-green);
}
并在按钮样式定义中使用这些:
.btn {
background-color: var(--bg-color-button);
color: var(--text-color-button);
border-color: var(--border-color-button);
}
.btn.btn-success {
background-color: var(--bg-color-button-success);
color: var(--text-color-button-success);
border-color: var(--border-color-button-sucess);
}
- 优点
- 您可以通过仅修改两个文件来重新设置整个应用程序的主题。
- 缺点
- 这种方法显然会产生大量的变量,因为我们需要为每个需要应用不同颜色的地方定义一个单独的变量。
- 如果您稍后想要引入其他按钮变体,则必须同时编辑
colors.css
和 button.css
。
另一种方法可能是重新定义指定上下文中的现有变量:
.btn {
background-color: var(--bg-color-button);
color: var(--text-color-button);
border-color: var(--border-color-button);
}
.btn.btn-success {
--bg-color-button: var(--color-light-green);
--text-color-button: var(--color-black);
--border-color-button: var(--color-green);
}
- 优点
- 很多变量少。
- 变量只会在实际使用的地方重新定义。
- 定义新按钮变体比其他方法更容易,因为您只需要编辑
button.css
.
- 缺点
- 要重新设置组件库的主题,除了
colorpalette.css
和 colors.css
. 之外,您可能还需要触及每个组件的 css 文件
我试图总结两种方法的优缺点。
问题
还有哪些其他原因使您更喜欢其中一种方式?
提示
在最终投票结束前请考虑以下:
我知道很多人可能会认为这个问题离题,因为它吸引了自以为是的答案,但我确信这个问题很多 对于许多开发人员来说具有实际意义,因为 css 自定义属性最近才成为事实上的标准,这通常会导致最佳实践的出现缓慢。所以自以为是的答案 以及这些观点的原因 正是我在这里要问的 故意 .
这也绝不是 Best Practices - CSS Theming 的重复,因为该问题来自 2010 年,当时 css 自定义属性不存在。
在我看来,主题系统的优先级要求是容易改变外观。所以你的第一个解决方案适合这种情况。说说它的缺点吧。
This approach obviously results in a myriad of variables, as we need to define a separate variable for each place where we need to apply a
different color.
需要更多变量。因为它们有不同的用途。当您重新设计主题时,它会帮助您快速更改外观,而无需查看所有组件文件。你只需要关心它以防万一重新设计主题。所以我觉得不应该算作缺点
If you later want to introduce additional button variations, you'd
have to edit both colors.css
and button.css
.
同样,我不认为这是缺点,因为您只需要在 2 个文件中添加一些额外的代码。而且这些代码不会影响之前存在的任何东西。
但是您忘记提及这种方法的最大缺点。您需要重写 CSS 规则。如果我们使用渐变背景会发生什么?代码将是这样的:
.btn {
background: linear-gradient(to left, var(--text-color-button-1), var(--text-color-button-2) 50%, var(--text-color-button-3) 75%, var(--text-color-button-4) 75%);
color: var(--text-color-button);
border-color: var(--border-color-button);
}
.btn.btn-success {
background: linear-gradient(to left, var(--text-color-button-success-1), var(--text-color-button-success-2) 50%, var(--text-color-button-success-3) 75%, var(--text-color-button-success-4) 75%);
color: var(--text-color-button-success);
border-color: var(--border-color-button-sucess);
}
如果我们想把50%这个数字改成另一个数字,那将是一场噩梦。
因此,让我们将您的两种方法合二为一,解决它们的缺点。
这是给想要快速扫描的人的解决方案:
color.css
--color-red-100: red;
--color-red-500: red;
--color-red-900: red;
--color-green-100: green;
--color-green-500: green;
--color-green-900: green;
--color-bg-button-1: var(--color-red-100);
--color-bg-button-2: var(--color-red-500);
--color-bg-button-3: var(--color-red-900);
--color-bg-button-4: var(--color-red-100);
--color-bg-button-success-1: var(--color-green-100);
--color-bg-button-success-2: var(--color-green-500);
--color-bg-button-success-3: var(--color-green-900);
--color-bg-button-success-4: var(--color-green-100);
button.css
.btn {
background: linear-gradient(to left, var(--text-color-button-1), var(--text-color-button-2) 50%, var(--text-color-button-3) 75%, var(--text-color-button-4) 75%);
}
.btn.btn-success {
--text-color-button-1: var(--color-bg-button-success-1);
--text-color-button-2: var(--color-bg-button-success-2);
--text-color-button-3: var(--color-bg-button-success-3);
--text-color-button-4: var(--color-bg-button-success-4);
}
在这种方法中:
- 通过使用基色变量,如果你只是想调整一些灰色阴影,你只需要改变基色变量,按钮和其他任何东西都会相应地改变.
- 通过使用范围变量但链接到新变量,您无需重写 CSS 规则,只需在一个文件中编辑变量值即可轻松重新设计主题。
- 当然,这种方法仍然有您第一个解决方案的两个缺点,但我认为它可以接受更高优先级的要求。
对我来说,最佳实践应该放在特定的上下文中,所以这个解决方案正好适合您的首要任务是轻松重新设计主题。如果您只是想使用 CSS 变量来轻松重用并且没有任何更改变量值的计划,那么应该选择 OP 的第二个解决方案以进行快速编程。
我目前正在与一个开发大量网络组件的团队合作,这些组件应该是客户公司当前和即将开发的网络应用程序的基础。
我希望这些组件支持颜色主题;第一个用例是支持 暗模式 .
当前方法
我已经在文件中定义了客户的公司设计颜色
colorpalette.css
(颜色只是一个例子)::root { --color-blue: #004994; --color-light-blue: #0095db; --color-light-green: #afca06; --color-light-grey: #9c9c9c; --color-green: #51ae31; --color-grey: #555555; --color-orange: #f39200; --color-red: #d40f14; --color-turquoise: #008c8e; --color-violet: #b80d78; --color-yellow: #ffcc00; --color-white: #ffffff; --color-black: #000000; }
我正在确保使用或定义颜色的所有其他文件仅使用此文件中的颜色。这会生成一个文件
colors.css
,我在其中开始为每个主题定义不同的颜色:@import "./colorpalette.css"; :root { --bg-color-button: var(--color-light-grey); --text-color-button: var(--color-black); --border-color-button: var(--color-grey); } :root[data-theme=dark] { --bg-color-button: var(--color-grey); --text-color-button: var(--color-white); --border-color-button: var(--color-light-grey); }
到目前为止,我对这种方法很满意。
问题
现在我开始添加这些按钮的不同语义版本:.btn-danger
、.btn-success
等,它们应该使用颜色作为传输这些语义的手段。
可能的解决方案 - 两种不同的选择
这里是我不确定要采用哪种方式来实现这一目标的地方,因为我看到了 2 个备选方案:
为这些语义创建新的变量,在它们的名字中携带语义:
:root { --bg-color-button-success: var(--color-light-green); --text-color-button-success: var(--color-black); --border-color-button-success: var(--color-green); }
并在按钮样式定义中使用这些:
.btn { background-color: var(--bg-color-button); color: var(--text-color-button); border-color: var(--border-color-button); } .btn.btn-success { background-color: var(--bg-color-button-success); color: var(--text-color-button-success); border-color: var(--border-color-button-sucess); }
- 优点
- 您可以通过仅修改两个文件来重新设置整个应用程序的主题。
- 缺点
- 这种方法显然会产生大量的变量,因为我们需要为每个需要应用不同颜色的地方定义一个单独的变量。
- 如果您稍后想要引入其他按钮变体,则必须同时编辑
colors.css
和button.css
。
- 优点
另一种方法可能是重新定义指定上下文中的现有变量:
.btn { background-color: var(--bg-color-button); color: var(--text-color-button); border-color: var(--border-color-button); } .btn.btn-success { --bg-color-button: var(--color-light-green); --text-color-button: var(--color-black); --border-color-button: var(--color-green); }
- 优点
- 很多变量少。
- 变量只会在实际使用的地方重新定义。
- 定义新按钮变体比其他方法更容易,因为您只需要编辑
button.css
.
- 缺点
- 要重新设置组件库的主题,除了
colorpalette.css
和colors.css
. 之外,您可能还需要触及每个组件的 css 文件
- 要重新设置组件库的主题,除了
- 优点
我试图总结两种方法的优缺点。
问题
还有哪些其他原因使您更喜欢其中一种方式?
提示
在最终投票结束前请考虑以下:
我知道很多人可能会认为这个问题离题,因为它吸引了自以为是的答案,但我确信这个问题很多 对于许多开发人员来说具有实际意义,因为 css 自定义属性最近才成为事实上的标准,这通常会导致最佳实践的出现缓慢。所以自以为是的答案 以及这些观点的原因 正是我在这里要问的 故意 .
这也绝不是 Best Practices - CSS Theming 的重复,因为该问题来自 2010 年,当时 css 自定义属性不存在。
在我看来,主题系统的优先级要求是容易改变外观。所以你的第一个解决方案适合这种情况。说说它的缺点吧。
This approach obviously results in a myriad of variables, as we need to define a separate variable for each place where we need to apply a different color.
需要更多变量。因为它们有不同的用途。当您重新设计主题时,它会帮助您快速更改外观,而无需查看所有组件文件。你只需要关心它以防万一重新设计主题。所以我觉得不应该算作缺点
If you later want to introduce additional button variations, you'd have to edit both
colors.css
andbutton.css
.
同样,我不认为这是缺点,因为您只需要在 2 个文件中添加一些额外的代码。而且这些代码不会影响之前存在的任何东西。
但是您忘记提及这种方法的最大缺点。您需要重写 CSS 规则。如果我们使用渐变背景会发生什么?代码将是这样的:
.btn {
background: linear-gradient(to left, var(--text-color-button-1), var(--text-color-button-2) 50%, var(--text-color-button-3) 75%, var(--text-color-button-4) 75%);
color: var(--text-color-button);
border-color: var(--border-color-button);
}
.btn.btn-success {
background: linear-gradient(to left, var(--text-color-button-success-1), var(--text-color-button-success-2) 50%, var(--text-color-button-success-3) 75%, var(--text-color-button-success-4) 75%);
color: var(--text-color-button-success);
border-color: var(--border-color-button-sucess);
}
如果我们想把50%这个数字改成另一个数字,那将是一场噩梦。 因此,让我们将您的两种方法合二为一,解决它们的缺点。
这是给想要快速扫描的人的解决方案:
color.css
--color-red-100: red;
--color-red-500: red;
--color-red-900: red;
--color-green-100: green;
--color-green-500: green;
--color-green-900: green;
--color-bg-button-1: var(--color-red-100);
--color-bg-button-2: var(--color-red-500);
--color-bg-button-3: var(--color-red-900);
--color-bg-button-4: var(--color-red-100);
--color-bg-button-success-1: var(--color-green-100);
--color-bg-button-success-2: var(--color-green-500);
--color-bg-button-success-3: var(--color-green-900);
--color-bg-button-success-4: var(--color-green-100);
button.css
.btn {
background: linear-gradient(to left, var(--text-color-button-1), var(--text-color-button-2) 50%, var(--text-color-button-3) 75%, var(--text-color-button-4) 75%);
}
.btn.btn-success {
--text-color-button-1: var(--color-bg-button-success-1);
--text-color-button-2: var(--color-bg-button-success-2);
--text-color-button-3: var(--color-bg-button-success-3);
--text-color-button-4: var(--color-bg-button-success-4);
}
在这种方法中:
- 通过使用基色变量,如果你只是想调整一些灰色阴影,你只需要改变基色变量,按钮和其他任何东西都会相应地改变.
- 通过使用范围变量但链接到新变量,您无需重写 CSS 规则,只需在一个文件中编辑变量值即可轻松重新设计主题。
- 当然,这种方法仍然有您第一个解决方案的两个缺点,但我认为它可以接受更高优先级的要求。
对我来说,最佳实践应该放在特定的上下文中,所以这个解决方案正好适合您的首要任务是轻松重新设计主题。如果您只是想使用 CSS 变量来轻松重用并且没有任何更改变量值的计划,那么应该选择 OP 的第二个解决方案以进行快速编程。