多主题

Lynx 支持了较丰富的 CSS 属性,配合 CSS 选择器CSS 变量以及 CSS 继承能力,可轻松实现多样化的主题样式,为用户界面提供一致且优雅的外观和风格。通过定义和管理不同的主题变量,开发者可以方便地切换不同的配色方案、字体风格以及其他视觉元件,确保用户获得最佳的视觉体验和互动感受。

使用 CSS 后代选择器切换主题

与 Web 开发类似,利用后代选择器可以通过切换父级元件的 class,来影响其所有后代节点的样式,从而实现多种主题样式的切换。

定义 CSS 主题

首先需要定义多个主题的 CSS 样式,不同主题会有不同的颜色、背景等属性。 比如我们可以定义浅色和深色两种主题样式,浅色模式通过 .theme-light .content 定义样式,深色模式通过 .theme-dark .content 定义样式。

/* 浅色主题 */
.theme-light .content {
  color: black;
  background-color: white;
}

/* 深色主题 */
.theme-dark .content {
  color: white;
  background-color: black;
}

应用 CSS 样式

在页面中,对父节点(可以定义在根节点)class 为 theme-darktheme-light,对后代节点设置 class 为 content,这样后代节点 就能被应用到 .theme-light .content 或者 .theme-dark .content 的样式。

function App() {
  return (
    <view className="theme-dark">
      <view>
        <text className="content">text</text>
      </view>
    </view>
  );
}

切换主题样式

当主题发生变化时,切换顶层的节点的 class 为 theme-darktheme-light,即可让后代节点的样式发生更新。在 Lynx 开发场景中,前端多主题的值可以由客户端通知前端,比如客户端可以通过更新 globalProps 来通知前端主题变化。

前端对应写法:

import { useMemo } from '@lynx-js/react';
import './App.css';

export function App() {
  const themeClass = useMemo(
    () => `theme-${lynx.__globalProps.appTheme}`,
    [lynx.__globalProps.appTheme],
  );

  return (
    //themeClass 的值为theme-dark或theme-light
    <view className={themeClass}>
      <view>
        ...
        <text className="content">Hello Theme</text>
        ...
      </view>
    </view>
  );
}

例子

使用 CSS 变量切换主题

使用后代选择器切换多主题时,我们需要预先定义不同主题样式的选择器,在主题种类较多的场景下不够灵活。

可以使用 CSS Variable 来定义主题样式,直接修改变量的值来实现主题切换。

定义 CSS 主题

同样我们定义需要变化的主题样式变量,对相同的变量定义不同的值。 比如不同的主题下,colorbackground-color 需要能跟随主题变化,那么需要定义两个 CSS 变量 --color--bg,后代节点可以在样式表中通过 var(--color)var(--bg) 来获取这些变量的值。

.theme-light {
  --color: black;
  --bg: white;
}

.content {
  color: var(--color);
  background-color: var(--bg);
}

应用 CSS 样式

注意 CSS 变量需要被挂载到顶层节点 (可以定义在根节点),这样其子孙节点可以在对应的样式表里使用到该变量。

其后代节点在 .content 中通过 var(--*) 的方式应用变量的值。

function App() {
  return (
    <view id="root" className="theme-light">
      <view>
        <text className="content">text</text>
      </view>
    </view>
  );
}

切换主题样式

JS 直接修改 CSS 变量的值

通过 JS API (setProperty) 来直接修改 CSS 变量值,这样可以灵活的批量更新 CSS 变量。

import './App.css';

export function App() {
  const handleClick = () => {
    lynx.getElementById('root').setProperty({
      '--color': 'white',
      '--bg': 'black',
    });
  };

  return (
    <view id="root" className="theme-light" bindtap={handleClick}>
      <text className="content">Hello Variable</text>
    </view>
  );
}

切换 class 间接修改变量的值

当然也可以在需要切换主题时,通过切换顶层节点上定义了不同的 CSS 变量的 class,间接修改变量的值,从而触发所有应用到该变量的子节点的样式更新。

比如用 .theme-light.theme-dark 来定义不同主题需要的 CSS 变量的值:

.theme-light {
  --color: black;
  --bg: white;
}

.theme-dark {
  --color: white;
  --bg: black;
}

.content {
  color: var(--color);
  background-color: var(--bg);
}

切换顶层节点 .theme-light 或者 .theme-dark,就是切换了 --color--bg 的值,从而让对应 .content 的样式表的属性值更新。

import { useMemo } from '@lynx-js/react';

import './App.css';

export function App() {
  const themeClass = useMemo(
    () => `theme-${lynx.__globalProps.appTheme}`,
    [lynx.__globalProps.appTheme],
  );

  return (
    //themeClass 的值为theme-dark或theme-light
    <view className={themeClass}>
      <text id="test" className="content">
        Hello Variable
      </text>
    </view>
  );
}

例子

按需使用 CSS 继承

在一些具有复杂样式的页面中,使用 CSS 继承会有助于简化开发,但实现属性继承逻辑,一定程度上增加了样式处理流程的复杂度,从而会带来一定的性能开销。 鉴于性能考虑,Lynx 没有默认开启 CSS 继承能力,需要开发者按需启用。

如何开启 CSS 继承

需要配置 enableCSSInheritance 来启用继承能力。

默认继承的属性

开启 enableCSSInheritance 后,默认情况下只有这些属性可以被继承:

direction,color,font-family,font-size,font-style,font-weight,letter-spacing,line-height,text-align,text-decoration,text-shadow

CSS 继承规则

默认继承属性的继承行为对齐 🌐W3C 继承行为

自定义可继承的属性

除了默认可继承属性之外,可以在页面配置 customCSSInheritanceList 自定义可继承的 CSS 属性。 当有自定义继承的声明时,仅有在自定义继承列表里面的 CSS 属性才可以继承。

范例:

"customCSSInheritanceList":["font-size","flex-direction"]

CSS 继承的功能局限

  1. position:fixed 的元件永远只继承 page 的属性。
  2. 不支持关键字 "inherit"
  3. 除了默认可继承属性外,只有类型为枚举或者布尔值的 CSS 属性支持自定义继承。
除非另有说明,本项目采用知识共享署名 4.0 国际许可协议进行许可,代码示例采用 Apache License 2.0 许可协议进行许可。