πŸ’…πŸΌ styled-components 없이 κ°œλ°œν•΄λ³΄κΈ°

YunShinΒ·2024λ…„ 3μ›” 9일
2

λ„μ „κ³Όμ œ

λͺ©λ‘ 보기
1/5
post-thumbnail

🚩 λ“€μ–΄κ°€λ©΄μ„œ..

μ €λŠ” 아직 λ§Žμ€ ν”„λ‘œμ νŠΈμ— 참여해보진 μ•Šμ•˜μ§€λ§Œ, Reactλ₯Ό ν™œμš©ν•΄ μ‹€μŠ΅&μž‘μ—…ν•  λ•Œλ©΄ λ°˜λ“œμ‹œ μ‚¬μš©ν–ˆλ˜ λΌμ΄λΈŒλŸ¬λ¦¬κ°€ λͺ‡ κ°€μ§€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. κ·Έ 쀑 ν•˜λ‚˜λŠ” λŒ€ν‘œμ μΈ cSS-in-js 라이브러리인 styled-components μ˜€μ£ ..

styled-components λ₯Ό μ‚¬μš©ν•  경우, css νŒŒμΌμ„ λ³„λ„λ‘œ λ§Œλ“€μ§€ μ•Šμ•„λ„ 되기 λ•Œλ¬Έμ— μž‘μ—…μ΄ νŽΈλ¦¬ν•΄μ§€κ³ , λ””μžμΈμ΄ μ™„μ„±λœ μ»΄ν¬λ„ŒνŠΈλ₯Ό μ—¬λŸ¬ νŒŒμΌμ—μ„œ ν˜ΈμΆœν•  수 있기 λ•Œλ¬Έμ— μž¬μƒμš©μ„±μ΄ λ†’μ•„μ§„λ‹€λŠ” μž₯점이 μžˆμŠ΅λ‹ˆλ‹€. 덕뢄에 μ§€κΈˆκΉŒμ§€ 직접 css νŒŒμΌμ„ 생성해 λ³Έ 적은 ν•œλ²ˆλ„ μ—†μ—ˆμŠ΅λ‹ˆλ‹€. πŸ˜…

ν•˜μ§€λ§Œ νŠΉμ • λΌμ΄λΈŒλŸ¬λ¦¬μ— 의쑴적인 κ°œλ°œμŠ΅κ΄€μ„ 듀이면 μ•ˆλœλ‹€κ³  μ–΄λ””μ„ κ°€ λ“€μ—ˆλ˜ κ±° κ°™μ•„μš”... 이번 개인 ν”„λ‘œμ νŠΈμ—μ„œλŠ” μŠ΅κ΄€μ μœΌλ‘œ μ‚¬μš©ν–ˆλ˜ styled-components 없이 μ§„ν–‰ν•˜λŠ” κ²ƒμœΌλ‘œ 개인 λ„μ „κ³Όμ œλ₯Ό μ„€μ •ν–ˆμŠ΅λ‹ˆλ‹€.

πŸ’‘ κΈ°λ³Έ κ°œλ…

처음 λ“€μ—ˆλ˜ μ•„μ΄λ””μ–΄λŠ” μ‹¬ν”Œν–ˆμŠ΅λ‹ˆλ‹€. jsx μ—μ„œ style 속성을 μ΄μš©ν•  경우, styled-components 와 λ§ˆμ°¬κ°€μ§€λ‘œ css νŒŒμΌμ„ λ³„λ„λ‘œ 두지 μ•Šκ³ λ„ ui μ»΄ν¬λ„ŒνŠΈ λ₯Ό μ‰½κ²Œ λ””μžμΈ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이λ₯Ό inline-styling 이라고 ν•œλ‹΅λ‹ˆλ‹€. πŸ™ƒ

// inline-styling
export const TestComponent = () => {
	return (
		<div style={{ width: "500px", height: "500px", backgroundColor: "red" }}>
			<p> ν•œλ³€μ˜ 길이가 500px 인 λΉ¨κ°„ μƒμž </p>
		</div>
	);
};

μœ„μ˜ ν˜•μ‹μ„ λ³΄μ•˜μ„ λ•Œ, style 의 κ°’μœΌλ‘œ κ°μ²΄ν˜•νƒœμ˜ css 속성이 ν•„μš”ν•œ 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

