React Styled-Components 基礎篇
本篇是學習 Styled-Components 時閱讀官網的一些筆記跟心得記錄
Install
$ npm install --save styled-components
若在 typescript 環境安裝需安裝相應的 types
$ npm install --save-dev @types/styled-components
Usage
Basic
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
render(
<Wrapper>
<Title>
Hello World!
</Title>
</Wrapper>
);
Props
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
Extends
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// A new component based on Button, but with some override styles
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
Change Tag
使用 as
屬性切換 html tag
const Button = styled.button`
display: inline-block;
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
display: block;
`;
render(
<div>
<Button>Normal Button</Button>
<Button as="a" href="#">Link with Button styles</Button>
</div>
);
或是使用 Custom Components
const ReversedButton = props => <Button {...props} children={props.children.split('').reverse()} />
render(
<div>
<Button>Normal Button</Button>
<Button as={ReversedButton}>Custom Button with Normal Button styles</Button>
</div>
);
Styling any component
const Link = ({ className, children }) => (
<a className={className}>
{children}
</a>
);
const StyledLink = styled(Link)`
color: palevioletred;
font-weight: bold;
`;
render(
<div>
<Link>Unstyled, boring Link</Link>
<br />
<StyledLink>Styled, exciting Link</StyledLink>
</div>
);
Define Styled Components outside of the render method
const StyledWrapper = styled.div`
/* ... */
`;
const Wrapper = ({ message }) => {
return <StyledWrapper>{message}</StyledWrapper>;
};
Nested
const Thing = styled.div.attrs((/* props */) => ({ tabIndex: 0 }))`
color: blue;
&:hover {
color: red; // <Thing> when hovered
}
& ~ & {
background: tomato; // <Thing> as a sibling of <Thing>, but maybe not directly next to it
}
& + & {
background: lime; // <Thing> next to <Thing>
}
&.something {
background: orange; // <Thing> tagged with an additional CSS class ".something"
}
.something-else & {
border: 1px solid; // <Thing> inside another element labeled ".something-else"
}
`
Attaching additional props
對組件 props 添加其他自訂 props
const Input = styled.input.attrs(props => ({
// we can define static props
type: "text",
// or we can define dynamic ones
size: props.size || "1em",
}))`
color: palevioletred;
font-size: 1em;
border: 2px solid palevioletred;
border-radius: 3px;
/* here we use the dynamically computed prop */
margin: ${props => props.size};
padding: ${props => props.size};
`;
Overriding .attrs
const Input = styled.input.attrs(props => ({
type: "text",
size: props.size || "1em",
}))`
border: 2px solid palevioletred;
margin: ${props => props.size};
padding: ${props => props.size};
`;
// Input's attrs will be applied first, and then this attrs obj
const PasswordInput = styled(Input).attrs({
type: "password",
})`
// similarly, border will override Input's border
border: 2px solid aqua;
`;
Animations
使用 keyframes
API 定義動畫
// Create the keyframes
const rotate = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
// Here we create a component that will rotate everything we pass in over two seconds
const Rotate = styled.div`
display: inline-block;
animation: ${rotate} 2s linear infinite;
padding: 2rem 1rem;
font-size: 1.2rem;
`;
render(
<Rotate>< 💅🏾 ></Rotate>
);
因為 keyframes 是 lazy-load 的,對於共用的 style fragment 記得在外層包裹 css
const rotate = keyframes``
// ❌ This will throw an error!
const styles = `
animation: ${rotate} 2s linear infinite;
`
// ✅ This will work as intended
const styles = css`
animation: ${rotate} 2s linear infinite;
`