[React]๐Ÿ“˜ ProgressBar ๋ Œ๋”๋ง ๋ฆฌํŒฉํ„ฐ๋ง

MIloยท2025๋…„ 4์›” 10์ผ

React_๊ฐœ์„ ์„ค๊ณ„

๋ชฉ๋ก ๋ณด๊ธฐ
1/1

๋ฐฐ๊ฒฝ

โ†’ ๊ธฐ์กด์—๋Š” width๋ฅผ $prop ์œผ๋กœ ์ง์ ‘ ์กฐ์ ˆํ–ˆ์œผ๋‚˜ โ—๏ธlayout ๋ณ€ํ™” ๋ฐœ์ƒ&๋ฆฌํ”Œ๋กœ์šฐ ๋ฐœ์ƒโ—๏ธ

์ด๋ฅผ ํ•ด๊ฒฐ ํ•˜๊ณ ์ž ๋ฆฌํŒฉํ† ๋ง ์‹คํ–‰

๋“ค์–ด๊ฐ€๊ธฐ์— ์•ž์„œโ€ฆ

โœ… scaleX()๋ž€?

transform: scaleX(n)์€

์š”์†Œ์˜ ๊ฐ€๋กœ ๊ธธ์ด(width)๋ฅผ n๋ฐฐ๋กœ ํ™•๋Œ€/์ถ•์†Œ

โ€ข n = 1 โ†’ ์›๋ž˜ ํฌ๊ธฐ

โ€ข n = 0.5 โ†’ ๊ฐ€๋กœ ๊ธธ์ด๊ฐ€ ์ ˆ๋ฐ˜

โ€ข n = 2 โ†’ ๊ฐ€๋กœ ๊ธธ์ด 2๋ฐฐ

โ€ข n = 0 โ†’ ๊ฐ€๋กœ ๊ธธ์ด 0 (์•ˆ ๋ณด์ž„)


โœ… ์‹œ๊ฐ์ ์œผ๋กœ ๋ณด๋ฉด:

transform: scaleX(0.5);

์ด๊ฑด ํ•ด๋‹น ์š”์†Œ๋ฅผ ์™ผ์ชฝ ๊ธฐ์ค€์œผ๋กœ ๊ฐ€๋กœ๋งŒ 50%๋กœ ์ค„์ด๋Š” ํšจ๊ณผ.

โœ”๏ธ ์ค‘์š”ํ•œ ์ : ์‹ค์ œ width๋ฅผ ๋ฐ”๊พธ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ โ€œ๋ณด์—ฌ์ง€๋Š” ํฌ๊ธฐโ€๋งŒ ๋ฐ”๋€œ

โ†’ ๊ทธ๋ž˜์„œ GPU(๊ทธ๋ž˜ํ”ฝ ๊ฐ€์†)๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ํ›จ์”ฌ ๋ถ€๋“œ๋Ÿฝ๋‹ค.


โœ… ์™œ width๋ณด๋‹ค ์ข‹๋ƒ?

๊ธฐ์ค€widthtransform: scaleX()
๋™์ž‘layout ๋ณ€ํ™” ๋ฐœ์ƒlayout ๋ณ€ํ™” ์—†์Œ
๋ฆฌํ”Œ๋กœ์šฐ์ƒ๊น€ (๋А๋ฆผ)์—†์Œ (๋น ๋ฆ„)
์„ฑ๋ŠฅCPU ๊ธฐ๋ฐ˜GPU ๊ฐ€์†
๋ถ€๋“œ๋Ÿฌ์›€์ค‘๊ฐ„โœ… ํ›จ์”ฌ ๋ถ€๋“œ๋Ÿฌ์›€
์ถ”์ฒœ๊ฐ„๋‹จํ•  ๋• OK๊ณ ์„ฑ๋Šฅ UI์—” ๊ฐ•๋ ฅ ์ถ”์ฒœ

๐Ÿ“ฆ ๊ฒฐ๋ก 

scaleX()๋Š” ๋ˆˆ์— ๋ณด์ด๋Š”

๊ธธ์ด๋งŒ ์ถ•์†Œ/ํ™•๋Œ€

์• ๋‹ˆ๋ฉ”์ด์…˜ ์ตœ์ ํ™”ํ•  ๋•Œ ์ž์ฃผ ์“ฐ์ด๋Š” ํ•ต์‹ฌ ์†์„ฑ.


โ™ป๏ธ๋ฆฌํŒฉํ† ๋ง

