在 React 中使用 Less + CSS Modules 切换主题
Posted
技术标签:
【中文标题】在 React 中使用 Less + CSS Modules 切换主题【英文标题】:Switching themes using Less + CSS Modules in React 【发布时间】:2020-05-04 08:34:45 【问题描述】:在我的项目中,我使用带有 Less 的 CSS 模块,这意味着我可以两全其美。
我的src
文件夹如下所示:
components/
[all components]
theme/
themes/
lightTheme.less
darkTheme.less
palette.less
palette.less:
@import './themes/lightTheme.less';
然后,在每个想要使用主题颜色的组件中,我都会这样做:
component.module.less:
@import '../../theme/palette.less';
.element
background-color: @primary;
这个结构让我可以编辑palette.less
来导入我想使用的主题。问题是我想让用户自己选择他们喜欢的主题。主题应该可以在运行时切换,这意味着我需要编译两个主题。
我认为完美的解决方案是这样的:
app.less
body
@theme: @light-theme;
&.dark-theme
@theme: @dark-theme;
然后以某种方式在每个组件中导入这个@theme
变量并从中读取属性(即@theme[primary]
)。
不幸的是,Less 变量的作用域不能像这样工作。
我对任何使用 Less 模块的解决方案持开放态度。
谢谢!
【问题讨论】:
你应该在 light-theme 之前添加@include @Ranjithv 这只是一些伪代码来展示我的想法 你应该看看css变量developer.mozilla.org/en-US/docs/Web/CSS/… 最好的解决方案是css in js
,比如样式组件、情感等。然后使用ThemeProvider
,可以很容易地以编程方式切换多个主题
Ahalan @gaditzkhori,我们不想使用 styled-components,因为它使我们的 CSS 方式更加混乱(那些 .styled.js
文件,一切都是组件,但它们绝对不是...... )
【参考方案1】:
我知道您可能一直在寻找使用 Less / CSS 模块的解决方案,但很可能您的情况可以仅通过使用 css 变量来解决(正如 Morpheus 对您的问题所评论的那样)。
它是如何工作的?
您必须确保所有样式不使用硬编码值,即,而不是:
.awesome-div
background-color: #fefefe;
你会:
:root
--awesome-color: #fefefe;
.awesome-div
background-color: var(--awesome-color);
明暗交替
在这种方法中有两种改变主题的方法:
在 React 中使用 vanilla Js 代码更新:root
CSS 元素,查看此 codepen 了解更多信息;
只需在其 component.css 文件中加载包含所有新 :root
变量的组件;
在 React 中(在原版 CSS 中也是如此),您可以轻松地让多个组件/元素在其 .css 文件中声明自己的 :root
。
此外,任何新的:root
都将覆盖之前:root
的冲突值。例如,如果在 app.css 文件中我们有 :root --color: red;
,并且在加载另一个组件时,例如组件 A,在 component_a.css 中我们有相同的变量被覆盖,例如:root --color: blue;
在我们的浏览器中呈现的那个将是来自组件 A 的那个。
按照这个逻辑,你可以有一个虚拟组件,它什么都不做,什么也不渲染,但是在这个 component.js 文件中你导入一个主题的 .css,例如:
import './light.css'; // suppose this is the light-theme dummy component
在您的应用中切换主题时,您只需从场景中移除虚拟组件并调用另一个。
我对 codepen 不太熟悉,无法在此处为您提供一个包含导入/模块的示例,但我希望上述解释可以让您了解我的意思。不过,这里是我打算演示的简短伪代码:
loadTheme()
if (this.state.theme === 'dark') return <LightTheme />;
if (this.state.theme === 'user-3232') return <UserTheme />;
return <DarkTheme />;
render()
return (
<App>
this.loadTheme()
<OtherContent>
</App>
);
【讨论】:
CSS 变量是一个很酷的解决方案,但它消除了我进行值操作(例如褪色)的选项。 您可以在 .less 文件中声明您的 css 变量并使用值操作 您也可以使用 CSS 变量模拟褪色;实际上,我在生产中经常这样做,即声明--fade-me: 200, 215, 225
然后使用这个变量,如下所示:border-color: rgba(var(--fade-me), 0.2)
。它不像使用 CSS 预处理器那么简单,但与我预期的相比,它允许我保持一个相对有组织的 CSS 代码库。不过,如果在您的项目中您过于依赖 Less,那么我建议您坚持使用它,我会在此处留下我的答案,因为使用纯 CSS 的人可能会从中受益。顺便说一句,我希望你在这里找到解决方案。
我看不出带有“导入主题”的示例如何工作。主题的导入会在构建时导入css,最后一个获胜。【参考方案2】:
查看 Styled 组件,它可以做到这一点。
https://www.npmjs.com/package/styled-components
https://styled-components.com/docs/advanced#theming
我自己在我的一个应用程序中作为复活节彩蛋做的,所以我确信它有效。不幸的是,它已关闭,因此我无法公开向您展示代码。
【讨论】:
正如我在 cmets 中所说,我们不想使用 styled-components,因为它让我们的 CSS 变得更加混乱(那些 .styled.js 文件,一切都是组件,但它们绝对不是...) 如果您不想使用,则不必使用 .styled.js 文件。此外,如果您喜欢的话,您可以创建一个包含所有样式的 one 样式组件。然后,您可以将您的应用包装在该组件周围,并将 CSS 保存在同一个文件中。以上是关于在 React 中使用 Less + CSS Modules 切换主题的主要内容,如果未能解决你的问题,请参考以下文章
在最新的 Create React App 中使用 LESS CSS