我们如何使用UI Kit主题通过CSS变量与SCSS成为朋友


大家好,我叫Vitalik,我是Skyeng的高级前端开发人员。 我们的团队正在建立一个在线Vimbox平台来学习英语。 大约一年前,设计师和我完成了一个小型UI工具包,该工具包消除了界面和代码库中的混乱情况。


原来,我们并不是公司中唯一想要UI套件的人,其他团队也开始向我们寻求“如何编写自己的工具”的建议。 我们设法劝阻他们退出这项事业,并承诺要改善我们自己的事业-这为公司节省了数百小时的开发时间。 选择解决方案后,我们检查了Angular Material,自定义程序集和CSS变量,并最终选择了后者,尽管它们与现有UI工具包的基础SCSS的兼容性较弱。 在削减-我们所做的细节。



问题


第一个UI工具包包括字体,调色板,用于创建表单(输入,按钮等)的一组元素,用于管理svg图标的系统。 还实现了基于Angular材质的弹出窗口和工具提示。 它仅因与“经典” Vimbox一起使用而被监禁:故意将许多东西缝紧,并且不允许外部进行更改。 Skyeng开始在同一平台上推出新产品,例如,儿童产品。


知道我们有一些新方向的开发人员来寻求建议。 而且,令我们惊讶的是,他们已经有了UI工具包的布局:他们将从头开始开发解决方案,因为 他们需要对组件的外观有所不同。 很明显,出了点问题,我们建议完善我们的库,增加其主题化的可能性。


论点很简单:设计我们的UI套件需要200个小时的UX设计和超过500个小时的开发。 这是创建字体,颜色和大约10个基本组件的系统所需的时间。 因此,如果您为每种产品编写一个单独的库,则该公司将花费N * 500个小时的开发时间。 我们认为改进我们的UI工具包会更便宜,而且不必为每个产品重复执行此步骤。


我们的论点被接受,相关领域的同意等待,我们开始寻求技术解决方案。


源数据


我们的工具:Angular,SCSS。


我们仅支持现代浏览器,并在某些限制下支持IE11。 这使生活更轻松。


我们所有的UI工具包组件都充满了常见的样式,这些样式作为SCSS常量存储在UI kit.var.scss中:


 @mixin fontSizeXl { @include fontSize(18px, 26px); } $colorSkillListening: #9679e0; $colorSkillListeningText: #7754d1; $colorSkillListeningBackground: mix($colorSkillListening, #ffffff, 16%); $colorSkillListeningBackgroundHover: mix($colorSkillListening, #ffffff, 8%); 

挑战赛


  • 所有新产品都是从“成人” Vimbox中的现有元素(教室,个人帐户等)组装而成的。
  • 设计师应该有很大的自由来实施创意,新功能和新产品的特定要求。
  • 同时,保持连续性,即 无论设计师发明了多么酸性的颜色和疯狂的字体,他的工作成果对Skyeng生态系统的归属仍然显而易见。
  • 所有这些都添加到了现有的UI套件中,同时保留了其所有优点。

走吧


因此,昨天我们期望得到结果,我们必须迅速进行技术审查并讨论选择方案。 在第一次会议上,我们确定了一系列可能的解决方案:


角材料


我们不喜欢写自行车,所以我们首先转向Angular Material。 在组件中,动态样式将移动到单独的{component}-theme.scss文件中。 这些样式绑定到组件的全局选择器。


加号缺点
无需向项目添加新技术需要对每个组件进行更改
工作量最大
必须牺牲样式封装

CSS变量


我们有很大的理由尝试使用时尚的CSS变量。 计划是将UI套件的自定义部分移植到CSS变量中。 这些组件使用相同的SCSS常量,但没有在其中写入CSS变量,而没有使用特定的值。


加号缺点
拥有范围必须为IE添加polyfill
本机浏览器技术(IE除外)我们将无法使用SCSS功能
开启了在其他任务中使用CSS变量的可能性

定制版本


我们喜欢简单的解决方案,为什么不尝试更改装配呢? 每个团队都使用主题设置创建自己的文件。 组装所有自定义主题时,将创建具有各自主题的单独捆绑包。


加号缺点
无需更改库代码更复杂的库程序集配置
库部署复杂
进行更改,您需要为所有项目重新组装工件
没有“动态”切换主题的可能性。 很难添加夜间模式

解决方案


在一周的时间里,我们研究了每种选择,进行了讨论,推迟了决定,然后再次进行了研究。


我们喜欢新技术并对其进行监控,但只有在它们给我们带来真正好处的情况下,才予以实施。 我们了解CSS变量,我们想尝试一下,但是缺少SCSS函数会引起很多麻烦。 但是,此选项的优点显而易见,我们决定弄清楚我们如何使用SCSS函数以及使用什么SCSS函数,以及是否有可能通过CSS var结识朋友。


了解CSS与SCSS


经过试验,我们意识到主要问题是CSS中缺少对#hex的支持:在SCSS中,我们编写了rgba(#ffffff, 0.4) ,而在CSS中,同一件事需要一组不同的参数rgba(255, 255, 255, 0.4) 。 一切都可以通过#hex为我们工作,而我们确实真的不想改变这一点。 我们找到了解决方案,我将按入学顺序告诉您。


变亮变暗