이 ν˜•νƒœλ₯Ό 예쁘게(?) λ§Œλ“€μ–΄λ³΄λ©΄ styled-components 와 λΉ„μŠ·ν•œ μ½”λ“œ ν˜•μ‹μ΄ λ‚˜μ˜¬ κ±° κ°™λ‹€κ³  μƒκ°ν–ˆμŠ΅λ‹ˆλ‹€.

#1 - styled-components μ‚¬μš©

import styled from 'styled-components'

export const UsingStyledComponents = () => {
	return (
		<RedBox>
			<p> ν•œλ³€μ˜ 길이가 500px 인 λΉ¨κ°„ μƒμž </p>
		</RedBox>
	);
};
export const RedBox = styled.div`
  height: 500px;
  weight: 500px;
  background-color: 'red';
`

#2 - style 속성 μ‚¬μš©

export const InlineStyling = () => {
	return (
		<div style={RedBox}>
			<p> ν•œλ³€μ˜ 길이가 500px 인 λΉ¨κ°„ μƒμž </p>
		</RedBox>
	);
};
const RedBox: React.CSSProperties = {
	width: "500px",
	height: "500px",
	backgroundColor: 'red'
};

μŠ₯μŠ₯(?) 봀을 λ•Œ, 얼핏 λΉ„μŠ·ν•˜κ²Œ 보이지 μ•Šλ‚˜μš”????
μ €μ˜ κ²½μš°μ—”, μœ„μ™€ μž‘μ„±μ„ ν•  경우 μ§€κΈˆκΉŒμ§€ μž‘μ„±ν•΄μ™”λ˜ μ½”λ“œλ“€κ³Ό 큰 이질감 없이 μž‘μ—…ν•  수 μžˆκ² λ‹€λŠ” 확신이 μƒκ²Όλ‹΅λ‹ˆλ‹€..

λ¬Όλ‘ , λ‹¨μˆœνžˆ μ½”λ“œλ₯Ό λΉ„μŠ·ν•˜κ²Œ μž‘μ„±ν•  수 μžˆλ‹€λŠ” μž₯점뿐만 μ•„λ‹ˆλΌ μ™ΈλΆ€ λΌμ΄λΈŒλŸ¬λ¦¬μ— λŒ€ν•œ μ˜μ‘΄μ„±μ„ ν•˜λ‚˜ 쀄일 수 μžˆλŠ” 일이기도 ν•˜μ£ . πŸ˜€

  • type-script 둜 μž‘μ„±ν•  경우, React.CSSProperties type 을 style 객체에 λΆ€μ—¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 덕뢄에 μžλ™μ™„μ„±κΈ°λŠ₯을 ν™œμš©ν•  수 μžˆκΈ°λ„ ν–ˆκ³ , 일반 κ°μ²΄μ™€μ˜ ꡬ별이 κ°€λŠ₯ν–ˆμŠ΅λ‹ˆλ‹€. πŸ‘

μ΄λ ‡κ²Œ ν•΄κ²°ν–ˆμŠ΅λ‹ˆλ‹€.! πŸ€

맨 처음 κ³ λ―Όν–ˆλ˜ 것은 μŠ€νƒ€μΌ μ»΄ν¬λ„ŒνŠΈμ— props λ₯Ό μ „λ‹¬ν•˜λŠ” 경우 μ˜€μŠ΅λ‹ˆλ‹€. styled-components λ₯Ό μ‚¬μš©ν•  경우, λ‹€μŒκ³Ό 같이 λ„ˆλΉ„μ™€ 높이λ₯Ό μœ λ™μ μœΌλ‘œ λ³€κ²½ κ°€λŠ₯ν•œ box μ»΄ν¬λ„ŒνŠΈλ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.

import styled from 'styled-components';
import { ReactNode } from 'react';

type BoxProps = {
  width?: string
  height?: string
  children: ReactNode
}
export const Box = ({ width = '100%', height = '100%', children }: BoxProps) => {
  return (
    <StyledBox width={width} height={height}>
      {children}
    </StyledBox>
  )
}