ํ˜„์žฌ ์ฝ”๋“œ์—์„œ ProgressBar๋ฅผ transform: scaleX() ๊ธฐ๋ฐ˜์œผ๋กœ ๊ฐœ์„ ํ•œ ๋‚ด์šฉ๊ณผ,

๊ธฐ์กด width ๋ฐฉ์‹๊ณผ์˜ ์ฐจ์ด์ , ์žฅ๋‹จ์ , ์ตœ์ข…์ ์œผ๋กœ ์™œ ์ด๋ ‡๊ฒŒ ๋ฐ”๊ฟจ๋Š”์ง€๋ฅผ ํฌํ•จํ•œ ๋ฌธ์„œ.

โœ… ๋ชฉํ‘œ

๊ธฐ์กด width ๊ธฐ๋ฐ˜ ์ง„ํ–‰๋ฐ”์—์„œ

๋” ๋ถ€๋“œ๋Ÿฝ๊ณ  ์„ฑ๋Šฅ ์ข‹์€ transform: scaleX() ๊ธฐ๋ฐ˜ ์ง„ํ–‰๋ฐ”๋กœ ๊ฐœ์„ ํ•จ.

์ด ๋ฌธ์„œ๋Š” ํ•ด๋‹น ๋ฆฌํŒฉํ„ฐ๋ง์˜ ๋™๊ธฐ, ๊ธฐ์ˆ  ๊ฐœ๋…, ์ฐจ์ด์ , ์žฅ์ , ์ฃผ์˜์‚ฌํ•ญ์„ ๋ชจ๋‘ ๋ฌธ์„œํ™”ํ•œ ์ž๋ฃŒ๋‹ค.


๐ŸŽฏ ๊ฐœ์„  ๋ชฉ์ 

๊ธฐ์กด ๋ฐฉ์‹ (width)๋ฌธ์ œ์ 
width: ${progress}%๋ธŒ๋ผ์šฐ์ € ๋ ˆ์ด์•„์›ƒ(Layout Reflow) ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ
transition ์ ์šฉ ์‹œ ์‚ด์ง ๋Š๊น€๋ถ€๋“œ๋Ÿฝ์ง€ ์•Š์Œ, ์• ๋‹ˆ๋ฉ”์ด์…˜ ์„ฑ๋Šฅ ๋–จ์–ด์ง
DOM ์‚ฌ์ด์ฆˆ ์ง์ ‘ ์กฐ์ ˆ๋ธŒ๋ผ์šฐ์ € ์—ฐ์‚ฐ ๋น„์šฉ ํผ (CPU)

โœ… ๊ฐœ์„ ๋œ ๋ฐฉ์‹: transform: scaleX()

โœ… ๊ฐœ๋… ์š”์•ฝ

transform: scaleX(n);

โ€ข ์š”์†Œ์˜ ๊ฐ€๋กœ ๋ฐฉํ–ฅ ์Šค์ผ€์ผ์„ ์กฐ์ ˆ

โ€ข n = 0 โ†’ ๊ฐ€๋กœ ๊ธธ์ด 0%

โ€ข n = 1 โ†’ ๊ฐ€๋กœ ๊ธธ์ด 100%

โ€ข n = 0.5 โ†’ ๊ฐ€๋กœ ๊ธธ์ด 50%


โœ… ์ถ”๊ฐ€ ์†์„ฑ

transform-origin: left;

โ€ข ์™ผ์ชฝ์„ ๊ธฐ์ค€์œผ๋กœ ์ปค์ง€๊ฑฐ๋‚˜ ์ค„์–ด๋“ฆ

โ€ข ์ง„ํ–‰ ๋ฐ”์ฒ˜๋Ÿผ ์™ผ์ชฝ โ†’ ์˜ค๋ฅธ์ชฝ ์ž์—ฐ์Šค๋Ÿฌ์šด ํ™•์žฅ ๊ฐ€๋Šฅ


๐Ÿ” ์ „์ฒด ๋ฆฌํŒฉํ„ฐ๋ง ์ฝ”๋“œ

const ProgressBarWrapper = styled.div`
  position: absolute;
  bottom: 0;
  left: 0;
  height: 100%;
  width: 100%;
  z-index: 1;
`;

const ProgressFill = styled.div`
  height: 100%;
  width: 100%;
  background-color: ${({ theme }) => theme.surface.brandDefault};
  transform-origin: left;
  transform: scaleX(${({ $progress }) => $progress / 100});
  transition: transform 0.5s linear;
  will-change: transform;
  opacity: 0.8;
`;
return (
  <ProgressBarWrapper>
    <ProgressFill $progress={progress} />
  </ProgressBarWrapper>
);

