Skip to main content

24장. 첫 화면 만들기

[5부] 첫 화면 만들기

[5부] 첫 화면 만들기

화면이 떠야 손이 풀린다

처음 웹 서비스를 만들 때 가장 강력한 순간은 복잡한 기능이 완성되는 때가 아니다. 브라우저를 열었더니 내가 만든 문장과 버튼이 화면에 딱 나타나는 바로 그 순간이다. 그 짧은 경험이 이상하게 사람을 바꾼다. "어? 진짜 되네." 이 감각이 생기면, 그다음부터는 로그인도 붙이고 데이터도 저장해 보고 싶어진다.

Next.js는 React 위에서 동작하는 풀스택 웹 프레임워크다. 쉽게 말해, 화면도 만들고 서버 쪽 기능도 함께 키워 갈 수 있는 작업장이라고 생각하면 된다.1 지금은 거대한 기능보다 먼저, 서비스의 입구가 되는 첫 화면을 만들어 보자.

첫 화면은 화려할 필요가 없다. 오히려 단순할수록 좋다. 지금 필요한 것은 세 가지뿐이다.

  • 서비스 이름

  • 한 줄 설명

  • 사용자가 다음으로 누를 버튼

이 세 가지만 있어도 화면은 이미 서비스처럼 보이기 시작한다.

첫 화면에서 해야 할 일

많은 초보자가 첫 화면을 만들 때 디자인부터 걱정한다. 색은 무슨 색으로 하지, 카드 그림자는 넣을까, 애니메이션은 어떻게 넣지 같은 고민이다. 물론 그런 고민도 즐겁다. 하지만 첫 화면의 핵심은 장식보다 역할이다.

첫 화면은 처음 온 사람에게 세 가지 질문에 답해야 한다.

이 서비스는 뭐지?

나는 여기서 뭘 할 수 있지?

지금 뭘 누르면 되지?

예를 들어 우리가 만들 서비스가 작은 글 공유 서비스라고 해 보자. 그렇다면 첫 화면의 문장은 이렇게 단순하게 갈 수 있다.

"생각을 짧게 기록하고, 다시 찾아볼 수 있는 작은 웹 서비스"

그리고 버튼은 이렇게 두 개면 충분하다.

"시작하기"

"글 보러 가기"

첫 화면은 설명서가 아니라 안내판이다. 길게 설득하기보다, 사용자를 다음 행동으로 이끌면 된다.

Next.js에서 첫 화면은 어디에 있을까

Next.js의 App Router에서는 파일과 폴더 구조가 곧 주소가 된다. app/page.tsx는 / 경로, 즉 사이트의 첫 화면을 담당한다. app/layout.tsx는 여러 페이지에서 공통으로 쓰는 뼈대를 담당한다. 그리고 루트 레이아웃인 app/layout.tsx는 반드시 있어야 하며, html과 body 태그를 포함해야 한다.2

이 구조를 처음 보면 조금 신기하다. 보통은 라우터 설정 파일이 따로 있을 것 같지만, Next.js는 폴더와 파일 이름 자체로 길을 만든다. 그래서 초보자에게 오히려 직관적이다.

아주 단순하게 보면 이렇게 이해하면 된다.

  • app/layout.tsx: 모든 페이지를 감싸는 공통 틀

  • app/page.tsx: 사이트 첫 화면

  • app/posts/page.tsx: /posts 화면

지금은 app/layout.tsx와 app/page.tsx 두 파일만 잘 잡아도 충분하다.

공통 레이아웃부터 세우기

먼저 전체 화면의 뼈대를 만든다. 로고처럼 보일 서비스 이름, 간단한 메뉴, 그리고 내용이 들어갈 자리인 main 정도면 충분하다.

// app/layout.tsx
import "./globals.css";
import Link from "next/link";

export const metadata = {
  title: "Vibe Notes",
  description: "생각을 기록하고 나누는 작은 웹 서비스",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="ko">
      <body>
        <header className="site-header">
          <Link href="/" className="logo">
            Vibe Notes
          </Link>

          <nav className="site-nav">
            <Link href="/login">로그인</Link>
            <Link href="/posts">글 보러 가기</Link>
          </nav>
        </header>

        <main>{children}</main>
      </body>
    </html>
  );
}

여기서 중요한 것은 어려운 기술이 아니다. 구조를 읽는 눈이다.

children은 레이아웃 안에 들어갈 실제 페이지 내용이다. 즉, app/page.tsx가 렌더링되면 그 내용이 main 안에 들어간다. 그래서 헤더는 계속 남아 있고, 페이지 내용만 바뀐다. 이런 방식 덕분에 같은 네비게이션을 매번 다시 쓰지 않아도 된다.2

