본문 바로가기

Front-End/React

React #9 (CSS - 박스모델)

반응형

 

※ 사전 세팅

더보기

깃허브 레포로 가서 실습에 쓸 파일만 가져오기 (ch03 > ch03_2 폴더)

https://github.com/yisj777s/doit-react-webapp-typescript/tree/main

 

터미널에서 아래 코드를 쳐서 그 아래에 있는 캡처(package.json)에 들어간 패키지들 일괄 설치

npm i -D

 

템플릿 파일 살짝 수정 - src./copy/CopyMe.tsx

import { Title } from "../components";

export default function CopyMe() {
  return (
    <section className="className">
      <Title>CopyMe</Title>
      <div className="mt-4"></div>
    </section>
  )
}

 

 일단 템플릿 파일들을 전부 복사해서 pages 안에 넣어준다.

cd src
cp copy/CopyMe.tsx pages/DivTest.tsx
cp copy/CopyMe.tsx pages/ViewportTest.tsx
cp copy/CopyMe.tsx pages/HeightTest.tsx
cp copy/CopyMe.tsx pages/PaddingTest.tsx
cp copy/CopyMe.tsx pages/MarginTest.tsx
cp copy/CopyMe.tsx pages/ImageTest.tsx
cp copy/CopyMe.tsx pages/BackgroundImageTest.tsx
cp copy/CopyMe.tsx pages/DisplayTest.tsx
cp copy/CopyMe.tsx pages/AvatarTest.tsx
cp copy/CopyMe.tsx pages/PositionTest.tsx
cp copy/CopyMe.tsx pages/OverlayTest.tsx

 

App쪽에 가서도 미리 판만 깔아두기 - src/App.tsx

import DivTest from './pages/DivTest'
import ViewportTest from './pages/ViewportTest'
import HeightTest from './pages/HeightTest'
import PaddingTest from './pages/PaddingTest'
import MarginTest from './pages/MarginTest'
import ImageTest from './pages/ImageTest'
import BackgroundImageTest from './pages/BackgroundImageTest'
import DisplayTest from './pages/DisplayTest'
import DisplayNoneTest from './pages/DisplayNoneTest'
import AvatarTest from './pages/AvatarTest'
import PositionTest from './pages/PositionTest'
import OverlayTest from './pages/OverlayTest'

export default function App() {
  return (
    <main>
      <OverlayTest />
      <PositionTest />
      <DisplayNoneTest />
      <DisplayTest />
      <AvatarTest />
      <BackgroundImageTest />
      <ImageTest />
      <MarginTest />
      <PaddingTest />
      <HeightTest />
      <ViewportTest />
      <DivTest />
    </main>
  )
}

  

(※ 여기선 몇 가지만 실습하는 걸로...)

 

Div

아래 경로로 2개의 파일 생성

touch ./src/components/WidthHeight.ts
touch ./src/components/Div.tsx

 

 

Div에 쓰일 WidthHeight 타입 구현

src/components/WidthHeight.ts

export type WidthHeight = {
  width?: string
  height?: string
}

 

 

WidthHeight 타입을 적용해서 Div 컴포넌트 생성

src/components/Div.tsx

import type {FC, DetailedHTMLProps, HTMLAttributes, PropsWithChildren} from 'react'
import type {WidthHeight} from './WidthHeight'
import type {LeftRightTopBottom} from './LeftRightTopBottom'

export type ReactDivProps = DetailedHTMLProps<
  HTMLAttributes<HTMLDivElement>,
  HTMLDivElement
>
export type DivProps = ReactDivProps &
  PropsWithChildren<WidthHeight> &
  LeftRightTopBottom & {
    src?: string
  }

//prettier-ignore
export const Div: FC<DivProps> = ({
  width, height, style: _style, src, className: _className,
  left, right, top, bottom, ...props
}) => {
  const style = {
    ..._style, width, height, backgroundImage: src && `url(${src})`,
    left, right, top, bottom
  }
  const className = ['box-border', src && 'bg-gray-300', _className].join(' ')
  return <div {...props} className={className} style={style} />
}

 

 

Div 컴포넌트 반영 (컴파일에 쓰기 위해 넘겨주기)

src/components/index.ts

export * from './Icon'
export * from './Texts'
export * from './Div'

 

 

Div 컴포넌트 사용

src/pages/DivTest.tsx

import {Title, Subtitle, Div, Icon} from '../components'

export default function DivTest() {
  return (
    <section className="mt-4">
      <Title>DivTest</Title>
      {/* <Div className="text-center text-blue-100 bg-blue-600" height="6rem"> */}
      <Div className="text-center text-blue-100 bg-blue-600">
        <Icon name="home" className="text-3xl"></Icon>
        <Subtitle>Home</Subtitle>
      </Div>
    </section>
  )
}

 

 

 

Viewport 

src/pages/ViewportTest.tsx

import { Title } from "../components";

export default function ViewportTest() {
    return (
        <section className="w-screen h-screen mt-4 bg-indigo-900">
            <Title className="text-white">ViewportTest</Title>
        </section>
    )
}

 

 

 

