使用作用域 CSS 创建 SVG 组件

Posted

技术标签:

【中文标题】使用作用域 CSS 创建 SVG 组件【英文标题】:Create SVG components with scoped CSS 【发布时间】:2019-02-22 14:04:59 【问题描述】:

我正在创建将呈现各种 SVG 的 React 组件:

const Close = (
  fill, width, height, float,
) => (
  <svg width= `$widthpx`  height= `$heightpx`  viewBox="0 0 14.48 14.48" style=  float: `$float`, cursor: 'pointer'  >
    <title>x</title>
    <g id="Layer_2" data-name="Layer 2">
      <g id="Background">
        <line style=  fill: 'none', stroke: `$fill`, strokeMiterlimit: 10   x1="14.13" y1="0.35" x2="0.35" y2="14.13" />
        <line style=  fill: 'none', stroke: `$fill`, strokeMiterlimit: 10   x1="14.13" y1="14.13" x2="0.35" y2="0.35" />
      </g>
    </g>
  </svg>
);

能够提供该组件的各种属性来控制尺寸,颜色等非常方便......

然而,我没有一个好的解决方案是以 DRY 方式处理样式。请注意line 元素与style 具有相同的值。我现在将它们内联编写,因为如果我添加了一个嵌入式样式表,那么我会与我在页面上其他地方渲染的其他 SVG 发生类名冲突(我们的 SVG 软件一遍又一遍地使用相同的类)。

&lt;style scoped&gt; 已从规范中删除:https://github.com/whatwg/html/issues/552

Edge 还不支持Shadow DOM:https://caniuse.com/#feat=shadowdomv1

范围样式还有其他替代方法吗?

【问题讨论】:

嗨@Mister。你为什么不去 css-in-js。 ? @MisterEpic 我对你在找什么有点困惑。每个 SVG 都非常独特,那么为什么要在它们之间共享样式呢? css-modules (github.com/css-modules/css-modules) 怎么样?它符合您的要求吗? 对于范围样式,请考虑使用 shadow DOM。对于边缘,使用 polyfills @MisterEpic OP 去哪儿了? 【参考方案1】:

实际上,如果我在你的位置,我当然会使用字体而不是 SVG,但是对于你的确切问题,我更喜欢在箭头函数中使用常量变量,如下所示:

import React from 'react';

const Close = ( fill, width, height, float ) => 
  const constStyle =  fill: 'none', stroke: `$fill`, strokeMiterlimit: 10 ;

  return (
    <svg
      width=`$widthpx`
      height=`$heightpx`
      viewBox="0 0 14.48 14.48"
      style= float: `$float`, cursor: 'pointer' 
    >
      <title>x</title>
      <g id="Layer_2" data-name="Layer 2">
        <g id="Background">
          <line style=constStyle x1="14.13" y1="0.35" x2="0.35" y2="14.13" />
          <line style=constStyle x1="14.13" y1="14.13" x2="0.35" y2="0.35" />
        </g>
      </g>
    </svg>
  );
;

export default Close;

即使,我将线尺寸变量设为props,但我不知道你的具体情况。

希望这个答案对你有所帮助。

【讨论】:

【参考方案2】:

要结合两全其美,您可以创建一个外部样式文件,就像创建 CSS 一样,但要使用导出的样式对象。然后,您可以将其导入到任何需要它的文件中。

例如,主文件:

import React,  Component  from 'react';
import  render  from 'react-dom';
import * as Styles from './svgstyles';

class App extends Component 
  render() 
    return (
      <div>
        <svg   viewBox="0 0 100 200">  
          <rect x="0" y="0"   style=Styles.style1 />
          <rect x="15" y="0"   style=Styles.style2 />
          <rect x="30" y="0"   style=Styles.style3 />
          <rect x="45" y="0"   style=Styles.style4 />
          <rect x="0" y="15"   style=Styles.style4 />
          <rect x="15" y="15"   style=Styles.style3 />
          <rect x="30" y="15"   style=Styles.style2 />
          <rect x="45" y="15"   style=Styles.style1 />
        </svg>
      </div>
    );
  


render(<App />, document.getElementById('root'));

还有一个外部样式文件:

export const style1 = 
  stroke: 'red',
  strokeWidth: "1",
  fill: "blue",


export const style2 = 
  stroke: 'red',
  strokeWidth: "1",
  fill: "green",


export const style3 = 
  stroke: 'red',
  strokeWidth: "1",
  fill: "yellow",


export const style4 = 
  ...style3,
  fill: "pink",

Live example here

【讨论】:

【参考方案3】:

如果你只是想干掉代码,你可以创建一个样式对象并重用它:

const Close = (
                 fill, width, height, float,
               ) => 
  const style =  fill: 'none', stroke: `$fill`, strokeMiterlimit: 10 
  return (
    <svg width= `$widthpx`  height= `$heightpx`  viewBox="0 0 14.48 14.48" style=  float: `$float`, cursor: 'pointer'  >
      <title>x</title>
      <g id="Layer_2" data-name="Layer 2">
        <g id="Background">
          <line style= style  x1="14.13" y1="0.35" x2="0.35" y2="14.13" />
          <line style= style  x1="14.13" y1="14.13" x2="0.35" y2="0.35" />
        </g>
      </g>
    </svg>
  );

这也将导致性能小幅提升,因为在每个渲染周期中创建的对象更少。

【讨论】:

是的,这样更好,但这是一个小例子。我在现实世界中的 SVG 有多种内联样式。

以上是关于使用作用域 CSS 创建 SVG 组件的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js:如何使动态创建的 HTML 使用作用域 CSS?

Vue项目中 css样式的作用域(深度作用选择器)

679 组件的拆分和嵌套,组件的css作用域

Vue:如何更改作用域子组件的样式

具有作用域 css 的 Vue.js 样式 v-html

如何覆盖 Vue 组件中的作用域样式?