I've never expected I should implement a Skeleton component from scratch...
Even though there's a bunch of library for it. :)
Shimmer (번쩍임)
전체 페이지 번쩍임 Shimmering at container
absolute + translate animation
styles.ts (emotion/styled)
const transXFlow = keyframes`
0% {
transform: translateX(-300%);
}
100% {
transform: translateX(300%);
}
`;
export const Shimmer = styled.div`
position: absolute;
top: 0;
left: 0;
width: 50%;
height: 100%;
background: linear-gradient(
100deg,
rgba(255, 255, 255, 0) 20%,
rgba(255, 255, 255, 0.5) 50%,
rgba(255, 255, 255, 0) 80%
);
animation: ${transXFlow} 2.2s infinite linear;
`;
번쩍임 각 컨테이너별 Shimmering on each child components
background + background-position animation
const shimmer = keyframes`
0% {
background-position: -1200px 0;
}
100% {
background-position: 1200px 0;
}
`;
export const ShimmerBG = styled.div`
animation-duration: 2.2s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-name: ${shimmer};
animation-timing-function: linear;
background: #ddd;
background: linear-gradient(45deg, #f6f6f6 8%, #f0f0f0 18%, #f6f6f6 33%);
background-size: 1200px 100%;
`;
// export const Container = styled(ShimmerBG)`
width: 100%;
height: 100%;
max-height: 300px;
position: relative;
display: flex;
`;
// export const Item = styled(ShimmerBG)`
position: relative;
box-shadow: 6px 0px 8px rgba(0, 0, 0, 0.1);
/* background-color: #fff; */
width: 100%;
background-color: #d9d9d9;
`;
Whole css
import { keyframes } from '@emotion/react';
import styled from '@emotion/styled';
import { CSSProperties } from 'react';
import { palette } from '../../styles/palette';
const shimmer = keyframes`
0% {
background-position: -1200px 0;
}
100% {
background-position: 1200px 0;
}
`;
export const ShimmerBG = styled.div`
animation-duration: 2.2s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-name: ${shimmer};
animation-timing-function: linear;
background: #ddd;
background: linear-gradient(45deg, #f6f6f6 8%, #f0f0f0 18%, #f6f6f6 33%);
background-size: 1200px 100%;
`;
// export const Container = styled(ShimmerBG)`
export const Container = styled.div`
width: 100%;
height: 100%;
max-height: 300px;
position: relative;
display: flex;
`;
// export const Item = styled(ShimmerBG)`
export const Bar = styled.div`
position: relative;
box-shadow: 6px 0px 8px rgba(0, 0, 0, 0.1);
/* background-color: #fff; */
width: 100%;
background-color: #d9d9d9;
`;
const transXFlow = keyframes`
0% {
transform: translateX(-300%);
}
100% {
transform: translateX(300%);
}
`;
export const Shimmer = styled.div`
position: absolute;
top: 0;
left: 0;
width: 50%;
height: 100%;
background: linear-gradient(
100deg,
rgba(255, 255, 255, 0) 20%,
rgba(255, 255, 255, 0.5) 50%,
rgba(255, 255, 255, 0) 80%
);
animation: ${transXFlow} 2.2s infinite linear;
`;
export const XAxis = styled.div<{ borderColor?: CSSProperties['color'] }>`
width: 100%;
height: 2px;
position: absolute;
bottom: -2px;
background: ${(props) => (props.borderColor ? props.borderColor : palette.gray400)};
`;
export const XAxisGridLine = styled.div<{ borderColor?: CSSProperties['color']; top?: CSSProperties['top'] }>`
width: 100%;
height: 2px;
position: absolute;
top: ${(props) => (props.top ? props.top : '50%')};
background: ${(props) => (props.borderColor ? props.borderColor : palette.chartGridLine)};
`;
export const YAxis = styled.div<{ borderColor?: CSSProperties['color'] }>`
width: 2px;
height: 100%;
position: absolute;
left: 0;
background: ${(props) => (props.borderColor ? props.borderColor : palette.gray400)};
`;
export const GradientLayer = styled.div`
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.7));
`;
whole component Code
function SkeletonDualBarChart({ showDualBar }: IProps) {
return (
<Container>
<XAxisGridLine top={'10%'} />
<XAxisGridLine top={'45%'} />
<XAxis />
<YAxis />
{[...Array(5)].map((config, idx) => {
return (
<CommColFlexContainer justifyContent="end" style={{ padding: `0 50px`, position: 'relative' }}>
<CommRowFlexContainer alignItems="end" gap={8} style={{ width: '100%', height: '100%' }}>
<Bar style={{ height: `${25 + idx * 10}%` }} />
<Bar style={{ height: `${30 + idx * 10}%` }} />
</CommRowFlexContainer>
{/* <CommText style={{ position: 'absolute', bottom: -26, left: '50%', transform: 'translate(-50% , 0)' }}>
{config.label}
</CommText> */}
</CommColFlexContainer>
);
})}
<GradientLayer />
<Shimmer />
</Container>
);
}