이 시점에서 초보자가 자주 하는 실수도 하나 있다. 모든 내용을 page.tsx에 몰아넣는 것이다. 그렇게 해도 잠깐은 돌아간다. 하지만 페이지가 늘어나면 헤더와 메뉴를 복붙하게 되고, 수정할 때마다 여기저기 다 고쳐야 한다. 처음부터 공통 부분은 레이아웃으로 분리하는 습관을 들이면 훨씬 편하다.

첫 화면 문장 채우기

이제 실제 첫 화면을 만든다. 중요한 건 멋진 문장을 쓰는 것이 아니라, 한눈에 이해되는 문장을 쓰는 것이다.

// app/page.tsx
import Link from "next/link";

export default function HomePage() {
  return (
    <section className="hero-section">
      <p className="eyebrow">내 아이디어를 바로 서비스로</p>
      <h1>AI와 함께 만드는 나만의 첫 웹 서비스</h1>
      <p className="hero-text">
        회원가입, 로그인, 글 작성, 검색까지 직접 만들며
        풀스택 웹 서비스의 흐름을 익혀보세요.
      </p>

      <div className="hero-actions">
        <Link href="/signup" className="primary-button">
          시작하기
        </Link>
        <Link href="/posts" className="secondary-button">
          글 보러 가기
        </Link>
      </div>
    </section>
  );
}

여기서 Link는 Next.js가 제공하는 이동용 컴포넌트다. 일반적인 <a> 태그처럼 보이지만, 페이지 이동을 더 부드럽게 처리하고 다음 화면을 미리 준비하는 데 도움을 준다.2

문장을 만들 때는 욕심을 줄이는 편이 좋다. 첫 화면 문구는 광고 카피 대회가 아니다. 사용자가 3초 안에 이해하면 성공이다.

제목은 크게 한 문장, 설명은 두 줄 안쪽, 버튼은 두 개 정도가 가장 다루기 쉽다. 버튼이 너무 많아지면 오히려 사용자가 멈춘다. 첫 화면은 선택지를 넓히는 곳이 아니라, 첫 발을 떼게 하는 곳이다.

아주 가볍게 보기 좋게 만들기

지금 단계에서는 스타일을 깊게 파지 않아도 된다. 그래도 너무 밋밋하면 성취감이 덜할 수 있으니, 최소한의 스타일만 넣어 보자.

/* app/globals.css */
* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  font-family: Arial, sans-serif;
  background: #f7f8fb;
  color: #111827;
}

a {
  color: inherit;
  text-decoration: none;
}

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px 24px;
  border-bottom: 1px solid #e5e7eb;
  background: white;
}

.logo {
  font-size: 20px;
  font-weight: 700;
}

.site-nav {
  display: flex;
  gap: 16px;
}

.hero-section {
  max-width: 760px;
  margin: 0 auto;
  padding: 80px 24px;
}

.eyebrow {
  margin-bottom: 12px;
  color: #2563eb;
  font-weight: 700;
}

.hero-section h1 {
  margin: 0;
  font-size: 44px;
  line-height: 1.2;
}

.hero-text {
  margin-top: 20px;
  font-size: 18px;
  line-height: 1.7;
  color: #4b5563;
}

.hero-actions {
  display: flex;
  gap: 12px;
  margin-top: 28px;
}

.primary-button,
.secondary-button {
  display: inline-block;
  padding: 12px 18px;
  border-radius: 12px;
  font-weight: 700;
}

.primary-button {
  background: #111827;
  color: white;
}

.secondary-button {
  background: white;
  border: 1px solid #d1d5db;
}

이 정도만 넣어도 화면이 훨씬 웹 서비스처럼 보인다. 아직 카드도 없고 아이콘도 없고 애니메이션도 없지만, 중요한 것은 이미 갖췄다. 구조가 있고, 메시지가 있고, 행동 버튼이 있다.

처음부터 완성형 디자인을 만들려고 하면 쉽게 지친다. 지금은 "보기에 나쁘지 않다" 정도면 충분하다. 다듬기는 나중에도 얼마든지 할 수 있다.

AI에게 이렇게 부탁하면 잘 움직인다

Claude Code나 Codex에게 첫 화면을 맡길 때는 "예쁘게 만들어줘"보다 "역할이 보이게 만들어줘"가 훨씬 낫다. AI는 애매한 요청을 받으면 과하게 화려한 코드를 만들거나, 쓸데없이 많은 컴포넌트를 쪼개기도 한다.

