关于css:使用CSS-Variable来实现可配置的微前端应用样式

8次阅读

共计 3080 个字符,预计需要花费 8 分钟才能阅读完成。

背景

目前,社区比拟关注微前端利用款式的”封装性“,网上曾经有诸多文章介绍了微前端的款式隔离计划。然而,如果微利用只有“封装性”而没有“灵活性”,那么利用场景就会大打折扣:就如同一个不承受内部参数的函数,永远只做本人的事件,不承受调用者的管控和配置。

在这种不足灵活性的微利用架构下,宿主利用很难管控整个利用的款式主题。比方以下需要很难实现:

  • 主题色从橙色升级成浅蓝色
  • 甲方要求可能在线切换主题色
  • 微利用在多个宿主中被应用。在某些宿主中,体现为橙色;在另一些宿主中,则体现为蓝色。

根本原因在于,其中的微利用曾经将款式硬编码(并且实现了款式隔离),而无奈通过宿主的配置来扭转,不足信息传递与共享的渠道。

过来的实现形式须要消耗极大的老本:比方,对于每个微利用,为每种主题构建出一份 css,而后依据宿主以后的主题状态,用 js 来切换每个微利用的 css。并且,任何一个波及到主题的批改,都要求你批改、从新构建、公布所有微利用,极其繁琐。

计划简介

本文分享一个计划,通过 cssVar 来实现微利用的主题管控,能够做到:

  • 微利用有本人的默认主题。开箱即用,无需任何配置就能应用。
  • 宿主有掌控权。当宿主想要进行款式管控的时候,能够准确、按需地管制每个微利用的主题变量,笼罩微利用本人的默认主题,保障整个利用是和谐一致的。

在这套计划中,微利用的款式就如同一个有可选参数的函数:

function (cssVar1 = defaultVar1, cssVar2 = defaultVar2) {// render style with cssVar1, cssVar2...}

在封装了外部款式的同时,又对外提供了能够配置的 API。更灵便地满足各种场景的需要。

上面用一个简略的例子,来介绍这套计划的实现思路。

开箱即用的默认主题

这是微利用挂载的款式:

/* 微利用 css */
.widget-k7na5-root {--button-bg: orange;}
.widget-k7na5-btn {background-color: var(--button-bg);
}

其中,widget-k7na5是微利用的类名前缀,实现款式隔离。你能够用网上的各种形式来实现款式隔离(比方 css module、css-in-js),它们都能够与本计划组合应用。

它的 DOM 构造如下:

<div classname="widget-k7na5-root">
  <button classname="widget-k7na5-btn">button</button>
</div>

因而,在无外界影响的状况下,这个微利用会展现默认的橙色主题。开箱即用,无需配置。

它的关键点在于,在微利用根元素上,定义一份默认的款式变量;而后在微利用外部,援用款式变量来实现款式,而不是将具体值硬编码在款式中。

宿主能够笼罩微利用的款式变量

如果宿主想要将整个站点的主题降级为蓝色,那么微利用就不应该持续体现为橙色。因而 宿主须要有笼罩微利用默认主题的能力

如何做到呢?

首先,微利用要提供一个 API,容许宿主配置微利用根元素的类名

/* 宿主 js */
// 宿主加载微利用的时候,能够定制微利用根元素的类名
function App() {return <LoadWidget id="widget-instance-list" className="theme-blue" />}

微利用有如下 DOM 构造:

<div classname="widget-k7na5-root theme-blue">
  <button classname="widget-k7na5-btn">button</button>
</div>

微利用加载的款式与后面一样,无需扭转

/* 微利用 css */
.widget-k7na5-root {--button-bg: orange;}
.widget-k7na5-btn {background-color: var(--button-bg);
}

因而,微利用的款式始终只用筹备一份,无需用 js 来做动静切换,实现与保护都很简略。

宿主 的款式蕴含如下主题变量定义:

/* 宿主 css */
/* 选择器权重高于 widget 本人的变量定义 */
.theme-blue.theme-blue {--button-bg: blue;}

实现!当初微利用中的 button 会展现为蓝色主题!
这里的关键点在于,宿主笼罩了微利用根元素上的 cssVar 款式变量定义。

宿主只须要用这种形式,给每个微利用都加上 .theme-blue 的类名,就能够让整个站点都对立变成蓝色主题。在这个主题降级过程中,各个微利用不须要做任何改变、公布。

留神到,宿主始终没有侵入微利用外部的实现,维持了微利用的封装性。宿主应用的仅仅是以下 API:

  • 定制根元素类名的 API。
  • 微利用在根元素上定义的 cssVar 变量名。它们就如同函数的具名参数,也是一种 API。

只有保障这两个 API 可能维持稳固,宿主与微利用就能各自独立迭代。封装性与灵活性兼得。

高级例子:准确控制能力

这种计划简略灵便,宿主甚至能够准确地管制每一个微利用要展示哪种主题。

宿主 js 如下,给每个微利用别离传入主题类名:

/* 宿主 js */
// 宿主加载微利用的时候,能够定制微利用根元素的类名
function App() {
  return (
    <>
      <LoadWidget id="widget-instance-list" className="theme-blue" />
      <LoadWidget id="widget-instance-list" className="theme-green" />
    </>
  );
}

宿主 的款式蕴含每个主题类名的变量定义:

/* 宿主 css */
/* 选择器权重高于 widget 本人的变量定义 */
.theme-blue.theme-blue {--button-bg: blue;}
.theme-green.theme-green {--button-bg: green;}

这样的话,前者会展现为蓝色主题,而后者会展现为绿色主题。两者互相不烦扰,并且齐全受宿主管制。

微利用默认继承宿主的款式变量

在下面的计划中,微利用默认展现本人的主题。宿主如果要笼罩微利用的主题,须要给每个微利用传入类名。即默认隔离 的计划。

cssVar 也能够实现 默认继承 的计划:微利用主动继承宿主的款式变量,宿主无需给微利用传入额定配置。

实际上,cssVar 本来就是默认继承的。

宿主 js:

/* 宿主 js */
function App() {return <LoadWidget id="widget-instance-list" />}

留神到,宿主不再须要定制微利用根元素的类名

宿主 css:

/* 宿主 css */
html {--button-bg: blue;}

留神到,宿主间接在全局范畴定义主题变量。

微利用的 DOM 构造与之前雷同:

<div classname="widget-k7na5-root">
  <button classname="widget-k7na5-btn">button</button>
</div>

微利用挂载的款式:

/* 微利用 css */

.widget-k7na5-root {}
.widget-k7na5-btn {background-color: var(--button-bg, orange);
}

为了防止每次应用 var(–button-bg)的时候都要带上默认值,让代码变得反复、难以编写和批改,你还能够借助预处理器的变量性能(比方$button-bg: var(--button-bg, orange);)。

这样,微利用会主动从宿主环境读取到 --button-bg 的值,体现为蓝色。

正文完
 0