如何使用Vite和Lit动态更改整个站点的CSS?

huangapple go评论73阅读模式
英文:

How to change CSS dynamically for whole site with vite and lit?

问题

Dear all, 我正在开发一个使用 Vite 和 Lit 的 Node 应用程序。我希望用户可以在运行时动态更改样式,例如在整个站点之间选择暗黑和明亮的主题。

我知道您可以直接import“css”文件并将其应用于单个 Lit 元素。但是如何在整个站点上动态更改样式呢?我还注意到ìmport from "xxxx.css"不能包含动态变量,因此以下内容似乎不受支持?

let theme = "dark"
import "folder/" + theme + ".css";

有什么建议可以帮助我实现这个目标吗?

英文:

Dear all I am developing a node app with vite and lit. I like to have the option that the user can change the style dynamically at runtime for instance to select between a dark and bright theme for the whole site.

I know that you can directly import "css" files and apply it on single lit elements. But how I can change the style dynamically for the whole site? I also noticed that an ìmport from "xxxx.css" can not contain a dynamic variable,so the following seems not to be supported?

let theme = "dark"
import "folder/" + theme + ".css";

Any suggestion how I can best achieve my goal?

答案1

得分: 1

这最好通过将所有元素中的颜色设置为CSS自定义属性来处理。例如:

class MyCustomCard extends LitElement {
  static styles = css`
    .card {
      /* 设置自定义属性和默认值 */
      background-color: var(--sys-color-surface, #FFF);
      color: var(--sys-color-on-surface, #000);
      ...
    }
  `;
  ...
}

然后,您可以在文档的根目录下创建一个名为theme.css的主题文件。例如:

<!-- index.html -->
<head>
  <link rel="stylesheet" href="theme.css">
</head>
/* theme.css */
/* 亮色主题 */
:root, body.force-light-mode {
  --sys-color-surface: #FFF;
  --sys-color-on-surface: #000;
  ...
}
/* 自动暗色主题 */
@media (prefers-color-scheme: dark) {
  :root {
    --sys-color-surface: #000;
    --sys-color-on-surface: #FFF;
    ...
  }
}

/* 用户偏好的暗色模式 */
body.force-dark-mode {
  /* 这可以使用 @import 来去重复 https://developer.mozilla.org/en-US/docs/Web/CSS/@import */
  --sys-color-surface: #000;
  --sys-color-on-surface: #FFF;
  ...
}

然后,您可以创建一个切换暗色主题的切换按钮,该按钮会在body上切换force-*-mode类:

class ThemeToggle extends LitElement {
  render() {
    return html`
      <div>Select Theme</div>
      <label>
        Light Mode
        <input
            type="radio"
            @change=${this.onChange('light')}
            name="theme">
       </label>
      <label>
        Follow System
        <input
            type="radio"
            @change=${this.onChange('system')}
            name="theme"
            checked>
       </label>
      <label>
        Dark Mode
        <input
            type="radio"
            @change=${this.onChange('dark')}
            name="theme">
       </label>`
  }

  onChange = (mode) => (e) => {
    if (e.target.checked) {
      switch(mode) {
        case 'light':
          document.body.classList.add('force-light-mode');
          break;
        case 'dark':
          document.body.classList.add('force-dark-mode');
          break;
      }
    } else {
      switch(mode) {
        case 'light':
          document.body.classList.remove('force-light-mode');
          break;
        case 'dark':
          document.body.classList.remove('force-dark-mode');
          break;
      }
    }
  }
}
英文:

This is best handled by setting all your colors in your elements as CSS Custom Properties. e.g.

class MyCustomCard extends LitElement {
  static styles = css`
    .card {
      /* Set custom property and default value */
      background-color: var(--sys-color-surface, #FFF);
      color: var(--sys-color-on-surface, #000);
      ...
    }
  `;
  ...
}

Then you can have a theming.css file at the root of your document. e.g.

&lt;!-- index.html --&gt;
&lt;head&gt;
  &lt;link rel=&quot;stylesheet&quot; href=&quot;theme.css&quot;&gt;
&lt;/head&gt;
/* theme.css */
/* light theme */
:root, body.force-light-mode {
  --sys-color-surface: #FFF;
  --sys-color-on-surface: #000;
  ...
}
/* auto dark theme */
@media (prefers-color-scheme: dark) {
  :root {
    --sys-color-surface: #000;
    --sys-color-on-surface: #FFF;
    ...
  }
}

/* user preference dark mode */
body.force-dark-mode {
  /* This can be deduplicated with an @import https://developer.mozilla.org/en-US/docs/Web/CSS/@import */
  --sys-color-surface: #000;
  --sys-color-on-surface: #FFF;
  ...
}

Then you can have a dark theme toggle that toggles the force-*-mode class on body:

class ThemeToggle extends LitElement {
  render() {
    return html`
      &lt;div&gt;Select Theme&lt;/div&gt;
      &lt;label&gt;
        Light Mode
        &lt;input
            type=&quot;radio&quot;
            @change=${this.onChange(&#39;light&#39;)}
            name=&quot;theme&quot;&gt;
       &lt;/label&gt;
      &lt;label&gt;
        Follow System
        &lt;input
            type=&quot;radio&quot;
            @change=${this.onChange(&#39;system&#39;)}
            name=&quot;theme&quot;
            checked&gt;
       &lt;/label&gt;
      &lt;label&gt;
        Dark Mode
        &lt;input
            type=&quot;radio&quot;
            @change=${this.onChange(&#39;dark&#39;)}
            name=&quot;theme&quot;&gt;
       &lt;/label&gt;`
  }

  onChange = (mode) =&gt; (e) =&gt; {
    if (e.target.checked) {
      switch(mode) {
        case &#39;light&#39;:
          document.body.classList.add(&#39;force-light-mode&#39;);
          break;
        case &#39;dark&#39;:
          document.body.classList.add(&#39;force-dark-mode&#39;);
          break;
      }
    } else {
      switch(mode) {
        case &#39;light&#39;:
          document.body.classList.remove(&#39;force-light-mode&#39;);
          break;
        case &#39;dark&#39;:
          document.body.classList.remove(&#39;force-dark-mode&#39;);
          break;
      }
    }
  }
}

huangapple
  • 本文由 发表于 2023年7月13日 13:19:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76676150.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定