이럴 때는 목표와 제약을 함께 주는 것이 좋다.

Next.js App Router 프로젝트의 첫 화면을 만들어줘.
app/layout.tsx에는 공통 헤더를 넣고,
app/page.tsx에는 서비스 소개 문구와 CTA 버튼 2개를 넣어줘.
서비스 이름은 Vibe Notes,
한 줄 설명은 초보자도 이해하기 쉽게 써줘.
스타일은 globals.css에 최소한만 추가하고,
아직 컴포넌트 분리는 하지 마.

조금 더 구체적으로 다듬고 싶다면 이렇게 말할 수도 있다.

너무 화려하게 만들지 말고,
처음 방문한 사용자가 3초 안에 이해할 수 있는 랜딩 화면으로 작성해줘.
버튼은 '시작하기', '글 보러 가기' 두 개만 두고,
불필요한 라이브러리는 추가하지 마.

좋은 요청은 늘 두 가지를 포함한다. 무엇을 만들지, 그리고 무엇은 하지 말아야 하는지다. 이 두 가지가 들어가면 AI의 결과가 훨씬 안정적이다.

실행했을 때 꼭 확인할 것

코드를 쓴 뒤에는 브라우저를 열기 전에 한 번만 더 생각해 보자. 첫 화면의 목표는 "코드가 있다"가 아니라 "사용자가 이해한다"다.

확인할 것은 많지 않다.

  • 주소 http://localhost:3000에서 첫 화면이 바로 뜨는가

  • 서비스 이름과 설명이 한눈에 읽히는가

  • 버튼을 눌렀을 때 이동할 자리로 연결되는가

  • 헤더와 본문이 서로 섞이지 않고 구분되는가

여기서 버튼의 목적지가 아직 준비되지 않았더라도 괜찮다. /signup, /posts 같은 경로는 일단 먼저 연결해 두고, 나중에 해당 페이지를 채워 넣으면 된다. 웹 서비스는 퍼즐처럼 한 조각씩 맞춰 가는 작업이다. 모든 조각이 한 번에 준비될 필요는 없다.

자주 막히는 작은 문제들

초보자가 이 단계에서 자주 부딪히는 문제는 생각보다 비슷하다.

브라우저에 화면이 안 바뀐다면 파일 위치를 먼저 보자. page.tsx가 app 폴더 안에 있는지, 파일 이름이 정말 page.tsx인지 확인하는 것만으로 해결되는 경우가 많다.

헤더가 안 보인다면 layout.tsx가 루트인 app/layout.tsx인지 확인하자. 다른 폴더 안의 layout.tsx는 그 하위 경로에만 적용된다.

링크를 눌렀는데 404가 나도 너무 놀랄 필요는 없다. 아직 그 페이지를 안 만들었기 때문이다. 오히려 잘 연결되고 있다는 뜻이다. 주소 체계부터 먼저 잡아 두는 것도 괜찮은 개발 방식이다.

스타일이 안 먹는다면 globals.css가 layout.tsx에서 import되고 있는지 보자. CSS 파일을 만들기만 하고 불러오지 않으면 브라우저는 모른 척한다. 꽤 흔한 무심함이다.

첫 화면은 작지만, 서비스의 시작점이다

첫 화면을 만드는 일은 단순히 빈 페이지에 문장을 올리는 작업이 아니다. 서비스의 얼굴을 만드는 일이고, 앞으로 붙일 기능들의 기준점을 세우는 일이다.

이제 화면에는 이름이 있고, 설명이 있고, 이동 버튼이 있다. 아직 로그인도 없고 글 목록도 없고 검색도 없지만, 중요한 변화는 이미 일어났다. 프로젝트가 더 이상 "폴더 속 코드"가 아니라 "브라우저에서 보이는 서비스"가 되었다는 점이다.

이 감각이 생기면 다음 단계가 훨씬 쉬워진다. 그다음에는 화면을 조금 더 잘게 나누고, 입력을 받고, 목록을 보여 주고, 실제 데이터와 연결하면 된다. 하지만 모든 흐름의 출발점은 늘 같다. 사용자가 처음 마주하는 한 장의 화면이다.

브라우저에 첫 화면이 뜬다면, 이미 절반은 시작한 셈이다.

참고

1시작하기 – Nextjs 한글 문서

2Getting Started: Layouts and Pages | Next.js

책 목록

바이브 코딩으로 완성하는 첫 풀스택 웹 서비스

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기