我们的设计师提出了一个由少量基本颜色组成的调色板,该调色板由于SCSS功能的lightendarken而扩展:


 // $color –   base: $color, background: mix($color, #ffffff, 16%), backgroundHover: mix($color, #ffffff, 8%), hover: lighten($color, 5), focused: darken($color, 5), ...more transformations... 

我们试图在CSS中找到lightendarken的类似物,但一无所获。 我们考虑了好几天,直到意识到要进行定制,我们需要摆脱库中的这些功能,将其取出。 毕竟,每个团队可能都想提出自己的改变焦点时改变颜色的公式-例如,来自Kids的同事需要更多的对比度。


一个简单的解决方案是将我们的转换转移到将初始化该主题的平台那一边。 对于平台,我们正在编写一个自动创建必要值的函数:


 @function getMainColors($color, $colorText) { $colors: ( text: $colorText, base: $color, background: mix($color, #ffffff, 16%), backgroundHover: mix($color, #ffffff, 8%), lightenLess: lighten($color, 5), darkenLess: darken($color, 5), lightenMore: lighten($color, 20), ); @return $colors; } 

平台在初始化颜色时使用它:


 //platform $colorValues: ( brand: getMainColors(#5d9cec, #4287df), positive: getMainColors(#8cc152, #55a900), accent: getMainColors(#ff3d6f, #ff255d), wrong: getMainColors(#ff6666, #fe4f44), ) 

RGBA


在我们的UI工具包中,我们使用rgba函数。 使用它,我们可以调整基色的透明度。 但是,如果rgba在SCSS中与#hex配合使用,则CSS不能。 我必须编写一个将#hex值分解为r / g / b的函数:


 // returns `r, g, b` from `#hex` for `rgba(var(--smth))` usage @function rgbValuesFromHex($hex) { @return red($hex), green($hex), blue($hex); } 

好吧,由于我们不想使用整个调色板的句柄生成RGB值,因此我们创建了一个单独的函数,该函数针对集合中的每种颜色递归执行此操作:


 // adds `fieldRgb: r, g, b` fields to map for each `field: #hex` for `rgba(var(--smth-rgb))` usage @function withRgbValues($map) { $rgbValues: (); @each $name, $value in $map { $formattedValue: (); @if type-of($value) == 'map' { $rgbValues: map-merge($rgbValues, (#{$name}: withRgbValues($value))); } @else { //   , rgb    Rgb   $rgbValues: map-merge($rgbValues, (#{$name}Rgb: rgbValuesFromHex($value))); } } @return map-merge($map, $rgbValues); } 

结果,使用生成的RGB值对调色板进行初始化如下所示:


 $colorValues: withRgbValues( ( text: ( base: #242d34, secondary: #50575c, label: #73797d, placeholder: #969b9e, inversed: #ffffff, inversedSecondary: #dadada, ), brand: getMainColors(#5d9cec, #4287df), positive: getMainColors(#8cc152, #55a900), accent: getMainColors(#ff3d6f, #ff255d), wrong: getMainColors(#ff6666, #fe4f44), //...etc 

输出为SCSS颜色图,然后可以将其转换为将其转换为CSS变量的方法。 为了从RGB主题获取值,我们编写了一个函数:


 @function getUiKitRgbVar($path...) { $path: set-nth($path, -1, #{nth($path, -1)}Rgb); //       @return getFromMap($uiKitBaseVars, $path...); } //  border-color: rgba(getUiKitRgbVar(color, brand, base), $opacity64); 

将SCSS const转换为CSS var


第一步是创建一个存储CSS变量名称的镜像结构(类似于SCSS):


 $colorCssVars: withRgbCssVars( ( text: ( base: getColorCssVar(text, base), secondary: getColorCssVar(text, secondary), label: getColorCssVar(text, label), placeholder: getColorCssVar(text, placeholder), inversed: getColorCssVar(text, inversed), //   

getColorCssVar将前缀添加到变量名称的方法。 添加--sky前缀,以避免与外部库冲突。 并将--sky - UI kit库前缀添加到--sky以避免与内部库冲突。 原来--sky- UI kit


 @function getColorCssVar($parts...) { @return getUiKitCssVar(color, $parts...); } @function getUiKitCssVar($parts...) { $uiKitCssVarPrefix: '--sky- UI kit'; $cssVar: $uiKitCssVarPrefix; @each $part in $parts { $cssVar: $cssVar + '-' + $part; } @return $cssVar; } 

例如,对于getColorCssVar(text, base)我们在输出中获得--sky- UI kit-color-text-base


最后一点是递归混合,该混合将SCSS结构中的值初始化为具有CSS Var结构中名称的变量:


 //       :root { @include uiKitThemeCssVars($uiKitDefaultTheme); //uiKitDefaultTheme – SCSS       } @mixin uiKitThemeCssVars($theme) { $cssVarsList: createVarsList($theme, $uiKitBaseCssVars); //18+,    Map  List, $uiKitBaseCssVars   css  @each $cssVar, $value in $cssVarsList { #{$cssVar}: $value; } } 

在平台上使用主题的示例:


 .popup { font-family: getUiKitVar(font, family); background-color: getUiKitVar(color, background, base); ... } 

结果如何


我们能够使用CSS变量,同时保留使用SCSS函数的能力。 创建了自定义组件外观的功能。 我们编写了一些递归方法来自动扩展主题。 好,最重要的是-花了30个小时的开发时间,而不是N * 500。


赢利!

Source: https://habr.com/ru/post/zh-CN459194/


All Articles