๐Ÿ†š ๊ธฐ์กด ๋ฐฉ์‹๊ณผ ๊ฐœ์„  ํฌ์ธํŠธ ๋น„๊ต

ํ•ญ๋ชฉ๊ธฐ์กด ๋ฐฉ์‹ (width)๊ฐœ์„  ๋ฐฉ์‹ (scaleX)
๋ Œ๋”๋ง ์„ฑ๋ŠฅCPU ์ค‘์‹ฌโœ… GPU ์ค‘์‹ฌ (transform)
์• ๋‹ˆ๋ฉ”์ด์…˜๋Š๊น€ ์žˆ์Œโœ… ๋งค์šฐ ๋ถ€๋“œ๋Ÿฌ์›€
DOM layout ์˜ํ–ฅlayout ์žฌ๊ณ„์‚ฐ ๋ฐœ์ƒโœ… layout ์˜ํ–ฅ ์—†์Œ
๋ฆฌ์†Œ์Šค ๋น„์šฉ๋†’์Œโœ… ๋‚ฎ์Œ
CSS transitionwidth transitiontransform transition (๋” ๋ถ€๋“œ๋Ÿฌ์›€)
์‹œ๊ฐ์  ์ œ์–ด๋น„๊ต์  ์ง๊ด€์ ์ดˆ๊ธฐ ํ•™์Šต ํ•„์š”ํ•˜์ง€๋งŒ ํšจ๊ณผ ์šฐ์ˆ˜

๐Ÿ“Œ ์‹ค์ „์—์„œ ์ฃผ์˜ํ•  ์ 

ํ•ญ๋ชฉ์„ค๋ช…
transform-origin๋ฐ˜๋“œ์‹œ left๋กœ ์„ค์ •ํ•ด์•ผ ์ง„ํ–‰๋ฐ”์ฒ˜๋Ÿผ ๋™์ž‘
transitiontransform์—๋งŒ ์ ์šฉํ•ด์•ผ ์ž์—ฐ์Šค๋Ÿฌ์›€
width: 100% ์œ ์ง€์Šค์ผ€์ผ ์กฐ์ •์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ๋ฐ•์Šค๋Š” ํ•ญ์ƒ 100%์—ฌ์•ผ ํ•จ
will-change: transform๋ธŒ๋ผ์šฐ์ €์— ์‚ฌ์ „ ํžŒํŠธ ์ค˜์„œ ์„ฑ๋Šฅ ํ–ฅ์ƒ

๐Ÿง  ์™œ ์ด๋ ‡๊ฒŒ ๋ฐ”๊ฟจ๋Š”๊ฐ€?

โ€ข width ๊ธฐ๋ฐ˜์€ ๊ฐ„๋‹จํ•˜์ง€๋งŒ, ๋ถ€๋“œ๋Ÿฝ์ง€ ์•Š๊ณ  ์„ฑ๋Šฅ ์ตœ์ ํ™” ์–ด๋ ค์›€

โ€ข transform ๊ธฐ๋ฐ˜์€ GPU ๊ฐ€์† โ†’ ํ”„๋ ˆ์ž„ ๋“œ๋ž ์—†์ด ๋ถ€๋“œ๋Ÿฌ์›€

โ€ข ํŠนํžˆ ์ €์‚ฌ์–‘ ๋””๋ฐ”์ด์Šค, ๋ชจ๋ฐ”์ผ์—์„œ ์ฒด๊ฐ ์ฐจ์ด ํผ

โ€ข ์‹œ๊ฐ์ ์œผ๋กœ๋„ ํ›จ์”ฌ ๋งค๋„๋Ÿฌ์šด UX ์ œ๊ณต ๊ฐ€๋Šฅ


โœ… ์ตœ์ข… ์š”์•ฝ

๋‚ด์šฉ์„ค๋ช…
์‚ฌ์šฉ ์†์„ฑtransform: scaleX(), transform-origin: left
์„ฑ๋Šฅโœ… ๋ถ€๋“œ๋Ÿฝ๊ณ  ์ตœ์ ํ™”๋จ
์“ฐ์ž„์ง„ํ–‰๋ฐ”, ๋กœ๋”ฉ๋ฐ”, ๊ทธ๋ž˜ํ”ฝ ์‹œ๊ฐํ™”
๋ฆฌ์•กํŠธ ์—ฐ๋™ ๋ฐฉ์‹์ƒํƒœ๊ฐ’ โ†’ ์Šค์ผ€์ผ ๋น„์œจ๋กœ ๋ฐ˜์˜
profile
์•ต๋งน!

0๊ฐœ์˜ ๋Œ“๊ธ€