
Styling Q&A 복습
Next.js Learn 2장을 실습하며 생긴 질문 정리.
| 일반 CSS | CSS Modules | Tailwind CSS | |
|---|---|---|---|
| 스타일 위치 | 별도 .css 파일 | 별도 .module.css 파일 | 태그의 className에 바로 |
| 이름표 | 내가 지음 (.card) | 내가 지음 → 자동 고유화 | 미리 정해진 이름 (bg-blue-500) |
| 연결 | import './App.css' | import styles from '...' → styles.shape | global.css에서 한 번 켜면 끝 |
| 적용 범위 | 전체 페이지 | 그 파일을 import한 컴포넌트만 | 붙인 요소만 |
| 이름 충돌 | 가능 | 없음 | 거의 없음 |
| 장점 | 익숙함 | 일반 CSS 문법 + 충돌 없음 | 파일 왔다 갔다 없이 빠름 |
| 단점 | 이름 겹침 | 파일이 늘어남 | className이 길어짐, 이름 외워야 함 |
비유
Q. 무엇을 했나?
// app/layout.tsx 맨 위
import '@/app/ui/global.css';
결과: 거대한 화살표 → 파란 상자, 로그인 버튼 있는 화면
Q. global.css는 내가 만든 건가?
A. 아니. --example로 받은 강의 코드에 들어 있던 파일. 연결만 함.
Q. 왜 layout.tsx에 연결하나?
A. layout = 모든 페이지를 감싸는 액자. 한 번 연결로 전체 페이지에 적용.
Q. CSS를 안 썼는데 왜 예뻐졌나?
A. global.css 맨 위 @tailwind (또는 @import "tailwindcss") = Tailwind 스위치. page.tsx에 이미 붙어 있던 Tailwind 이름표가 한꺼번에 작동.
Q. import를 함수 안에 넣으면?
A. 에러. import는 재료 가져오기라 파일 맨 위(함수 바깥)에.
Q. @/는?
A. 프로젝트 맨 위 폴더. @/app/ui/global.css = nextjs-dashboard/app/ui/global.css
Q. 같은 파란 상자를 만들면?
/* 일반 CSS */
.hero { display: flex; background-color: #3b82f6; padding: 16px; }
<div className="hero"> // 일반 CSS
<div className="flex bg-blue-500 p-4"> // Tailwind
Q. <div className="hero">는 CSS 선언문인가?
A. 아니. JSX(적용받는 쪽). CSS 용어는
.hero { /* 선택자: 누구에게 */
background-color: blue; /* 선언: 무엇을 (속성: 값) */
}
Tailwind 이름표 1개 = 선언 1개가 미리 들어 있는 것.
Q. page.tsx의 이름표들
| 이름표 | 뜻 |
|---|---|
flex / flex-col | 나란히 / 세로로 쌓기 |
p-6, px-6, py-10 | 안쪽 여백 (전체/좌우/상하) |
bg-blue-500 | 파란 배경 |
rounded-lg | 둥근 모서리 |
min-h-screen | 최소 높이 = 화면 |
md: | 중간 크기 화면 이상일 때만 |
hover: | 마우스 올렸을 때만 |
md:w-2/5 | 큰 화면에서 너비 5분의 2 |
[15px] | 정해진 값 말고 원하는 숫자 |
Q. 그 외 코드
{/* ... */} = 주석. <AcmeLogo />가 잠겨 있어서 파란 상자가 비어 있었음<Link href="/login"> = Next.js 전용 페이지 이동 링크{' '} = 줄바꿈으로 사라질 띄어쓰기 한 칸<div className="relative w-0 h-0 border-l-[15px] border-r-[15px] border-b-[26px] border-l-transparent border-r-transparent border-b-black" />
Q. relative는?
A. position: relative. 자기 자리 기준 위치. 이 삼각형에선 역할 없음 (지워도 같음).
Q. 테두리로 어떻게 삼각형이 되나?
1. 크기 0 상자(w-0 h-0)에 두꺼운 테두리 → 네 테두리가 한 점에서 만나 삼각형 4조각
2. 위 테두리 없음
3. 양옆 투명(transparent) → 아래 조각만 보임 → ▲
Q. 투명할 거면서 왜 두께 15px?
A. 양옆 두께가 아래 테두리의 밑변 폭을 정함. 밑변 = 0 + 15 + 15 = 30px. 0이면 폭 0이라 안 보임. (텐트 줄: 안 보이지만 천을 펼쳐줌)
/* app/ui/home.module.css */
.shape {
height: 0;
width: 0;
border-bottom: 30px solid black;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
}
import styles from '@/app/ui/home.module.css';
<div className={styles.shape} />
.module 필수styles.shape = 자동 생성된 고유 이름(home_shape__a1b2)을 꺼내옴Q. clsx는?
A. 조건에 따라 이름표를 바꿔 붙이는 도구.
className={clsx(
'inline-flex rounded-full px-2 py-1 text-sm', // 항상
{
'bg-gray-100 text-gray-500': status === 'pending', // pending이면 회색
'bg-green-500 text-white': status === 'paid', // paid면 초록
},
)}
Q. pending과 paid 차이?
A. 송장 상태 값. pending = 결제 대기, paid = 결제 완료. definitions.ts에 'pending' | 'paid' 둘 중 하나만 허용.
Q. ? : 코드는?
{status === 'pending' ? (<>Pending <ClockIcon /></>) : null}
A. 조건이 맞으면 보여주고, 아니면 null(아무것도 안 보임). = 조건부 렌더링
| 바꾸는 것 | |
|---|---|
| clsx | 모양 (색) |
? : | 내용 (글자, 아이콘) |
Q. 작동을 직접 보려면?
import InvoiceStatus from '@/app/ui/invoices/status';
<InvoiceStatus status="pending" />
<InvoiceStatus status="paid" />
status={invoice.status}로 데이터에서 꺼냄| 문제 | 원인 | 해결 |
|---|---|---|
Command "dev" not found | package.json 없는 폴더(상위/빈 폴더)에서 실행 | cd nextjs-dashboard 또는 프로젝트 폴더 자체를 VS Code로 열기 |
Unable to acquire lock | 같은 서버가 이미 켜져 있음 | localhost:3000 바로 열기 또는 lsof -ti:3000 \| xargs kill |
command not found: localhost:3000 | 주소를 터미널에 입력 | 브라우저 주소창에 입력 |
| 사이트 안 열림 | VS Code 종료 = 서버 종료 | 폴더 열기 → pnpm dev |
substitution failed | 복사 시 특수 문자 / 터미널 준비 전 입력 | 직접 타이핑 |
| global.css 모듈 못 찾음 (빨간 줄) | TypeScript가 .css 설명서 없음 | 무시 가능, 또는 css.d.ts에 declare module '*.css'; |
baseUrl deprecated | TS 7에서 없어질 설정 예고 | 무시 가능, 또는 tsconfig에서 한 줄 삭제 |
| 탭에 ● 표시 | 저장 안 됨 | Cmd+S |
pnpm dev → 브라우저