type StyledBoxProps = {
  width: string
  height: string
}
const StyledBox = styled.div<StyledBoxProps>`
  width: ${(props) => props.width};
  height: ${(props) => props.height};
  background-color: 'red';
`

ν•˜μ§€λ§Œ μœ„μ—μ„œ μž‘μ„±ν–ˆλ˜λŒ€λ‘œ style 객체λ₯Ό μ„ μ–Έν•  경우, props λ₯Ό 전달할 방법이 μ—†μŠ΅λ‹ˆλ‹€.

λͺ¨μ–‘이 쑰금 μ•ˆ μ˜ˆμ˜λ‹€κ³ (?) μƒκ°ν–ˆμ§€λ§Œ μ €λŠ” λ‹€μŒμ˜ λ°©λ²•μœΌλ‘œ 같은 결과물을 λ§Œλ“€μ–΄ λƒˆμŠ΅λ‹ˆλ‹€.!

import { ReactNode } from 'react';

type BoxProps = {
  width?: string
  height?: string
  children: ReactNode
}

export const TestBox = ({ width = '100%', height = '100%', children }: BoxProps) => {
  return <div style={{ ...StyleBox, width, height }}> {children}</div>
}

const StyleBox: CSSProperties = {
  backgroundColor: 'red',
}

λ‹€λ₯Έ κ°œλ°œμžμ— μ˜ν•΄ λ””μžμΈμ΄ μœ λ™μ μ΄μ–΄μ•Ό ν•˜λŠ” prop 의 경우, λ°”λ‘œ style μ†μ„±μœΌλ‘œ 꽂은거죠(.?)

κ·Έ μ™Έ 값듀은 (μœ„μ˜ 상황에선 배경색상) CSSProperties 객체에 κ·Έ 값을 μ§€μ •ν•˜λ˜, spread μ—°μ‚°μžλ₯Ό 톡해 style 둜 μ „λ‹¬ν–ˆμŠ΅λ‹ˆλ‹€.

자주 μ‚¬μš©ν•˜λŠ” 속성 κ°’μ˜ κ²½μš°μ—” λ³„λ„λ‘œ μž‘μ„±ν•΄λ‘μ—ˆλ‹€κ°€, ν•„μš”ν•œ κ²½μš°μ— λ‹€λ₯Έ 속성과 μ„žμ–΄ μ‚¬μš©ν•  수 κ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. πŸ˜ƒ

# 크기 κ΄€λ ¨ css 속성

# μ‚¬μš© μ˜ˆμ‹œ


돌이켜 보면 κ°€μž₯ κ³¨μΉ˜κ°€ μ•„νŒ λ˜ 건 styled-components 의GlobalStyles κΈ°λŠ₯을 μ‚΄λ¦¬λŠ” κ²ƒμ΄μ—ˆμŠ΅λ‹ˆλ‹€. GlobalStyles λ₯Ό μ‚¬μš©ν•  경우, ν•΄λ‹Ή ν”„λ‘œμ νŠΈμ—μ„œ μ‚¬μš©λ˜λŠ” 폰트 μ„€μ •μ΄λ‚˜ jsx νƒœκ·Έμ— λŒ€ν•΄ 기본적인 μŠ€νƒ€μΌμ„ μ μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

전역적인 λ””μžμΈ 섀정이 κΌ­ ν•„μš”ν–ˆλ˜ 이유 쀑 ν•˜λ‚˜λŠ” (개인적으둜..) 화면에 크기에 λ”°λ₯Έ μœ λ™μ μΈ font-size λ³€κ²½μ΄μ—ˆμŠ΅λ‹ˆλ‹€. μ΄μ „κΉŒμ§€λŠ” GlobalStyles 에 media-query 섀정을 톡해 κ΅¬ν˜„μ΄ κ°€λŠ₯ν–ˆμ—ˆμ§€μš”..


import { createGlobalStyle } from 'styled-components'
import { GIANTS_BOLD, GIANTS_REGULAR } from './css-utils'
import { BORDER_RADIUS, BREAK_POINT, COLOR, FONT_SIZE } from './reference-tokens'