BackgroundImage

먼저 Div 쪽에 이미지 출처를 받아오는 src 부분을 넣어줘야 한다.

src/components/Div.tsx

 

 

src/pages/BackgroundImageTest.tsx

import { Div, Title, Subtitle } from '../components'
import * as D from '../data'

const src = D.randomImage(1200, 400);
export default function BackgroundImage () {
  return (
    <section className="mt-4">
      <Title>BackgroundImageTest</Title>
      <Div className="mt-4 bg-gray-300 h-80" src={src}>
        <Subtitle className='text-gray-500'>Some Text here</Subtitle>
      </Div>
    </section>
  )
}

 

 

 

 

 

Avatar

src/components 경로에 파일 생성

touch src/components/Avatar.tsx

 

src/components/Avatar.tsx

import type { FC } from 'react';
import { Div } from './Div';
import type { DivProps } from './Div';

export type AvatarProps = DivProps & {
    size?: string;
}

export const Avatar: FC<AvatarProps> = ({
    className: _className, style, src, size, ...props
}) => {
    const w_or_h = size ?? '3rem';
    const className = ['rounded-full bg-cover bg-gray-300', _className].join(' ');
    
    return (
        <Div
            {...props}
            src={src}
            width={w_or_h}
            height={w_or_h}
            className={className}
            style={style}
        />
    )

}

 

추가

src/components/index.ts

 

기능 함수 구현

src/pages/AvatarTest.tsx

import { Div, Title, Avatar } from '../components'
import * as D from '../data'

export default function AvatarTest () {
  const avatars = D.range(0, 10).map(index => (
    <Avatar
      className="inline-block -ml-6 border-4 border-white"
      key={index}
      src={D.randomAvatar()}
    />
  ))
  return (
    <section className="mt-4">
      <Title>AvatarTest</Title>
      <Div className="px-12 py-4 m-8 bg-blue-300">{avatars}</Div>
    </section>
  )
}

Position

그 전에 상우하좌 기능 구현

src/components/LeftRightTopBottom.ts

export type LeftRightTopBottom = {
    left?: string;
    right?: string;
    top?: string;
    bottom?: string;
}

 

Div 쪽에 속성 추가

src/components/Div.tsx 

 

 

Position 사용하기

src/pages/PositionTest.tsx

import {Div, Title, Icon} from '../components'
import * as D from '../data'

const src = D.randomImage(800, 500)
//prettier-ignore
export default function PositionTest() {
  const icons = ['home', 'search', 'settings', 'favorite'].map(name => (
    <Icon key={name} name={name} className="mr-2" />
  ))
  return (
    <Div>
      <Title>PositionTest</Title>
      <Div className="relative border-2 border-gray-500"
        src={src} height="10rem">
        <Div className="absolute p-2 text-white bg-red-500"
          left="1rem" top="1rem">{icons}</Div>
        <Div className="absolute p-2 text-white bg-blue-500"
          right="1rem" top="1rem">{icons}</Div>
        <Div className="absolute p-2 text-white bg-pink-500"
          left="1rem" bottom="1rem">{icons}</Div>
        <Div className="absolute p-2 text-white bg-yellow-500"
          right="1rem" bottom="1rem">{icons}</Div>
      </Div>
    </Div>
  )
}

 

 

Overlay

Overlay 컴포넌트 파일 생성

touch src/components/Overlay.tsx

 

src/components/Overlay.tsx

import {FC} from 'react'
import {ReactDivProps} from './Div'
import {Div} from './Div'

export type OverlayProps = ReactDivProps & {
  opacityClass?: string
}

export const Overlay: FC<OverlayProps> = ({
  className: _className,
  opacityClass,
  children,
  ...props
}) => {
  const className = [
    _className,
    'absolute z-50 w-screen h-screen',
    opacityClass ?? 'bg-black/70',
    'flex items-center justify-center'
  ].join(' ')
  //prettier-ignore
  return (
    <Div {...props} className={className} top="0" left="0">{children}</Div>
  )
}

 

추가

src/components/index.ts

 

src/pages/OverlayTest.tsx

import {Title, Div, Icon, Overlay} from '../components'

export default function OverlayTest() {
  return (
    <section className="mt-4">
      <Title>OverlayTest</Title>
      <Overlay opacityClass="bg-black/70">
        <Div className="relative flex items-center justify-center p-8 bg-white h-1/2">
          <Div className="absolute" right="1rem" top="1rem">
            <Icon name="close" className="text-gray-500" />
          </Div>
          <p className="text-5xl">modal dialog box</p>
        </Div>
      </Overlay>
    </section>
  )
}

 

 

 

 

 

 

반응형

'Front-End > React' 카테고리의 다른 글

React #11 (CSS - user & card)  (0) 2025.07.14
React #10 (CSS - flexbox layout)  (0) 2025.07.14
React #8 (CSS - TailwindCSS)  (0) 2025.07.10
React #7 (CSS - 아이콘)  (2) 2025.07.09
React #6 (CSS - bootstrap)  (1) 2025.07.09