在 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

React16.8搭建支持Less文件的开发环境

react中利用sass配置来做移动端适配(vw/vh)

create-react-app使用less

我可以在 webpack 中构建 sass/less/css 而无需在我的 JS 中使用它们吗?

基于create-react-app脚手架,按需加载antd组件以及less样式