const GlobalStyles = createGlobalStyle`
  html{
    background-color: ${COLOR.grayScale[300]};
    color: ${COLOR.grayScale[1500]};
     
    // ν™”λ©΄ λΉ„μœ¨μ— 따라 폰트 크기 
    font-size: 62.5%;  
    @media screen and (max-width: ${BREAK_POINT.md}) {
      font-size: 50%;
    }
    @media screen and (max-width: ${BREAK_POINT.sm}) {
      font-size: 31.25%;
    }
  }
  .
  .
  .
`

λΆ„λͺ… 방법이 μžˆμ—ˆμ„ 것 같은데,, 이에 λŒ€ν•œ λ²ˆλœ©μ΄λŠ” μ•„μ΄λ””μ–΄λŠ” μ—†μ—ˆμŠ΅λ‹ˆλ‹€..

일단 이번 ν”„λ‘œμ νŠΈμ—μ„œλŠ” css 파일 μž‘μ„±ν•˜μ—¬ μ μš©ν–ˆμŠ΅λ‹ˆλ‹€.γ… γ… γ…  μΆ”κ°€μ μœΌλ‘œ 각 νŽ˜μ΄μ§€ 에 λŒ€ν•œ λ°°κ²½ μƒ‰μƒμ΄λ‚˜, κΈ°λ³Έ 폰트 색상 등을 CSSProperties 객체둜 λ§Œλ“€μ–΄μ„œ 상속 적용이 λ˜λ„λ‘ ν–ˆμ–΄μš”.!

globalStyles.tsx

main.tsx

λ―Έν•΄κ²° 과제 🀦

hover, active, focus λ“± pseudo-selectors(가상 μ„ νƒμž) λ₯Ό μ΄μš©ν•œ 효과 λΆ€μ—¬λŠ” ν”„λ‘œμ νŠΈμ— μ μš©ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. 특히 μ €λŠ” hover 효과λ₯Ό 잘 자주 μ‚¬μš©ν•˜λŠ” 편인데, μ•„μ‰½λ”λΌκ΅¬μš” πŸ₯²

λ¬Όλ‘  μ°Ύμ•„λ³΄λ‹ˆ λΉ„μŠ·ν•œ 효과λ₯Ό μ£ΌκΈ° μœ„ν•œ 방법이 μ•„μ˜ˆ μ—†λŠ” 건 μ•„λ‹ˆμ—ˆμŠ΅λ‹ˆλ‹€.
onmouseover, onmouseleave 이벀트λ₯Ό κ°μ§€ν•˜μ—¬ ν˜Έλ²„ 효과λ₯Ό μ£ΌλŠ” 것이 κ°€λŠ₯ν•©λ‹ˆλ‹€.


