마크다운 완전 가이드 — 블로그 스타일링의 모든 것
마크다운(Markdown)은 읽기 쉽고 쓰기 쉬운 경량 마크업 언어다. 2004년 John Gruber와 Aaron Swartz가 설계했으며, 오늘날 GitHub, Notion, 대부분의 블로그 플랫폼에서 표준처럼 쓰인다. 이 글은 마크다운 문법을 처음 접하는 사람부터 레퍼런스가 필요한 숙련자까지 모두를 위해 작성했다. 한 페이지에서 거의 모든 문법을 직접 확인하고 복사해 쓸 수 있도록 구성했다.
1. 제목 계층 (Headings)
제목은 # 기호의 개수로 레벨을 결정한다. HTML의 <h1> ~ <h6>에 대응한다. 블로그 글에서는 보통 ##(h2)부터 시작하고 ####(h4)까지 사용하는 것을 권장한다. #(h1)은 페이지 제목과 충돌할 수 있으므로 본문에서는 피하는 편이 좋다.
1-1. h3 소제목
h3는 h2 아래에서 세부 항목을 나눌 때 사용한다.
1-1-1. h4 세부 항목
h4는 더 세밀한 분류가 필요할 때 사용한다. 너무 깊은 계층은 가독성을 해치므로 h4 이하는 꼭 필요한 경우에만 쓰는 것이 좋다.
2. 텍스트 서식 (Text Formatting)
일반 문단 텍스트에 강조와 의미를 더하는 인라인 서식들이다.
- 굵게(Bold): 양쪽에
**또는__를 붙인다. 핵심 키워드나 경고 문구에 사용한다. - 기울임(Italic): 양쪽에
*또는_를 붙인다. 책 제목, 외래어, 강조에 사용한다. 취소선(Strikethrough): 양쪽에~~를 붙인다. 오류 수정이나 더 이상 유효하지 않은 정보를 나타낼 때 쓴다.인라인 코드(Inline Code): 백틱(`)으로 감싼다. 변수명, 함수명, 명령어를 본문 안에서 표기할 때 쓴다.- 굵게+기울임:
**_텍스트_**처럼 조합할 수도 있다.
실제 문장에서 혼합해 보면 이런 식이다. useState는 React의 핵심 훅 중 하나로, *상태(state)*를 함수형 컴포넌트에서 관리할 수 있게 해준다. 클래스 컴포넌트의 this.state는 이제 레거시다.
3. 리스트 (Lists)
3-1. 순서 없는 리스트
-, *, + 중 하나로 시작하면 된다. 보통 -를 통일해서 쓰는 것이 일관성 있다.
- 프론트엔드 프레임워크
- React
- Next.js
- Remix
- Vue
- Nuxt.js
- Svelte
- React
- 백엔드 언어
- TypeScript (Node.js / Bun)
- Go
- Rust
- 데이터베이스
- PostgreSQL
- SQLite
- Redis
3-2. 순서 있는 리스트
숫자와 점(.)으로 시작한다. 실제 숫자가 달라도 렌더링 시 자동으로 순서가 맞춰진다.
- 요구사항 분석
- 와이어프레임 설계
- 컴포넌트 구조 정의
- 개발 환경 설정
- 구현
- UI 레이아웃
- API 연동
- 상태 관리
- 테스트
- 배포
3-3. 체크리스트
- 마크다운 문법 정리
- 코드블록 예제 추가
- 테이블 작성
- 이미지 최적화
- 다크모드 대응 확인
- SEO 메타데이터 점검
4. 코드블록 (Code Blocks)
코드블록은 세 개의 백틱(```)으로 시작하고 끝낸다. 언어 이름을 명시하면 문법 강조(syntax highlighting)가 적용된다.
4-1. JavaScript
// 비동기 데이터 페칭 예시
async function fetchPosts(page = 1, limit = 10) {
const url = new URL('/api/posts', window.location.origin);
url.searchParams.set('page', page);
url.searchParams.set('limit', limit);
const response = await fetch(url.toString());
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
}
// 호출 예시
fetchPosts(1, 5)
.then(posts => console.log(posts))
.catch(err => console.error('Failed to fetch:', err));4-2. TypeScript
interface Post {
id: string;
title: string;
slug: string;
date: string;
tags: string[];
draft: boolean;
}
type PostSummary = Pick<Post, 'id' | 'title' | 'slug' | 'date'>;
function sortPostsByDate(posts: Post[]): Post[] {
return [...posts].sort(
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()
);
}
function filterPublished(posts: Post[]): PostSummary[] {
return sortPostsByDate(posts)
.filter(post => !post.draft)
.map(({ id, title, slug, date }) => ({ id, title, slug, date }));
}4-3. CSS
/* 마크다운 렌더링 스타일 */
.prose {
max-width: 65ch;
margin: 0 auto;
line-height: 1.75;
color: var(--color-text);
}
.prose h2 {
font-size: 1.5rem;
font-weight: 700;
margin-top: 2rem;
margin-bottom: 1rem;
border-bottom: 1px solid var(--color-border);
padding-bottom: 0.5rem;
}
.prose code {
background-color: var(--color-code-bg);
padding: 0.2em 0.4em;
border-radius: 4px;
font-size: 0.875em;
font-family: 'JetBrains Mono', 'Fira Code', monospace;
}
.prose pre code {
background-color: transparent;
padding: 0;
}4-4. Bash / Shell
# 프로젝트 초기화
mkdir my-blog && cd my-blog
bun create next-app . --typescript --tailwind --app
# 의존성 설치
bun add @mdx-js/react gray-matter reading-time
# 개발 서버 실행
bun dev
# 빌드 및 배포
bun run build
bun run start4-5. JSON
{
"name": "hubblelog",
"version": "0.1.0",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "^15.0.0",
"react": "^19.0.0",
"gray-matter": "^4.0.3"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0",
"@types/react": "^19.0.0"
}
}5. 인용구 (Blockquotes)
> 기호로 인용구를 만든다. 여러 줄에 걸쳐 사용할 수 있고, 중첩도 가능하다.
5-1. 일반 인용구
마크다운의 목표는 최대한 읽기 쉽고 쓰기 쉽게 만드는 것이다. 마크다운으로 서식이 지정된 문서는 태그나 서식 지정 명령으로 표시되지 않고 일반 텍스트 그대로 출판될 수 있어야 한다.
— John Gruber, Markdown 소개 문서 (2004)
5-2. 중첩 인용구
좋은 코드에 대한 논쟁에서 자주 인용되는 말이 있다.
코드는 작성하는 것보다 읽히는 횟수가 훨씬 많다. — Guido van Rossum
이 원칙은 마크다운 문서를 작성할 때도 동일하게 적용된다. 렌더링된 결과뿐 아니라 소스 텍스트 자체가 읽기 쉬어야 좋은 문서다.
5-3. 주의/팁 스타일 인용구
주의:
draft: true로 설정된 포스트는 빌드 시 제외된다. 공개하려면 반드시draft: false로 변경하거나 필드를 삭제해야 한다.
팁: VSCode에서 마크다운을 작성할 때
Ctrl+Shift+V(Mac:Cmd+Shift+V)로 미리보기를 열 수 있다.
6. 링크 (Links)
6-1. 인라인 링크
기본 링크 문법은 [텍스트](URL) 형식이다.
6-2. 본문 내 인라인 링크
마크다운은 John Gruber가 만들었고, GitHub에서 대중화됐다. 오늘날 MDX를 사용하면 마크다운 안에 JSX 컴포넌트를 삽입할 수도 있다.
6-3. 링크에 title 속성 추가
마우스를 올리면 툴팁이 나타나는 링크를 만들 수 있다.
7. 이미지 (Images)
이미지 문법은 링크와 비슷하지만 앞에 !가 붙는다: .
7-1. 기본 이미지
7-2. 이미지에 title 속성 추가
7-3. 이미지에 링크 걸기
8. 테이블 (Tables)
파이프(|)와 하이픈(-)으로 테이블을 만든다. 헤더 행 아래에 구분선을 넣고, :의 위치로 정렬 방향을 지정한다.
8-1. 마크다운 지원 현황 비교
| 문법 | CommonMark | GitHub GFM | MDX |
|---|---|---|---|
| 제목(Headings) | ✅ | ✅ | ✅ |
| 굵게/기울임 | ✅ | ✅ | ✅ |
| 취소선 | ❌ | ✅ | ✅ |
| 테이블 | ❌ | ✅ | ✅ |
| 체크리스트 | ❌ | ✅ | ✅ |
| 자동 링크 | ✅ | ✅ | ✅ |
| JSX 컴포넌트 | ❌ | ❌ | ✅ |
| 수식(LaTeX) | ❌ | ✅ | 플러그인 필요 |
8-2. 인기 블로그 프레임워크 비교
| 프레임워크 | 언어 | 마크다운 지원 | 빌드 속도 | 러닝커브 |
|---|---|---|---|---|
| Next.js | React / TS | MDX | 빠름 | 중간 |
| Astro | Any / TS | MDX, MD | 매우 빠름 | 낮음 |
| Hugo | Go 템플릿 | MD | 매우 빠름 | 높음 |
| Jekyll | Ruby / Liquid | MD | 보통 | 낮음 |
| Gatsby | React / TS | MDX | 느림 | 높음 |
9. 구분선 (Horizontal Rule)
세 개 이상의 -, *, _으로 구분선을 만든다.
위는 ---으로 만든 구분선이다.
위는 ***으로 만든 구분선이다. 시각적으로 동일하지만 소스 가독성을 위해 ---를 권장한다.
10. 마무리 — 마크다운을 잘 쓰는 법
마크다운은 문법보다 사용 철학이 더 중요하다. 가장 중요한 원칙 몇 가지를 정리하면 이렇다.
- 구조가 먼저다: 헤딩 계층을 논리적으로 잡아야 TOC와 스크린 리더 모두 제대로 동작한다.
- 덜 쓸수록 좋다: 서식 과잉은 오히려 핵심을 흐린다. Bold는 진짜 중요한 것에만 쓰자.
- 소스도 읽힌다: 렌더링된 화면뿐 아니라
.md파일 자체도 사람이 읽는다. 빈 줄과 들여쓰기를 일관되게 유지하자. - 링크는 의미 있게:
여기를 클릭대신Next.js 공식 문서처럼 목적지를 알 수 있는 텍스트를 써야 접근성이 높아진다. - 코드는 항상 언어를 명시:
```js처럼 언어를 명시해야 신택스 하이라이팅이 적용되고 가독성이 좋아진다.
좋은 글은 좋은 구조에서 시작한다. 마크다운은 그 구조를 강요하지 않고, 자연스럽게 유도한다.
이 가이드가 마크다운을 처음 배우는 사람에게는 입문서로, 이미 쓰고 있는 사람에게는 레퍼런스로 도움이 되길 바란다.