使用样式化组件更改 SVG 笔划的颜色
Using Styled Components to change the color of an SVG's stroke
我有一个 SVG 用作 <img>
标签。使用样式化组件,我试图达到在悬停时更改笔触颜色的程度。
我导入了 SVG:
import BurgerOpenSvg from '../../images/burger_open.svg';
我为它创建了样式组件:
const BurgerImageStyle = styled.img`
&:hover {
.st0 {
stroke: red;
}
}
`;
我用它:
<BurgerImageStyle alt="my-burger" src={BurgerOpenSvg}/>
结果是,我的 SVG 显示正确,但悬停时没有颜色变化。
我使用的 SVG 来源:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 38 28.4" style="enable-background:new 0 0 38 28.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#221f1f;stroke-width:2;stroke-miterlimit:10;}
</style>
<g>
<g id="XMLID_7_">
<line class="st0" x1="0" y1="1" x2="38" y2="1"/>
</g>
<g id="XMLID_6_">
<line class="st0" x1="0" y1="14.2" x2="38" y2="14.2"/>
</g>
<g id="XMLID_5_">
<line class="st0" x1="0" y1="27.4" x2="38" y2="27.4"/>
</g>
</g>
</svg>
SVG 渲染如下:
甚至可以在 <img>
标签中加载的 SVG 上更新 class 吗?还是必须是内联 <svg>
标签?
所以我调查了这个。事实证明,您不能 CSS 使用 <img>
标签为正在加载的 SVG 图像设置样式。
我所做的是这样的:
我这样内联我的 SVG:
<BurgerImageStyle x="0px" y="0px" viewBox="0 0 38 28.4">
<line x1="0" y1="1" x2="38" y2="1"/>
<line x1="0" y1="14.2" x2="38" y2="14.2"/>
<line x1="0" y1="27.4" x2="38" y2="27.4"/>
</BurgerImageStyle>
然后我使用 Styled Components 来设置样式 BurgerImageStyle
:
const BurgerImageStyle = styled.svg`
line {
stroke: black;
}
&:hover {
line {
stroke: purple;
}
}
`;
这有效。
如果您希望避免编写单独的组件或复制原始 SVG 文件,请考虑 react-inlinesvg
;
https://github.com/gilbarbara/react-inlinesvg
import React from "react";
import styled from "styled-components";
import SVG from "react-inlinesvg";
import radio from "./radio.svg";
interface SVGProps {
color: string;
}
const StyledSVG = styled(SVG)<SVGProps>`
width: 24px;
height: 24px;
& path {
fill: ${({ color }) => color};
}
`;
export default function App() {
const color = "#007bff";
return <StyledSVG color={color} src={radio} />;
}
代码沙盒:https://codesandbox.io/s/stack-56692784-styling-svgs-iz3dc?file=/src/App.tsx:0-414
如果你想在多个 SVG 之间共享一些样式并且你不想对 react-inlinesvg
有额外的依赖,你可以改用这个东西:
在 src
属性中它接受 SVG React 组件
import styled from 'styled-components';
import React, { FC, memo } from 'react';
type StyledIconProps = {
checked?: boolean;
};
const StyledIconWrapper = styled.div<StyledIconProps>`
& svg {
color: ${(p) => p.checked ? '#8761DB' : '#A1AAB9'};
transition: 0.1s color ease-out;
}
`;
export const StyledIcon = memo((props: StyledIconProps & { src: FC }) => {
const { src, ...rest } = props;
const Icon = src;
return (
<StyledIconWrapper {...rest}>
<Icon/>
</StyledIconWrapper>
);
});
然后你可以像这样使用它:
import { StyledIcon } from 'src/StyledIcon';
import { ReactComponent as Icon } from 'assets/icon.svg';
const A = () => (<StyledIcon src={Icon} checked={false} />)
我有一个 SVG 用作 <img>
标签。使用样式化组件,我试图达到在悬停时更改笔触颜色的程度。
我导入了 SVG:
import BurgerOpenSvg from '../../images/burger_open.svg';
我为它创建了样式组件:
const BurgerImageStyle = styled.img`
&:hover {
.st0 {
stroke: red;
}
}
`;
我用它:
<BurgerImageStyle alt="my-burger" src={BurgerOpenSvg}/>
结果是,我的 SVG 显示正确,但悬停时没有颜色变化。
我使用的 SVG 来源:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 38 28.4" style="enable-background:new 0 0 38 28.4;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#221f1f;stroke-width:2;stroke-miterlimit:10;}
</style>
<g>
<g id="XMLID_7_">
<line class="st0" x1="0" y1="1" x2="38" y2="1"/>
</g>
<g id="XMLID_6_">
<line class="st0" x1="0" y1="14.2" x2="38" y2="14.2"/>
</g>
<g id="XMLID_5_">
<line class="st0" x1="0" y1="27.4" x2="38" y2="27.4"/>
</g>
</g>
</svg>
SVG 渲染如下:
甚至可以在 <img>
标签中加载的 SVG 上更新 class 吗?还是必须是内联 <svg>
标签?
所以我调查了这个。事实证明,您不能 CSS 使用 <img>
标签为正在加载的 SVG 图像设置样式。
我所做的是这样的:
我这样内联我的 SVG:
<BurgerImageStyle x="0px" y="0px" viewBox="0 0 38 28.4">
<line x1="0" y1="1" x2="38" y2="1"/>
<line x1="0" y1="14.2" x2="38" y2="14.2"/>
<line x1="0" y1="27.4" x2="38" y2="27.4"/>
</BurgerImageStyle>
然后我使用 Styled Components 来设置样式 BurgerImageStyle
:
const BurgerImageStyle = styled.svg`
line {
stroke: black;
}
&:hover {
line {
stroke: purple;
}
}
`;
这有效。
如果您希望避免编写单独的组件或复制原始 SVG 文件,请考虑 react-inlinesvg
;
https://github.com/gilbarbara/react-inlinesvg
import React from "react";
import styled from "styled-components";
import SVG from "react-inlinesvg";
import radio from "./radio.svg";
interface SVGProps {
color: string;
}
const StyledSVG = styled(SVG)<SVGProps>`
width: 24px;
height: 24px;
& path {
fill: ${({ color }) => color};
}
`;
export default function App() {
const color = "#007bff";
return <StyledSVG color={color} src={radio} />;
}
代码沙盒:https://codesandbox.io/s/stack-56692784-styling-svgs-iz3dc?file=/src/App.tsx:0-414
如果你想在多个 SVG 之间共享一些样式并且你不想对 react-inlinesvg
有额外的依赖,你可以改用这个东西:
在 src
属性中它接受 SVG React 组件
import styled from 'styled-components';
import React, { FC, memo } from 'react';
type StyledIconProps = {
checked?: boolean;
};
const StyledIconWrapper = styled.div<StyledIconProps>`
& svg {
color: ${(p) => p.checked ? '#8761DB' : '#A1AAB9'};
transition: 0.1s color ease-out;
}
`;
export const StyledIcon = memo((props: StyledIconProps & { src: FC }) => {
const { src, ...rest } = props;
const Icon = src;
return (
<StyledIconWrapper {...rest}>
<Icon/>
</StyledIconWrapper>
);
});
然后你可以像这样使用它:
import { StyledIcon } from 'src/StyledIcon';
import { ReactComponent as Icon } from 'assets/icon.svg';
const A = () => (<StyledIcon src={Icon} checked={false} />)