const App = () => {
	const Hover: MouseEventHandler<HTMLDivElement> = (event) => {
        // λ§ˆμš°μŠ€κ°€ μ»΄ν¬λ„ŒνŠΈ μœ„μ— μžˆλ‹€λ©΄ νŒŒλž€μƒ‰
		if (event.type === 'mouseover') (event.target as HTMLDivElement).style.backgroundColor = 'blue' 
        // λ§ˆμš°μŠ€κ°€ μ»΄ν¬λ„ŒνŠΈ λ°”κΉ₯에 μžˆλ‹€λ©΄ 빨간색
		else (event.target as HTMLDivElement).style.backgroundColor = 'red' 
	}
	return (
		<CenterBox>
			<div style={RedBox} onMouseOver={Hover} onMouseLeave={Hover}></div>
		</CenterBox>
	)

const RedBox: CSSProperties = {
	width: '500px',
	height: '500px',
	backgroundColor: 'red',
	transition: 'background-color 0.5s' // trasition μ„€μ •
}

ν•˜μ§€λ§Œ μœ„μ˜ Hover()λ₯Ό 보면 μ•Œ 수 μžˆλ“―, ui λ””μžμΈκ³Ό κ΄€λ ¨λœ λ‘œμ§μ„ 일단 λ‹€λ₯Έ ν•¨μˆ˜μ™€ ν•¨κ»˜ μž‘μ„±ν•΄μ•Όν•¨μ΄ 쑰금 꺼렀쑌기 λ•Œλ¬Έμ— 이번 ν”„λ‘œμ νŠΈμ—μ„  μ‚¬μš©ν•˜μ§„ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

( 근데, 이 λ¬Έμ œλŠ” λ³„λ„μ˜ νŒŒμΌμ— 효과 λ‘œμ§μ„ 뢄리 μž‘μ„±ν›„, μΈμŠ€ν„΄μŠ€λ₯Ό κ°€μ Έμ˜€λŠ” λ°©λ²•μœΌλ‘œ ν•΄κ²°κ°€λŠ₯ ν•  것 κ°™λ„€μš”.. πŸ˜²πŸ’‘ )

무엇보닀도 styled-components λ₯Ό μ‚¬μš©ν•  경우, μ½”λ“œμž‘μ„±μ΄ 더 쉽고 μ§κ΄€μ μœΌλ‘œ μž‘μ„±μ΄ κ°€λŠ₯ν•˜λ©° μ»΄ν¬λ„ŒνŠΈμ˜ κΈ°λŠ₯ 둜직과 μ™„λ²½ν•˜κ²Œ κ΅¬λΆ„λ˜κΈ° λ•Œλ¬Έμ— ꡳ이 μ΄λ ‡κ²Œ 효과λ₯Ό λΆ€μ—¬ν•΄μ•Ό ν•˜λ‚˜ μ‹ΆμŠ΅λ‹ˆλ‹€;;

// 훨씬 직관적!!
const $RedBox = styled.div`
	width: '500px';
	height: '500px';
	background-color: 'red';
	transition: background-color 1s;

	&:hover {
		background-color: 'blue';
	}
	&:active {
		// active 효과
	}
	&:focus {
		// focus 효과
	}
`

회고

μ–΄λ €μš΄ 점이 많이 있긴 ν–ˆμ§€λ§Œ, 검색과 고민을 많이 ν•΄λ³΄λ‹ˆ styled-components 없이도 κΈ°λŠ₯ 둜직, 데이터 객체와 ꡬ뢄 κ°€λŠ₯ν•˜κ²Œ ui λ””μžμΈ μ½”λ“œλ₯Ό μž‘μ„±ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. (μ•„λŠ” 지식 μ„ μ—μ„œ,, κ·Έ ν˜•νƒœμ™€ κΈ°λŠ₯을 μ΅œλŒ€ν•œ λΉ„μŠ·ν•˜κ²Œ κ΅¬ν˜„ν•˜λ €κ³  λ…Έλ ₯을 ν–ˆλ˜ 것 κ°™μŠ΅λ‹ˆλ‹€.) κ·ΈλŸΌμ—λ„ μ‚¬λžŒλ“€μ΄ 많이 μ‚¬μš©ν•˜λŠ” λΌμ΄λΈŒλŸ¬λ¦¬λŠ” 감히 저같은 ...😎... κ°€ 흉내내기 μ–΄λ €μšΈλ§ŒνΌ ν›Œλ₯­ν•œ developer-experience 을 μ œκ³΅ν•œλ‹€λŠ” 사싀이 μ‹€κ°ν–ˆμŠ΅λ‹ˆλ‹€.πŸ˜…

그런 이유둜 ν˜‘μ—… ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•  λ•Œ, λ³„λ„μ˜ styling-library 없이 inline-styling λ°©μ‹μœΌλ‘œ μ§„ν–‰ν•˜μžκ³  μ œμ•ˆν•˜κΈ°λŠ” νž˜λ“€ 것 κ°™μŠ΅λ‹ˆλ‹€;; μ»¨λ²€μ…˜μ΄λ‚˜ μ½”λ“œνŒ¨ν„΄ 등을 ꡉμž₯히 꼼꼼히 톡일해야 라이브러리λ₯Ό μ‚¬μš©ν•˜λŠ” 것 만큼의 κ²½ν—˜μ„ ν•  수 μžˆμ„ 것 κ°™μ•„μš”,, 그런 κ³Όμ •μ—μ„œ λ°œμƒν•˜λŠ” μ‹œκ°„λΉ„μš©λ„ 클 κ±° κ°™μŠ΅λ‹ˆλ‹€.

μ°Έκ³  및 기타


profile
πŸ˜ŽπŸ‘

0개의 λŒ“κΈ€