<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mskimdev.log</title>
        <link>https://velog.io/</link>
        <description>&lt;- 개발 공부하는 나</description>
        <lastBuildDate>Tue, 19 May 2026 08:11:50 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>mskimdev.log</title>
            <url>https://velog.velcdn.com/images/mskim_/profile/a3ee3547-8be2-484a-9e56-1796b33798c2/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. mskimdev.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mskim_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[의사 클래스 / 의사 요소]]></title>
            <link>https://velog.io/@mskim_/%EC%9D%98%EC%82%AC-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%98%EC%82%AC-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@mskim_/%EC%9D%98%EC%82%AC-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%9D%98%EC%82%AC-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Tue, 19 May 2026 08:11:50 GMT</pubDate>
            <description><![CDATA[<h1 id="의사-클래스와-의사-요소">의사 클래스와 의사 요소</h1>
<p>마우스를 올렸을 때 색이 바뀌거나, 첫 번째 항목에만 스타일이 적용되거나, 요소 앞뒤에 내용이 자동으로 붙는 기능. 이런 것들이 HTML에 추가 클래스 없이 CSS만으로 가능하다. 의사 클래스와 의사 요소 덕분이다.</p>
<hr>
<h2 id="의사-클래스-pseudo-class">의사 클래스 (Pseudo-class)</h2>
<p>요소의 <strong>특정 상태</strong>에 스타일을 적용한다. <code>:</code> 하나로 표기한다.</p>
<h3 id="마우스포커스-상태">마우스/포커스 상태</h3>
<pre><code class="language-css">/* 마우스를 올렸을 때 */
a:hover {
  color: royalblue;
  text-decoration: underline;
}

/* 클릭 중일 때 */
button:active {
  background-color: #ccc;
  transform: scale(0.98);
}

/* 포커스를 받았을 때 (input, a 등) */
input:focus {
  outline: 2px solid royalblue;
  border-color: royalblue;
}

/* 이미 방문한 링크 */
a:visited {
  color: purple;
}</code></pre>
<hr>
<h3 id="구조-관련-의사-클래스">구조 관련 의사 클래스</h3>
<pre><code class="language-css">/* 첫 번째 자식 */
li:first-child {
  font-weight: bold;
}

/* 마지막 자식 */
li:last-child {
  border-bottom: none;
}

/* n번째 자식 */
li:nth-child(3) {
  color: red;
}

/* 짝수 번째 */
li:nth-child(even) {
  background-color: #f5f5f5;
}

/* 홀수 번째 */
li:nth-child(odd) {
  background-color: white;
}

/* 3의 배수 번째 */
li:nth-child(3n) {
  color: navy;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/31b2bb5e-9e7a-46d0-9614-e4814c2a5a83/image.png" alt=""></p>
<hr>
<h3 id="상태-관련-의사-클래스">상태 관련 의사 클래스</h3>
<pre><code class="language-css">/* 체크된 체크박스 */
input:checked {
  accent-color: royalblue;
}

/* 비활성화된 요소 */
input:disabled {
  background-color: #eee;
  cursor: not-allowed;
}

/* 유효한 input 값 */
input:valid {
  border-color: green;
}

/* 유효하지 않은 input 값 */
input:invalid {
  border-color: red;
}

/* 유일한 자식일 때 */
p:only-child {
  font-style: italic;
}</code></pre>
<hr>
<h3 id="not-선택자">not() 선택자</h3>
<pre><code class="language-css">/* button이 아닌 모든 요소 */
input:not([type=&quot;submit&quot;]) {
  border: 1px solid #ccc;
}

/* 마지막 li가 아닌 것들 */
li:not(:last-child) {
  border-bottom: 1px solid #eee;
}</code></pre>
<hr>
<h2 id="의사-요소-pseudo-element">의사 요소 (Pseudo-element)</h2>
<p>요소의 <strong>특정 부분</strong>을 선택하거나, <strong>존재하지 않는 요소를 가상으로 만든다.</strong> <code>::</code> 두 개로 표기한다.</p>
<h3 id="before-after">::before, ::after</h3>
<p>요소 안의 콘텐츠 앞(<code>::before</code>)과 뒤(<code>::after</code>)에 가상 콘텐츠를 삽입한다. <code>content</code> 속성이 필수다.</p>
<pre><code class="language-css">.required::after {
  content: &quot; *&quot;;
  color: red;
}

.quote::before {
  content: &#39;&quot;&#39;;
  font-size: 2em;
  color: #ccc;
}

.quote::after {
  content: &#39;&quot;&#39;;
  font-size: 2em;
  color: #ccc;
}</code></pre>
<pre><code class="language-html">&lt;label class=&quot;required&quot;&gt;이름&lt;/label&gt;
&lt;!-- 렌더링: 이름 * --&gt;</code></pre>
<p><code>content: &quot;&quot;</code>로 비워두고 CSS로만 꾸미는 방식도 많이 쓴다 (장식용 선이나 도형).</p>
<hr>
<h3 id="first-line-first-letter">::first-line, ::first-letter</h3>
<pre><code class="language-css">/* 첫 번째 줄 */
p::first-line {
  font-weight: bold;
  color: navy;
}

/* 첫 번째 글자 (드롭캡 효과) */
p::first-letter {
  font-size: 3em;
  float: left;
  margin-right: 8px;
  line-height: 1;
}</code></pre>
<hr>
<h3 id="placeholder">::placeholder</h3>
<pre><code class="language-css">input::placeholder {
  color: #aaa;
  font-style: italic;
}</code></pre>
<hr>
<h3 id="selection">::selection</h3>
<p>사용자가 텍스트를 드래그해서 선택했을 때의 스타일이다.</p>
<pre><code class="language-css">::selection {
  background-color: royalblue;
  color: white;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/b2dd6d81-3278-4146-b667-a9e8fa172b5d/image.png" alt=""></p>
<hr>
<h2 id="의사-클래스-vs-의사-요소">의사 클래스 vs 의사 요소</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>의사 클래스</th>
<th>의사 요소</th>
</tr>
</thead>
<tbody><tr>
<td>표기</td>
<td><code>:hover</code>, <code>:nth-child()</code></td>
<td><code>::before</code>, <code>::after</code></td>
</tr>
<tr>
<td>대상</td>
<td>요소의 상태</td>
<td>요소의 특정 부분 또는 가상 콘텐츠</td>
</tr>
<tr>
<td>예시</td>
<td>마우스 오버, 첫 번째 자식</td>
<td>앞뒤 콘텐츠 삽입, 첫 글자</td>
</tr>
</tbody></table>
<hr>
<p>의사 클래스와 의사 요소를 잘 활용하면 HTML에 불필요한 클래스를 추가하지 않고도 세밀한 스타일을 만들 수 있다. <code>:hover</code>로 인터랙션을 주고, <code>::before</code>로 꾸밈 요소를 추가하는 패턴은 CSS 어디서나 만날 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[반응형 웹]]></title>
            <link>https://velog.io/@mskim_/%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9</link>
            <guid>https://velog.io/@mskim_/%EB%B0%98%EC%9D%91%ED%98%95-%EC%9B%B9</guid>
            <pubDate>Tue, 19 May 2026 08:08:58 GMT</pubDate>
            <description><![CDATA[<h1 id="반응형-웹--미디어-쿼리">반응형 웹 — 미디어 쿼리</h1>
<p>같은 HTML 파일을 노트북으로 열면 넓은 화면에 맞게 보이고, 스마트폰으로 열면 작은 화면에 맞게 레이아웃이 바뀐다. 이걸 가능하게 하는 CSS 기능이 미디어 쿼리다.</p>
<hr>
<h2 id="반응형-웹이란">반응형 웹이란</h2>
<p><strong>화면 크기, 해상도, 기기 종류에 따라 레이아웃과 스타일이 유연하게 바뀌는 웹</strong>을 말한다. 하나의 HTML/CSS로 데스크탑, 태블릿, 모바일을 모두 대응한다.</p>
<hr>
<h2 id="viewport-설정">viewport 설정</h2>
<p>반응형 웹의 첫 번째 단계는 HTML <code>&lt;head&gt;</code>에 이 한 줄을 넣는 것이다.</p>
<pre><code class="language-html">&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;</code></pre>
<p>이 설정이 없으면 모바일 브라우저가 페이지를 데스크탑 너비로 렌더링한 뒤 축소해서 보여준다. 미디어 쿼리를 써도 제대로 동작하지 않는다.</p>
<hr>
<h2 id="미디어-쿼리-기본-문법">미디어 쿼리 기본 문법</h2>
<pre><code class="language-css">@media (조건) {
  /* 조건이 참일 때 적용되는 스타일 */
}</code></pre>
<pre><code class="language-css">/* 화면 너비가 768px 이하일 때 */
@media (max-width: 768px) {
  body {
    font-size: 14px;
  }

  .container {
    flex-direction: column;
  }
}</code></pre>
<hr>
<h2 id="브레이크포인트-breakpoint">브레이크포인트 (Breakpoint)</h2>
<p>레이아웃이 바뀌는 기준 너비를 브레이크포인트라고 한다. 보편적으로 쓰이는 기준은 이렇다.</p>
<pre><code class="language-css">/* 모바일 */
@media (max-width: 480px) { }

/* 태블릿 */
@media (max-width: 768px) { }

/* 소형 데스크탑 */
@media (max-width: 1024px) { }

/* 대형 데스크탑 */
@media (min-width: 1200px) { }</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/302a5994-a4b4-422b-b37e-fc6edb9fbf73/image.png" alt=""></p>
<hr>
<h2 id="mobile-first-vs-desktop-first">Mobile First vs Desktop First</h2>
<h3 id="desktop-first-max-width-사용">Desktop First (max-width 사용)</h3>
<p>기본 스타일을 데스크탑으로 작성하고, 화면이 작아질수록 조건을 추가한다.</p>
<pre><code class="language-css">/* 기본: 데스크탑 */
.container {
  display: flex;
  flex-direction: row;
}

/* 모바일 */
@media (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}</code></pre>
<h3 id="mobile-first-min-width-사용">Mobile First (min-width 사용)</h3>
<p>기본 스타일을 모바일로 작성하고, 화면이 커질수록 조건을 추가한다.</p>
<pre><code class="language-css">/* 기본: 모바일 */
.container {
  flex-direction: column;
}

/* 태블릿 이상 */
@media (min-width: 768px) {
  .container {
    flex-direction: row;
  }
}</code></pre>
<p>모바일 트래픽이 많은 요즘에는 <strong>Mobile First</strong>가 권장된다. 성능 면에서도 불필요한 스타일을 덮어쓰는 일이 줄어든다.</p>
<hr>
<h2 id="실전-예시--3열-카드-→-1열">실전 예시 — 3열 카드 → 1열</h2>
<pre><code class="language-css">/* 데스크탑: 3열 */
.card-list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}

/* 태블릿: 2열 */
@media (max-width: 1024px) {
  .card-list {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* 모바일: 1열 */
@media (max-width: 600px) {
  .card-list {
    grid-template-columns: 1fr;
  }
}</code></pre>
<hr>
<h2 id="기타-미디어-조건">기타 미디어 조건</h2>
<pre><code class="language-css">/* 방향 — 세로 모드 */
@media (orientation: portrait) { }

/* 방향 — 가로 모드 */
@media (orientation: landscape) { }

/* 인쇄 */
@media print {
  .no-print { display: none; }
}

/* 다크 모드 선호 */
@media (prefers-color-scheme: dark) {
  body {
    background-color: #1a1a1a;
    color: #f0f0f0;
  }
}</code></pre>
<hr>
<h2 id="유동적-단위-활용">유동적 단위 활용</h2>
<p>미디어 쿼리와 함께 유동적인 단위를 쓰면 더 부드럽게 대응된다.</p>
<pre><code class="language-css">.container {
  width: 90%;          /* 화면 너비의 90% */
  max-width: 1200px;   /* 너무 넓어지지 않게 제한 */
  margin: 0 auto;      /* 가운데 정렬 */
}

img {
  max-width: 100%;     /* 부모를 넘지 않게 */
  height: auto;        /* 비율 유지 */
}</code></pre>
<hr>
<p>반응형 웹은 &quot;모든 화면에서 잘 보이게 한다&quot;는 목표다. 미디어 쿼리 자체는 문법이 단순하지만, 어떤 브레이크포인트에서 무엇을 바꿀지 판단하는 것이 핵심이다. 레이아웃을 먼저 잡고, 화면을 줄여가며 무너지는 지점을 찾는 것이 가장 빠른 방법이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Grid]]></title>
            <link>https://velog.io/@mskim_/Grid</link>
            <guid>https://velog.io/@mskim_/Grid</guid>
            <pubDate>Tue, 19 May 2026 08:07:21 GMT</pubDate>
            <description><![CDATA[<h1 id="grid">Grid</h1>
<p>Flexbox가 한 방향(가로 또는 세로)의 레이아웃을 다룬다면, Grid는 행과 열을 동시에 정의하는 <strong>2차원 레이아웃</strong>이다. 신문 지면처럼 칸을 나눠 콘텐츠를 배치하고 싶을 때 Grid가 적합하다.</p>
<hr>
<h2 id="grid-기본">Grid 기본</h2>
<pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;item&quot;&gt;1&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;2&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;3&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;4&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;5&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;6&lt;/div&gt;
&lt;/div&gt;</code></pre>
<pre><code class="language-css">.container {
  display: grid;
  grid-template-columns: 200px 200px 200px; /* 3열, 각 200px */
  grid-template-rows: 100px 100px;          /* 2행, 각 100px */
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/aa429559-8f38-462b-bcd2-8a7d25d3dbfb/image.png" alt=""></p>
<hr>
<h2 id="fr-단위">fr 단위</h2>
<p><code>fr</code>(fraction)은 그리드에서 사용 가능한 공간의 비율을 나타내는 단위다.</p>
<pre><code class="language-css">.container {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  /* 전체를 4등분 → 1/4, 2/4, 1/4 */
}</code></pre>
<p><code>px</code>와 <code>fr</code>을 섞어 쓸 수도 있다.</p>
<pre><code class="language-css">grid-template-columns: 200px 1fr;
/* 첫 열은 200px 고정, 나머지를 두 번째 열이 차지 */</code></pre>
<hr>
<h2 id="repeat">repeat()</h2>
<p>같은 크기의 열이나 행을 반복할 때 쓴다.</p>
<pre><code class="language-css">.container {
  grid-template-columns: repeat(3, 1fr);
  /* 1fr 1fr 1fr 과 동일 */

  grid-template-columns: repeat(4, 200px);
  /* 200px 200px 200px 200px */
}</code></pre>
<hr>
<h2 id="gap--아이템-간격">gap — 아이템 간격</h2>
<pre><code class="language-css">.container {
  gap: 16px;             /* 행·열 모두 16px */
  row-gap: 20px;         /* 행 간격만 */
  column-gap: 12px;      /* 열 간격만 */
}</code></pre>
<hr>
<h2 id="auto-fill과-auto-fit">auto-fill과 auto-fit</h2>
<p>컨테이너 너비에 맞게 열 수를 자동으로 조절한다. 반응형 그리드를 만들 때 유용하다.</p>
<pre><code class="language-css">.container {
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}</code></pre>
<ul>
<li><code>minmax(200px, 1fr)</code> — 최소 200px, 최대 1fr</li>
<li><code>auto-fill</code> — 빈 칸이 생겨도 자리를 유지</li>
<li><code>auto-fit</code> — 남는 공간을 기존 아이템이 채움</li>
</ul>
<hr>
<h2 id="아이템-배치--grid-column-grid-row">아이템 배치 — grid-column, grid-row</h2>
<p>아이템이 몇 번 선(grid line)부터 몇 번 선까지 차지할지 지정한다.</p>
<pre><code class="language-css">.item-a {
  grid-column: 1 / 3;  /* 1번 선 ~ 3번 선 (2열 차지) */
  grid-row: 1 / 2;     /* 1행 */
}

.item-b {
  grid-column: span 2; /* 현재 위치에서 2열 차지 */
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/fea4111f-d9c9-4c19-a007-c8888eb91334/image.png" alt=""></p>
<hr>
<h2 id="grid-template-areas">grid-template-areas</h2>
<p>이름으로 레이아웃 구조를 정의하는 직관적인 방법이다.</p>
<pre><code class="language-css">.container {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr 40px;
  grid-template-areas:
    &quot;header header&quot;
    &quot;sidebar main&quot;
    &quot;footer footer&quot;;
}

header { grid-area: header; }
aside  { grid-area: sidebar; }
main   { grid-area: main; }
footer { grid-area: footer; }</code></pre>
<hr>
<h2 id="flexbox-vs-grid">Flexbox vs Grid</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>Flexbox</th>
<th>Grid</th>
</tr>
</thead>
<tbody><tr>
<td>차원</td>
<td>1차원 (가로 또는 세로)</td>
<td>2차원 (가로 + 세로)</td>
</tr>
<tr>
<td>기준</td>
<td>콘텐츠 크기 기반</td>
<td>고정 트랙(행/열) 기반</td>
</tr>
<tr>
<td>적합한 상황</td>
<td>네비게이션, 버튼 그룹, 카드 한 줄</td>
<td>페이지 레이아웃, 갤러리, 대시보드</td>
</tr>
</tbody></table>
<p>둘은 경쟁 관계가 아니다. 페이지 전체 레이아웃은 Grid로 잡고, 그 안의 컴포넌트 배치는 Flexbox로 하는 식으로 함께 쓴다.</p>
<hr>
<p>Grid의 핵심은 &quot;행과 열을 먼저 정의하고, 아이템을 그 위에 올린다&quot;는 사고방식이다. 익숙해지면 복잡한 레이아웃도 코드 몇 줄로 표현된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Flexbox]]></title>
            <link>https://velog.io/@mskim_/Flexbox</link>
            <guid>https://velog.io/@mskim_/Flexbox</guid>
            <pubDate>Tue, 19 May 2026 08:04:45 GMT</pubDate>
            <description><![CDATA[<h1 id="flexbox">Flexbox</h1>
<p>요소들을 가로로 나란히 놓거나, 세로 가운데 정렬을 하거나, 공간을 균등하게 나누는 작업이 Flexbox 이전에는 꽤 까다로웠다. float를 쓰거나, <code>inline-block</code>에 여백을 계산하거나. Flexbox가 등장하면서 이런 레이아웃 작업이 직관적으로 바뀌었다.</p>
<hr>
<h2 id="flexbox-기본">Flexbox 기본</h2>
<p><code>display: flex</code>를 부모에 지정하면 Flexbox가 활성화된다. <strong>자식 요소들이 flex item이 된다.</strong></p>
<pre><code class="language-html">&lt;div class=&quot;container&quot;&gt;
  &lt;div class=&quot;item&quot;&gt;A&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;B&lt;/div&gt;
  &lt;div class=&quot;item&quot;&gt;C&lt;/div&gt;
&lt;/div&gt;</code></pre>
<pre><code class="language-css">.container {
  display: flex;
}</code></pre>
<p>기본적으로 자식들이 가로로 나란히 배치된다.</p>
<hr>
<h2 id="주축과-교차축">주축과 교차축</h2>
<p>Flexbox는 두 개의 축을 기준으로 동작한다.</p>
<ul>
<li><strong>주축(main axis)</strong> — 아이템이 나열되는 방향</li>
<li><strong>교차축(cross axis)</strong> — 주축과 수직인 방향</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mskim_/post/07b0d52a-00d3-4aac-b0a5-7d039962b3d8/image.png" alt=""></p>
<hr>
<h2 id="flex-direction--주축-방향">flex-direction — 주축 방향</h2>
<pre><code class="language-css">.container {
  flex-direction: row;            /* 가로 (기본값) */
  flex-direction: row-reverse;    /* 가로 역방향 */
  flex-direction: column;         /* 세로 */
  flex-direction: column-reverse; /* 세로 역방향 */
}</code></pre>
<hr>
<h2 id="justify-content--주축-정렬">justify-content — 주축 정렬</h2>
<p>아이템들을 <strong>주축 방향</strong>으로 어떻게 배치할지 지정한다.</p>
<pre><code class="language-css">.container {
  justify-content: flex-start;    /* 시작점에 모음 (기본값) */
  justify-content: flex-end;      /* 끝점에 모음 */
  justify-content: center;        /* 가운데 */
  justify-content: space-between; /* 양 끝 고정, 사이 균등 */
  justify-content: space-around;  /* 아이템 양쪽에 균등 여백 */
  justify-content: space-evenly;  /* 모든 여백 균등 */
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/b3ff90c6-95d2-4efe-81f2-da79d0829d49/image.png" alt=""></p>
<hr>
<h2 id="align-items--교차축-정렬">align-items — 교차축 정렬</h2>
<p>아이템들을 <strong>교차축 방향</strong>으로 어떻게 배치할지 지정한다.</p>
<pre><code class="language-css">.container {
  align-items: stretch;     /* 교차축 방향으로 늘림 (기본값) */
  align-items: flex-start;  /* 교차축 시작점 */
  align-items: flex-end;    /* 교차축 끝점 */
  align-items: center;      /* 교차축 가운데 */
  align-items: baseline;    /* 텍스트 기준선 맞춤 */
}</code></pre>
<hr>
<h2 id="가운데-정렬">가운데 정렬</h2>
<p>Flexbox로 수평·수직 가운데 정렬을 가장 간단하게 할 수 있다.</p>
<pre><code class="language-css">.container {
  display: flex;
  justify-content: center; /* 주축(가로) 가운데 */
  align-items: center;     /* 교차축(세로) 가운데 */
  height: 300px;
}</code></pre>
<hr>
<h2 id="flex-wrap--줄바꿈">flex-wrap — 줄바꿈</h2>
<p>아이템이 컨테이너를 넘칠 때 줄바꿈 여부를 지정한다.</p>
<pre><code class="language-css">.container {
  flex-wrap: nowrap;   /* 줄바꿈 없음 (기본값) — 넘쳐도 한 줄 */
  flex-wrap: wrap;     /* 넘치면 다음 줄로 */
}</code></pre>
<hr>
<h2 id="flex--아이템의-크기-비율">flex — 아이템의 크기 비율</h2>
<p>자식 아이템에 지정하는 속성이다. 남은 공간을 어떻게 나눌지 비율로 설정한다.</p>
<pre><code class="language-css">.item-a { flex: 1; }  /* 1 비율 */
.item-b { flex: 2; }  /* 2 비율 — item-a의 두 배 */
.item-c { flex: 1; }  /* 1 비율 */
/* 전체 4 비율 → a: 25%, b: 50%, c: 25% */</code></pre>
<hr>
<h2 id="align-self--개별-아이템-교차축-정렬">align-self — 개별 아이템 교차축 정렬</h2>
<p><code>align-items</code>는 모든 아이템에 적용되지만, 특정 아이템만 다르게 하고 싶을 때 쓴다.</p>
<pre><code class="language-css">.item-special {
  align-self: flex-end;
}</code></pre>
<hr>
<h2 id="자주-쓰는-flexbox-패턴">자주 쓰는 Flexbox 패턴</h2>
<pre><code class="language-css">/* 가로 네비게이션 */
nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* 카드 그리드 */
.card-list {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

/* 세로 가운데 정렬 */
.hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100vh;
}</code></pre>
<p><code>gap</code> 속성으로 아이템 사이 간격을 한 번에 설정할 수 있다.</p>
<hr>
<p>Flexbox는 1차원(가로 또는 세로) 레이아웃에 최적화되어 있다. 가로 정렬과 세로 정렬의 기준이 되는 주축과 교차축만 머릿속에 있으면, <code>justify-content</code>와 <code>align-items</code>가 자연스럽게 읽힌다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[position]]></title>
            <link>https://velog.io/@mskim_/position</link>
            <guid>https://velog.io/@mskim_/position</guid>
            <pubDate>Tue, 19 May 2026 08:01:41 GMT</pubDate>
            <description><![CDATA[<h1 id="position-속성">position 속성</h1>
<p>요소를 특정 위치에 고정하거나, 다른 요소 위에 겹치게 하거나, 스크롤해도 화면에 따라오게 하려면 <code>position</code> 속성이 필요하다. 처음에는 개념이 헷갈리지만 각 값의 기준점이 어디인지를 이해하면 풀린다.</p>
<hr>
<h2 id="position의-기준">position의 기준</h2>
<p><code>position</code> 속성은 요소를 어디에, 어떤 기준으로 배치할지 결정한다. <code>top</code>, <code>right</code>, <code>bottom</code>, <code>left</code>와 함께 쓰여 위치를 조정한다.</p>
<hr>
<h2 id="static-기본값">static (기본값)</h2>
<pre><code class="language-css">div {
  position: static;
}</code></pre>
<p>모든 요소의 기본값이다. 문서 흐름에 따라 순서대로 배치되고, <code>top</code>, <code>left</code> 등 위치 속성이 적용되지 않는다.</p>
<hr>
<h2 id="relative--자기-자신-기준">relative — 자기 자신 기준</h2>
<pre><code class="language-css">div {
  position: relative;
  top: 20px;
  left: 10px;
}</code></pre>
<p><strong>원래 있어야 할 자리를 기준</strong>으로 이동한다. 원래 자리는 여전히 공간을 차지한다. 주로 <code>absolute</code> 자식 요소의 기준점을 만들 때 많이 쓴다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/80366ffe-b0e3-4e11-b7ed-bdc5a831a4a3/image.png" alt=""></p>
<hr>
<h2 id="absolute--가장-가까운-positioned-조상-기준">absolute — 가장 가까운 positioned 조상 기준</h2>
<pre><code class="language-css">.parent {
  position: relative; /* 기준점 역할 */
}

.child {
  position: absolute;
  top: 10px;
  right: 10px;
}</code></pre>
<p><strong>가장 가까운 <code>position: relative</code> (또는 absolute/fixed) 조상을 기준</strong>으로 배치된다. 그런 조상이 없으면 <code>&lt;html&gt;</code>(뷰포트)이 기준이 된다.</p>
<p>문서 흐름에서 빠져나오기 때문에 원래 자리가 사라진다. 다른 요소들이 이 요소의 자리를 무시하고 채워진다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/12987371-4038-449c-94bc-01287d0a8bc7/image.png" alt=""></p>
<hr>
<h2 id="fixed--뷰포트-기준">fixed — 뷰포트 기준</h2>
<pre><code class="language-css">.navbar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
}</code></pre>
<p><strong>브라우저 뷰포트(화면)</strong>를 기준으로 배치된다. 스크롤해도 항상 같은 위치에 고정된다. 상단 고정 헤더, 하단 고정 버튼 등에 쓰인다.</p>
<p>문서 흐름에서 빠져나오기 때문에 fixed 요소 아래에 콘텐츠가 가려지지 않도록 다른 요소에 <code>padding-top</code>을 주는 경우가 많다.</p>
<hr>
<h2 id="sticky--스크롤에-따라-고정">sticky — 스크롤에 따라 고정</h2>
<pre><code class="language-css">.section-title {
  position: sticky;
  top: 0;
}</code></pre>
<p><code>relative</code>처럼 문서 흐름에 있다가, 스크롤 시 지정한 위치(<code>top: 0</code>)에 닿으면 <code>fixed</code>처럼 고정된다. 스크롤 기반 섹션 헤더에 자주 쓰인다.</p>
<hr>
<h2 id="z-index--요소의-쌓임-순서">z-index — 요소의 쌓임 순서</h2>
<p><code>position</code>이 <code>static</code>이 아닌 요소들은 <code>z-index</code>로 앞뒤 순서를 조절할 수 있다.</p>
<pre><code class="language-css">.modal {
  position: fixed;
  z-index: 1000;  /* 숫자가 클수록 앞에 표시 */
}

.overlay {
  position: fixed;
  z-index: 999;
}</code></pre>
<p><code>z-index</code>가 없으면 HTML에 늦게 나온 요소가 앞에 쌓인다.</p>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>값</th>
<th>기준</th>
<th>문서 흐름</th>
<th>스크롤</th>
</tr>
</thead>
<tbody><tr>
<td><code>static</code></td>
<td>—</td>
<td>유지</td>
<td>따라감</td>
</tr>
<tr>
<td><code>relative</code></td>
<td>자기 자신 원래 위치</td>
<td>유지 (공간 차지)</td>
<td>따라감</td>
</tr>
<tr>
<td><code>absolute</code></td>
<td>가장 가까운 positioned 조상</td>
<td>이탈</td>
<td>따라감</td>
</tr>
<tr>
<td><code>fixed</code></td>
<td>뷰포트</td>
<td>이탈</td>
<td>고정</td>
</tr>
<tr>
<td><code>sticky</code></td>
<td>부모 스크롤 영역</td>
<td>유지 → 고정</td>
<td>조건부 고정</td>
</tr>
</tbody></table>
<hr>
<p><code>absolute</code>를 쓸 때 요소가 엉뚱한 곳에 붙는다면 대부분 기준이 될 부모에 <code>position: relative</code>를 빠뜨린 경우다. absolute는 항상 &quot;기준 부모가 어디인가&quot;를 먼저 확인하는 게 디버깅의 출발점이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[display]]></title>
            <link>https://velog.io/@mskim_/display-%EC%86%8D%EC%84%B1</link>
            <guid>https://velog.io/@mskim_/display-%EC%86%8D%EC%84%B1</guid>
            <pubDate>Tue, 19 May 2026 07:43:58 GMT</pubDate>
            <description><![CDATA[<h1 id="display-속성">display 속성</h1>
<p>HTML 파트에서 블록 요소와 인라인 요소를 배웠다. CSS의 <code>display</code> 속성은 그 기본 동작 방식을 바꿀 수 있다. <code>&lt;span&gt;</code>을 블록처럼 쓰거나, <code>&lt;div&gt;</code>를 인라인처럼 배치하는 것도 가능하다.</p>
<hr>
<h2 id="display-block">display: block</h2>
<pre><code class="language-css">span {
  display: block;
}</code></pre>
<ul>
<li>가로 전체를 차지하고, 다음 요소는 새 줄로 밀린다</li>
<li><code>width</code>, <code>height</code>, 상하 <code>margin</code> 모두 적용된다</li>
<li>기본적으로 블록인 태그: <code>div</code>, <code>p</code>, <code>h1~h6</code>, <code>ul</code>, <code>section</code> 등</li>
</ul>
<hr>
<h2 id="display-inline">display: inline</h2>
<pre><code class="language-css">div {
  display: inline;
}</code></pre>
<ul>
<li>콘텐츠 너비만큼만 차지하고, 옆으로 나란히 배치된다</li>
<li><code>width</code>, <code>height</code> 지정이 <strong>무시</strong>된다</li>
<li>상하 <code>margin</code>이 적용되지 않는다</li>
<li>기본적으로 인라인인 태그: <code>span</code>, <code>a</code>, <code>strong</code>, <code>em</code> 등</li>
</ul>
<hr>
<h2 id="display-inline-block">display: inline-block</h2>
<p>inline과 block의 특성을 합쳐놓은 값이다.</p>
<pre><code class="language-css">.button {
  display: inline-block;
  width: 120px;
  height: 40px;
  padding: 8px 16px;
}</code></pre>
<ul>
<li>옆으로 나란히 배치된다 (inline처럼)</li>
<li><code>width</code>, <code>height</code>, <code>margin</code> 상하까지 모두 적용된다 (block처럼)</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mskim_/post/25851891-c8a0-4099-bd83-537096be4cf4/image.png" alt=""></p>
<hr>
<h2 id="display-none">display: none</h2>
<p>요소를 화면에서 완전히 제거한다. 공간도 차지하지 않는다.</p>
<pre><code class="language-css">.hidden {
  display: none;
}</code></pre>
<p><code>visibility: hidden</code>은 공간은 유지하되 보이지 않게 한다. 차이를 알아두면 좋다.</p>
<table>
<thead>
<tr>
<th>속성</th>
<th>화면 표시</th>
<th>공간 차지</th>
</tr>
</thead>
<tbody><tr>
<td><code>display: none</code></td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><code>visibility: hidden</code></td>
<td>X</td>
<td>O</td>
</tr>
</tbody></table>
<hr>
<h2 id="display-flex">display: flex</h2>
<p>Flexbox 레이아웃을 활성화한다. 자식 요소들을 가로 또는 세로로 유연하게 배치할 수 있다. 다음 챕터에서 자세히 다룬다.</p>
<pre><code class="language-css">.container {
  display: flex;
  justify-content: center;
  align-items: center;
}</code></pre>
<hr>
<h2 id="display-grid">display: grid</h2>
<p>Grid 레이아웃을 활성화한다. 행과 열을 정의해서 2차원 배치를 만들 수 있다.</p>
<pre><code class="language-css">.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
}</code></pre>
<hr>
<h2 id="정리">정리</h2>
<table>
<thead>
<tr>
<th>값</th>
<th>너비</th>
<th>height/width</th>
<th>상하 margin</th>
</tr>
</thead>
<tbody><tr>
<td><code>block</code></td>
<td>전체</td>
<td>적용 O</td>
<td>적용 O</td>
</tr>
<tr>
<td><code>inline</code></td>
<td>콘텐츠</td>
<td>적용 X</td>
<td>적용 X</td>
</tr>
<tr>
<td><code>inline-block</code></td>
<td>콘텐츠</td>
<td>적용 O</td>
<td>적용 O</td>
</tr>
<tr>
<td><code>none</code></td>
<td>—</td>
<td>—</td>
<td>—</td>
</tr>
</tbody></table>
<hr>
<p><code>display</code>는 CSS 레이아웃의 핵심 속성이다. 요소가 의도와 다르게 배치될 때 가장 먼저 확인해야 할 것이 <code>display</code> 값이다. 블록인지 인라인인지 파악하는 것이 레이아웃 문제 해결의 첫 단계다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[박스 모델]]></title>
            <link>https://velog.io/@mskim_/%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8</link>
            <guid>https://velog.io/@mskim_/%EB%B0%95%EC%8A%A4-%EB%AA%A8%EB%8D%B8</guid>
            <pubDate>Tue, 19 May 2026 07:39:41 GMT</pubDate>
            <description><![CDATA[<h1 id="박스-모델--margin-padding-border">박스 모델 — margin, padding, border</h1>
<p>CSS를 배우다가 &quot;왜 여기에 여백이 생기지?&quot;, &quot;왜 크기가 내가 지정한 것보다 크지?&quot;라는 경험이 한 번씩은 생긴다. 이 혼란의 대부분은 박스 모델을 모르기 때문이다.</p>
<hr>
<h2 id="박스-모델이란">박스 모델이란</h2>
<p>HTML의 모든 요소는 눈에 보이지 않는 <strong>박스</strong>로 이루어져 있다. 이 박스는 네 가지 영역으로 구성된다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/5f094714-73c8-46e8-990b-f9dffe4701cb/image.png" alt=""></p>
<ul>
<li><strong>content</strong> — 실제 내용이 들어가는 영역 (텍스트, 이미지 등)</li>
<li><strong>padding</strong> — content와 border 사이의 안쪽 여백</li>
<li><strong>border</strong> — 테두리</li>
<li><strong>margin</strong> — 요소 바깥쪽 여백, 다른 요소와의 간격</li>
</ul>
<hr>
<h2 id="padding--안쪽-여백">padding — 안쪽 여백</h2>
<pre><code class="language-css">div {
  padding: 20px;                /* 상하좌우 모두 20px */
  padding: 10px 20px;           /* 상하 10px, 좌우 20px */
  padding: 10px 20px 15px;      /* 상 10, 좌우 20, 하 15 */
  padding: 10px 20px 15px 5px;  /* 상 우 하 좌 (시계방향) */
}

/* 개별 지정 */
div {
  padding-top: 10px;
  padding-right: 20px;
  padding-bottom: 10px;
  padding-left: 20px;
}</code></pre>
<p>padding은 배경색의 영향을 받는다. <code>background-color</code>를 지정하면 padding 영역까지 색이 채워진다.</p>
<hr>
<h2 id="margin--바깥-여백">margin — 바깥 여백</h2>
<pre><code class="language-css">div {
  margin: 20px;
  margin: 10px auto;   /* 상하 10px, 좌우 auto → 가운데 정렬 */
  margin: 0;
}</code></pre>
<p><code>margin: 0 auto</code>는 블록 요소를 가운데 정렬하는 고전적인 방법이다. 단, 요소에 <code>width</code>가 지정되어 있어야 한다.</p>
<h3 id="마진-겹침-margin-collapsing">마진 겹침 (Margin Collapsing)</h3>
<p>인접한 블록 요소들의 마진이 합산되지 않고 더 큰 값 하나만 적용되는 현상이다.</p>
<pre><code class="language-css">.box1 { margin-bottom: 30px; }
.box2 { margin-top: 20px; }
/* 두 박스 사이 간격은 50px이 아니라 30px */</code></pre>
<p>Flexbox나 Grid를 쓰면 마진 겹침이 발생하지 않는다.</p>
<hr>
<h2 id="border--테두리">border — 테두리</h2>
<pre><code class="language-css">div {
  border: 1px solid #ccc;     /* 두께 스타일 색상 */
  border: 2px dashed red;
  border: 3px dotted blue;
}

/* 개별 지정 */
div {
  border-top: 2px solid black;
  border-right: none;
  border-radius: 8px;          /* 모서리 둥글게 */
  border-radius: 50%;          /* 원형 */
}</code></pre>
<p>border 스타일 종류: <code>solid</code>(실선), <code>dashed</code>(점선), <code>dotted</code>(점점선), <code>double</code>(이중선), <code>none</code></p>
<hr>
<h2 id="box-sizing--크기-계산-방식">box-sizing — 크기 계산 방식</h2>
<p><code>width: 200px</code>으로 지정한 요소가 실제로는 200px보다 크게 렌더링되는 경험이 있을 것이다. 기본값인 <code>content-box</code> 때문이다.</p>
<pre><code class="language-css">/* 기본값 — width가 content 영역만 포함 */
.box {
  box-sizing: content-box;
  width: 200px;
  padding: 20px;
  border: 5px solid black;
  /* 실제 렌더링 너비: 200 + 20*2 + 5*2 = 250px */
}

/* border-box — width가 padding, border까지 포함 */
.box {
  box-sizing: border-box;
  width: 200px;
  padding: 20px;
  border: 5px solid black;
  /* 실제 렌더링 너비: 200px (지정값 그대로) */
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/676bedf6-48a2-4278-b99c-21fc67d28729/image.png" alt=""></p>
<p>그래서 대부분의 프로젝트에서 이걸 전역으로 설정하고 시작한다.</p>
<pre><code class="language-css">* {
  box-sizing: border-box;
}</code></pre>
<hr>
<h2 id="width-height">width, height</h2>
<pre><code class="language-css">div {
  width: 300px;
  height: 200px;
  max-width: 600px;   /* 최대 너비 */
  min-height: 100px;  /* 최소 높이 */
  width: 100%;        /* 부모 너비의 100% */
}</code></pre>
<hr>
<p>박스 모델은 레이아웃의 기초다. padding과 margin의 차이, <code>box-sizing: border-box</code>의 동작 방식만 이해해도 크기와 여백 관련 문제의 절반은 해결된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[텍스트 스타일]]></title>
            <link>https://velog.io/@mskim_/Text-style</link>
            <guid>https://velog.io/@mskim_/Text-style</guid>
            <pubDate>Tue, 19 May 2026 07:35:40 GMT</pubDate>
            <description><![CDATA[<h1 id="텍스트-스타일">텍스트 스타일</h1>
<p>디자인의 대부분은 텍스트다. 글자 크기, 굵기, 간격, 정렬 — 이것들만 잘 잡아도 페이지가 훨씬 읽기 편해진다. CSS에서 텍스트를 다루는 주요 속성들을 정리한다.</p>
<hr>
<h2 id="font-family--글꼴">font-family — 글꼴</h2>
<pre><code class="language-css">body {
  font-family: &#39;Noto Sans KR&#39;, Arial, sans-serif;
}</code></pre>
<p>쉼표로 여러 폰트를 나열하면 앞에서부터 순서대로 적용 가능한 폰트를 찾는다. 마지막에는 항상 <code>serif</code>, <code>sans-serif</code>, <code>monospace</code> 같은 <strong>범용 폰트 패밀리</strong>를 넣어두는 것이 관례다. 앞의 폰트가 모두 없을 때 브라우저 기본 폰트를 대신 쓰게 된다.</p>
<p>웹 폰트를 사용하려면 <code>&lt;link&gt;</code>로 불러오거나 <code>@font-face</code>로 등록한다.</p>
<pre><code class="language-html">&lt;!-- Google Fonts 사용 예 --&gt;
&lt;link href=&quot;https://fonts.googleapis.com/css2?family=Noto+Sans+KR&amp;display=swap&quot; rel=&quot;stylesheet&quot;&gt;</code></pre>
<hr>
<h2 id="font-size--글자-크기">font-size — 글자 크기</h2>
<pre><code class="language-css">p {
  font-size: 16px;   /* 픽셀 — 고정값 */
  font-size: 1rem;   /* 루트 요소(html) 기준 배수 */
  font-size: 1.2em;  /* 부모 요소 기준 배수 */
  font-size: 120%;   /* 부모 기준 퍼센트 */
}</code></pre>
<ul>
<li><code>px</code> — 화면 픽셀 단위. 고정적이라 예측하기 쉽다</li>
<li><code>rem</code> — HTML 루트의 <code>font-size</code> 기준. 브라우저 기본값은 16px이라 <code>1rem = 16px</code></li>
<li><code>em</code> — 부모 요소의 <code>font-size</code> 기준. 중첩되면 계산이 복잡해질 수 있다</li>
</ul>
<p>반응형 디자인에서는 <code>rem</code>이 가장 다루기 편하다.</p>
<hr>
<h2 id="font-weight--굵기">font-weight — 굵기</h2>
<pre><code class="language-css">p {
  font-weight: normal;  /* 400 */
  font-weight: bold;    /* 700 */
  font-weight: 300;     /* 얇게 */
  font-weight: 900;     /* 아주 굵게 */
}</code></pre>
<p>숫자는 100 단위로 100~900까지 사용한다. 폰트가 해당 굵기를 지원해야 실제로 적용된다.</p>
<hr>
<h2 id="font-style--기울임">font-style — 기울임</h2>
<pre><code class="language-css">em {
  font-style: italic;   /* 기울임 */
  font-style: normal;   /* 기본 */
}</code></pre>
<hr>
<h2 id="line-height--줄-간격">line-height — 줄 간격</h2>
<pre><code class="language-css">p {
  line-height: 1.6;    /* 단위 없는 숫자 권장 — font-size의 1.6배 */
  line-height: 24px;
  line-height: 160%;
}</code></pre>
<p>단위 없는 숫자(<code>1.6</code>)가 권장된다. 자식 요소에 상속될 때 부모의 픽셀값이 아닌 배수 자체가 상속되기 때문이다. 본문 텍스트는 <code>1.5~1.8</code> 정도가 읽기 편하다.</p>
<hr>
<h2 id="letter-spacing-word-spacing--자간-단어-간격">letter-spacing, word-spacing — 자간, 단어 간격</h2>
<pre><code class="language-css">h1 {
  letter-spacing: 0.05em;  /* 자간 */
  word-spacing: 0.2em;     /* 단어 간격 */
}</code></pre>
<hr>
<h2 id="text-align--정렬">text-align — 정렬</h2>
<pre><code class="language-css">p {
  text-align: left;     /* 왼쪽 (기본) */
  text-align: right;    /* 오른쪽 */
  text-align: center;   /* 가운데 */
  text-align: justify;  /* 양쪽 맞춤 */
}</code></pre>
<hr>
<h2 id="text-decoration--장식선">text-decoration — 장식선</h2>
<pre><code class="language-css">a {
  text-decoration: none;          /* 밑줄 제거 */
  text-decoration: underline;     /* 밑줄 */
  text-decoration: line-through;  /* 취소선 */
  text-decoration: overline;      /* 윗줄 */
}</code></pre>
<p>링크의 기본 밑줄을 없앨 때 <code>text-decoration: none</code>을 자주 쓴다.</p>
<hr>
<h2 id="text-transform--대소문자-변환">text-transform — 대소문자 변환</h2>
<pre><code class="language-css">h1 {
  text-transform: uppercase;   /* 전부 대문자 */
  text-transform: lowercase;   /* 전부 소문자 */
  text-transform: capitalize;  /* 각 단어 첫 글자 대문자 */
}</code></pre>
<hr>
<h2 id="text-overflow--넘치는-텍스트-처리">text-overflow — 넘치는 텍스트 처리</h2>
<p>긴 텍스트가 지정된 너비를 넘어갈 때 처리 방법을 지정한다. 세 가지 속성을 함께 써야 동작한다.</p>
<pre><code class="language-css">.card-title {
  white-space: nowrap;       /* 줄바꿈 금지 */
  overflow: hidden;          /* 넘치는 부분 숨김 */
  text-overflow: ellipsis;   /* 말줄임표(...) 표시 */
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/72f9472b-6fa9-40be-8252-97d4d206c453/image.png" alt=""></p>
<hr>
<h2 id="자주-쓰는-텍스트-스타일-조합">자주 쓰는 텍스트 스타일 조합</h2>
<pre><code class="language-css">body {
  font-family: &#39;Noto Sans KR&#39;, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: #333;
}

h1 {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.02em;
}

a {
  color: royalblue;
  text-decoration: none;
}</code></pre>
<hr>
<p>텍스트 스타일은 하나하나보다 조합이 중요하다. <code>font-size</code>, <code>line-height</code>, <code>color</code>를 잡는 것만으로 페이지의 가독성이 크게 달라진다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[색상과 배경]]></title>
            <link>https://velog.io/@mskim_/%EC%83%89%EC%83%81%EA%B3%BC-%EB%B0%B0%EA%B2%BD</link>
            <guid>https://velog.io/@mskim_/%EC%83%89%EC%83%81%EA%B3%BC-%EB%B0%B0%EA%B2%BD</guid>
            <pubDate>Tue, 19 May 2026 07:32:29 GMT</pubDate>
            <description><![CDATA[<h1 id="색상과-배경">색상과 배경</h1>
<p>웹 페이지의 분위기를 결정짓는 가장 빠른 요소가 색이다. CSS에서 색상을 다루는 방법과 배경을 설정하는 속성들을 정리한다.</p>
<hr>
<h2 id="색상-표현-방식">색상 표현 방식</h2>
<p>CSS에서 색을 지정하는 방법은 여러 가지다.</p>
<h3 id="키워드">키워드</h3>
<pre><code class="language-css">color: red;
color: blue;
color: black;
color: white;
color: transparent; /* 투명 */</code></pre>
<p>기본 색상 이름 외에도 <code>tomato</code>, <code>cornflowerblue</code>, <code>salmon</code> 같은 이름도 지원한다.</p>
<h3 id="hex-16진수">HEX (16진수)</h3>
<pre><code class="language-css">color: #ff0000;  /* 빨강 */
color: #00ff00;  /* 초록 */
color: #0000ff;  /* 파랑 */
color: #333333;  /* 진한 회색 */
color: #fff;     /* 흰색 (축약형) */</code></pre>
<p><code>#RRGGBB</code> 형식으로 각각 00~ff 범위다. 두 자리가 같으면 한 자리로 줄일 수 있다 (<code>#333333</code> → <code>#333</code>).</p>
<h3 id="rgb">RGB</h3>
<pre><code class="language-css">color: rgb(255, 0, 0);       /* 빨강 */
color: rgb(0, 128, 255);     /* 파란 계열 */</code></pre>
<p>각 값은 0~255 범위다.</p>
<h3 id="rgba--투명도-포함">RGBA — 투명도 포함</h3>
<pre><code class="language-css">color: rgba(0, 0, 0, 0.5);   /* 50% 투명한 검정 */
color: rgba(255, 255, 255, 0.8); /* 80% 불투명한 흰색 */</code></pre>
<p>네 번째 값(alpha)은 0(완전 투명) ~ 1(완전 불투명) 범위다.</p>
<h3 id="hsl">HSL</h3>
<pre><code class="language-css">color: hsl(0, 100%, 50%);    /* 빨강 */
color: hsl(240, 100%, 50%);  /* 파랑 */
color: hsl(120, 60%, 40%);   /* 초록 계열 */</code></pre>
<p>색조(Hue, 0~360°), 채도(Saturation, %), 명도(Lightness, %)로 지정한다. 색상을 감각적으로 조정하기 편하다.</p>
<hr>
<h2 id="color--글자색">color — 글자색</h2>
<pre><code class="language-css">p {
  color: #333;
}

a {
  color: royalblue;
}</code></pre>
<hr>
<h2 id="background--배경">background — 배경</h2>
<h3 id="background-color">background-color</h3>
<pre><code class="language-css">div {
  background-color: #f0f4ff;
}

body {
  background-color: rgba(0, 0, 0, 0.05);
}</code></pre>
<h3 id="background-image">background-image</h3>
<pre><code class="language-css">div {
  background-image: url(&#39;background.jpg&#39;);
}</code></pre>
<h3 id="background-repeat">background-repeat</h3>
<p>이미지가 반복되는 방식을 지정한다.</p>
<pre><code class="language-css">div {
  background-repeat: no-repeat;  /* 반복 없음 */
  background-repeat: repeat-x;   /* 가로만 반복 */
  background-repeat: repeat-y;   /* 세로만 반복 */
  background-repeat: repeat;     /* 기본값, 전방향 반복 */
}</code></pre>
<h3 id="background-size">background-size</h3>
<pre><code class="language-css">div {
  background-size: cover;    /* 요소를 꽉 채움, 잘릴 수 있음 */
  background-size: contain;  /* 요소 안에 전부 보이게 */
  background-size: 400px 300px;  /* 직접 지정 */
  background-size: 100% auto;
}</code></pre>
<h3 id="background-position">background-position</h3>
<pre><code class="language-css">div {
  background-position: center;
  background-position: top right;
  background-position: 50% 50%;
}</code></pre>
<h3 id="축약형-background">축약형 background</h3>
<pre><code class="language-css">div {
  background: #f0f4ff url(&#39;bg.jpg&#39;) no-repeat center / cover;
}</code></pre>
<p>순서: <code>색상 이미지경로 반복방식 위치 / 크기</code></p>
<hr>
<h2 id="그라디언트">그라디언트</h2>
<p>CSS만으로 색상이 부드럽게 이어지는 효과를 만들 수 있다.</p>
<pre><code class="language-css">/* 선형 그라디언트 */
div {
  background: linear-gradient(to right, #ff6b6b, #ffa500);
}

/* 각도로 방향 지정 */
div {
  background: linear-gradient(135deg, #667eea, #764ba2);
}

/* 원형 그라디언트 */
div {
  background: radial-gradient(circle, #fff, #ccc);
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/9b20ff95-ad9e-451e-a2ea-ddc8e0efb3a6/image.png" alt=""></p>
<hr>
<p>색상은 어느 표기법을 써도 결과는 같다. 다만 투명도가 필요하면 <code>rgba</code>, 색을 감각적으로 조절하고 싶으면 <code>hsl</code>, 디자이너가 건네준 값이라면 보통 <code>hex</code>다. 상황에 맞는 표기법을 자연스럽게 고르게 되면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CSS(Cascading Style Sheets)]]></title>
            <link>https://velog.io/@mskim_/CSSCascading-Style-Sheets</link>
            <guid>https://velog.io/@mskim_/CSSCascading-Style-Sheets</guid>
            <pubDate>Tue, 19 May 2026 07:28:54 GMT</pubDate>
            <description><![CDATA[<h1 id="css란--선택자와-기본-문법">CSS란 — 선택자와 기본 문법</h1>
<p>HTML만으로 만든 페이지는 흰 배경에 검은 글씨가 전부다. 구조는 있지만 디자인이 없다. CSS가 없던 시절 웹이 딱 그랬다. CSS는 그 페이지에 색, 크기, 간격, 배치를 입히는 언어다.</p>
<hr>
<h2 id="css란">CSS란</h2>
<p>CSS(Cascading Style Sheets)는 HTML 요소가 화면에 어떻게 보일지를 정의하는 스타일 언어다. HTML이 &quot;무엇을&quot;이라면 CSS는 &quot;어떻게 보이게 할지&quot;를 담당한다.</p>
<hr>
<h2 id="css-작성-방법">CSS 작성 방법</h2>
<h3 id="외부-스타일시트-권장">외부 스타일시트 (권장)</h3>
<p>별도의 <code>.css</code> 파일을 만들고 HTML에서 불러온다.</p>
<pre><code class="language-html">&lt;!-- HTML의 head 안에 --&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&gt;</code></pre>
<pre><code class="language-css">/* style.css */
h1 {
  color: blue;
  font-size: 32px;
}</code></pre>
<h3 id="내부-스타일">내부 스타일</h3>
<p>HTML 파일 내 <code>&lt;style&gt;</code> 태그 안에 작성한다.</p>
<pre><code class="language-html">&lt;head&gt;
  &lt;style&gt;
    h1 { color: blue; }
  &lt;/style&gt;
&lt;/head&gt;</code></pre>
<h3 id="인라인-스타일">인라인 스타일</h3>
<p>태그에 직접 <code>style</code> 속성으로 작성한다. 특정 요소에만 일시적으로 적용할 때 쓰지만, 유지보수가 어려워 자주 쓰지 않는 게 좋다.</p>
<pre><code class="language-html">&lt;h1 style=&quot;color: blue; font-size: 32px;&quot;&gt;제목&lt;/h1&gt;</code></pre>
<hr>
<h2 id="css-기본-문법">CSS 기본 문법</h2>
<pre><code class="language-css">선택자 {
  속성: 값;
  속성: 값;
}</code></pre>
<pre><code class="language-css">p {
  color: #333333;
  font-size: 16px;
  line-height: 1.6;
}</code></pre>
<ul>
<li><strong>선택자(Selector)</strong> — 스타일을 적용할 HTML 요소를 지정</li>
<li><strong>속성(Property)</strong> — 어떤 스타일을 바꿀지</li>
<li><strong>값(Value)</strong> — 속성에 설정할 내용</li>
<li>각 선언은 세미콜론(<code>;</code>)으로 끝냄</li>
</ul>
<hr>
<h2 id="선택자-종류">선택자 종류</h2>
<h3 id="태그-선택자">태그 선택자</h3>
<pre><code class="language-css">/* 모든 p 태그에 적용 */
p {
  color: gray;
}</code></pre>
<h3 id="클래스-선택자">클래스 선택자</h3>
<p><code>.클래스명</code> 형식으로 쓴다. 여러 요소에 같은 클래스를 붙여 공통 스타일을 줄 수 있다.</p>
<pre><code class="language-html">&lt;p class=&quot;highlight&quot;&gt;강조된 문단&lt;/p&gt;
&lt;span class=&quot;highlight&quot;&gt;강조된 텍스트&lt;/span&gt;</code></pre>
<pre><code class="language-css">.highlight {
  background-color: yellow;
  font-weight: bold;
}</code></pre>
<h3 id="id-선택자">ID 선택자</h3>
<p><code>#아이디명</code> 형식이다. 한 페이지에 하나의 요소에만 써야 한다.</p>
<pre><code class="language-html">&lt;h1 id=&quot;main-title&quot;&gt;메인 제목&lt;/h1&gt;</code></pre>
<pre><code class="language-css">#main-title {
  font-size: 40px;
  color: navy;
}</code></pre>
<h3 id="전체-선택자">전체 선택자</h3>
<pre><code class="language-css">/* 모든 요소에 적용 */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}</code></pre>
<h3 id="그룹-선택자">그룹 선택자</h3>
<p>여러 선택자를 쉼표로 묶어 같은 스타일을 한 번에 적용한다.</p>
<pre><code class="language-css">h1, h2, h3 {
  font-family: sans-serif;
  color: #222;
}</code></pre>
<h3 id="자손-선택자">자손 선택자</h3>
<p>공백으로 구분한다. 특정 요소 안에 있는 요소를 선택한다.</p>
<pre><code class="language-css">/* nav 안에 있는 모든 a 태그 */
nav a {
  text-decoration: none;
  color: white;
}</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/752ed7fe-ea42-4452-9299-04bc56541b9f/image.png" alt=""></p>
<hr>
<h2 id="우선순위-specificity">우선순위 (Specificity)</h2>
<p>같은 요소에 여러 스타일이 겹치면 우선순위가 높은 것이 적용된다.</p>
<pre><code>!important &gt; 인라인 스타일 &gt; ID 선택자 &gt; 클래스 선택자 &gt; 태그 선택자</code></pre><pre><code class="language-css">p { color: black; }          /* 우선순위 낮음 */
.text { color: blue; }       /* 중간 */
#intro { color: red; }       /* 높음 */</code></pre>
<p><code>!important</code>는 모든 우선순위를 무시하지만, 남발하면 스타일이 뒤엉켜 유지보수가 어려워진다. 꼭 필요한 경우에만 쓰는 것이 좋다.</p>
<hr>
<p>CSS는 선택자로 대상을 고르고, 속성과 값으로 스타일을 지정한다. 이 구조를 이해하면 어떤 CSS 코드를 봐도 &quot;누구에게, 어떤 스타일을 적용하는가&quot;를 읽어낼 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Block / Inline]]></title>
            <link>https://velog.io/@mskim_/Block-Inline</link>
            <guid>https://velog.io/@mskim_/Block-Inline</guid>
            <pubDate>Tue, 19 May 2026 07:26:27 GMT</pubDate>
            <description><![CDATA[<h1 id="블록-요소와-인라인-요소">블록 요소와 인라인 요소</h1>
<p>HTML 태그를 쓰다 보면 어떤 태그는 항상 새 줄에서 시작하고, 어떤 태그는 글자 옆에 붙어서 따라온다. 이 차이는 CSS를 배우기 전에 꼭 짚고 가야 한다. 레이아웃을 이해하는 기초가 되기 때문이다.</p>
<hr>
<h2 id="블록-요소-block-element">블록 요소 (Block Element)</h2>
<p><strong>가로 전체를 차지하고, 앞뒤로 줄바꿈이 생기는 요소</strong>다. 항상 새 줄에서 시작한다.</p>
<pre><code class="language-html">&lt;div&gt;첫 번째 div&lt;/div&gt;
&lt;div&gt;두 번째 div&lt;/div&gt;
&lt;p&gt;문단입니다&lt;/p&gt;</code></pre>
<p>위 코드는 세 줄로 렌더링된다. <code>&lt;div&gt;</code>, <code>&lt;p&gt;</code>, <code>&lt;h1&gt;~&lt;h6&gt;</code>, <code>&lt;ul&gt;</code>, <code>&lt;ol&gt;</code>, <code>&lt;table&gt;</code>, <code>&lt;form&gt;</code>, <code>&lt;header&gt;</code>, <code>&lt;main&gt;</code>, <code>&lt;section&gt;</code> 등이 블록 요소다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/8a02ddba-fa62-4b23-a57a-791e3a98717f/image.png" alt=""></p>
<hr>
<h2 id="인라인-요소-inline-element">인라인 요소 (Inline Element)</h2>
<p><strong>내용만큼만 너비를 차지하고, 줄바꿈 없이 옆으로 나란히 배치되는 요소</strong>다.</p>
<pre><code class="language-html">&lt;span&gt;첫 번째&lt;/span&gt;
&lt;span&gt;두 번째&lt;/span&gt;
&lt;span&gt;세 번째&lt;/span&gt;</code></pre>
<p>위 코드는 한 줄에 이어서 표시된다. <code>&lt;span&gt;</code>, <code>&lt;a&gt;</code>, <code>&lt;strong&gt;</code>, <code>&lt;em&gt;</code>, <code>&lt;img&gt;</code>, <code>&lt;input&gt;</code>, <code>&lt;label&gt;</code> 등이 인라인 요소다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/f7afd3cd-56e5-4b04-a245-19380651cefa/image.png" alt=""></p>
<hr>
<h2 id="두-요소의-차이-비교">두 요소의 차이 비교</h2>
<pre><code class="language-html">&lt;!-- 블록 요소 — 각자 새 줄 차지 --&gt;
&lt;div&gt;블록 1&lt;/div&gt;
&lt;div&gt;블록 2&lt;/div&gt;
&lt;div&gt;블록 3&lt;/div&gt;

&lt;!-- 인라인 요소 — 한 줄에 나란히 --&gt;
&lt;span&gt;인라인 1&lt;/span&gt;
&lt;span&gt;인라인 2&lt;/span&gt;
&lt;span&gt;인라인 3&lt;/span&gt;</code></pre>
<table>
<thead>
<tr>
<th>구분</th>
<th>블록 요소</th>
<th>인라인 요소</th>
</tr>
</thead>
<tbody><tr>
<td>너비</td>
<td>부모의 전체 너비</td>
<td>콘텐츠만큼</td>
</tr>
<tr>
<td>줄바꿈</td>
<td>앞뒤 자동 줄바꿈</td>
<td>없음</td>
</tr>
<tr>
<td>width/height</td>
<td>CSS로 지정 가능</td>
<td>지정 불가 (무시됨)</td>
</tr>
<tr>
<td>margin/padding</td>
<td>상하좌우 모두 적용</td>
<td>좌우만 적용</td>
</tr>
<tr>
<td>대표 태그</td>
<td>div, p, h1~h6, ul</td>
<td>span, a, strong, em</td>
</tr>
</tbody></table>
<hr>
<h2 id="블록-안에-인라인-인라인-안에-블록">블록 안에 인라인, 인라인 안에 블록</h2>
<p>블록 요소 안에 인라인 요소를 넣는 것은 자연스럽다.</p>
<pre><code class="language-html">&lt;p&gt;이 문단에서 &lt;strong&gt;중요한 부분&lt;/strong&gt;을 강조합니다.&lt;/p&gt;</code></pre>
<p>반대로 인라인 요소 안에 블록 요소를 넣는 것은 HTML 규칙에 어긋난다.</p>
<pre><code class="language-html">&lt;!-- 잘못된 구조 --&gt;
&lt;span&gt;
  &lt;div&gt;블록을 인라인 안에 넣으면 안 됨&lt;/div&gt;
&lt;/span&gt;

&lt;!-- 올바른 구조 --&gt;
&lt;div&gt;
  &lt;span&gt;인라인을 블록 안에&lt;/span&gt;
&lt;/div&gt;</code></pre>
<p>단, <code>&lt;a&gt;</code> 태그는 예외적으로 블록 요소를 감쌀 수 있다 (HTML5 기준).</p>
<hr>
<h2 id="css로-바꾸기">CSS로 바꾸기</h2>
<p>블록/인라인 특성은 CSS의 <code>display</code> 속성으로 바꿀 수 있다. 이 부분은 CSS 파트에서 자세히 다루는데, 미리 알아두면 좋다.</p>
<pre><code class="language-css">span { display: block; }   /* 인라인 → 블록 */
div  { display: inline; }  /* 블록 → 인라인 */</code></pre>
<p>실제로는 <code>display: inline-block</code>이나 <code>display: flex</code>를 더 많이 쓰지만, 개념의 출발점은 블록/인라인의 구분이다.</p>
<hr>
<p>태그를 고를 때 &quot;이 내용이 한 줄 전체를 차지해야 하나, 아니면 텍스트 흐름 안에 녹아들어야 하나&quot;를 생각해보면 블록과 인라인 중 어느 쪽이 맞는지 자연스럽게 판단된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[시맨틱 태그(Semantic tag)]]></title>
            <link>https://velog.io/@mskim_/%EC%8B%9C%EB%A7%A8%ED%8B%B1-%ED%83%9C%EA%B7%B8Semantic-tag</link>
            <guid>https://velog.io/@mskim_/%EC%8B%9C%EB%A7%A8%ED%8B%B1-%ED%83%9C%EA%B7%B8Semantic-tag</guid>
            <pubDate>Tue, 19 May 2026 07:16:29 GMT</pubDate>
            <description><![CDATA[<h1 id="시맨틱-태그">시맨틱 태그</h1>
<p><code>&lt;div&gt;</code>로만 구성된 페이지와 <code>&lt;header&gt;</code>, <code>&lt;nav&gt;</code>, <code>&lt;main&gt;</code>, <code>&lt;footer&gt;</code>로 구성된 페이지는 브라우저에서 똑같이 보일 수 있다. 하지만 코드의 의미는 완전히 다르다.</p>
<hr>
<h2 id="시맨틱-태그란">시맨틱 태그란</h2>
<p><strong>태그 이름 자체가 콘텐츠의 의미를 담고 있는 태그</strong>다. <code>&lt;div&gt;</code>나 <code>&lt;span&gt;</code>은 아무 의미 없는 컨테이너지만, <code>&lt;header&gt;</code>는 &quot;이곳이 헤더다&quot;, <code>&lt;nav&gt;</code>는 &quot;이곳이 내비게이션이다&quot;라는 의미를 명시적으로 전달한다.</p>
<p>검색 엔진은 시맨틱 태그를 보고 페이지 구조를 파악한다. 스크린 리더는 <code>&lt;nav&gt;</code>를 만나면 &quot;탐색 메뉴&quot;라고 사용자에게 알려준다. 개발자는 코드를 보고 어느 부분이 어떤 역할인지 쉽게 파악할 수 있다.</p>
<hr>
<h2 id="주요-시맨틱-태그">주요 시맨틱 태그</h2>
<p><img src="https://velog.velcdn.com/images/mskim_/post/320c8fed-d65b-4804-b063-bc25af134a93/image.png" alt=""></p>
<h3 id="header">header</h3>
<p>페이지 또는 섹션의 머리말 영역이다. 로고, 사이트 제목, 상단 내비게이션이 보통 여기에 들어간다.</p>
<pre><code class="language-html">&lt;header&gt;
  &lt;h1&gt;My Blog&lt;/h1&gt;
  &lt;nav&gt;...&lt;/nav&gt;
&lt;/header&gt;</code></pre>
<h3 id="nav">nav</h3>
<p>사이트 내 주요 탐색 링크 모음이다. 메뉴, 목차, 페이지네이션이 여기에 해당한다.</p>
<pre><code class="language-html">&lt;nav&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;/&quot;&gt;홈&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/about&quot;&gt;소개&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;/posts&quot;&gt;글목록&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/nav&gt;</code></pre>
<h3 id="main">main</h3>
<p>페이지의 핵심 콘텐츠 영역이다. 한 페이지에 하나만 써야 하고, <code>&lt;header&gt;</code>, <code>&lt;footer&gt;</code>, <code>&lt;nav&gt;</code> 안에 들어가지 않는다.</p>
<pre><code class="language-html">&lt;main&gt;
  &lt;h2&gt;오늘의 글&lt;/h2&gt;
  &lt;p&gt;본문 내용...&lt;/p&gt;
&lt;/main&gt;</code></pre>
<h3 id="article">article</h3>
<p>독립적으로 배포하거나 재사용할 수 있는 콘텐츠 단위다. 블로그 포스트, 뉴스 기사, 댓글 하나하나가 <code>&lt;article&gt;</code>에 해당한다.</p>
<pre><code class="language-html">&lt;article&gt;
  &lt;h2&gt;Observer 패턴이란&lt;/h2&gt;
  &lt;p&gt;게시일: 2024-05-01&lt;/p&gt;
  &lt;p&gt;본문 내용...&lt;/p&gt;
&lt;/article&gt;</code></pre>
<h3 id="section">section</h3>
<p>주제별로 콘텐츠를 묶는 구역이다. <code>&lt;article&gt;</code>과 달리 독립적이지 않아도 된다. 보통 제목(<code>&lt;h2&gt;</code> 등)을 포함한다.</p>
<pre><code class="language-html">&lt;section&gt;
  &lt;h2&gt;생성 패턴&lt;/h2&gt;
  &lt;p&gt;Singleton, Factory Method, Builder...&lt;/p&gt;
&lt;/section&gt;</code></pre>
<h3 id="aside">aside</h3>
<p>본문과 간접적으로 관련된 보조 콘텐츠다. 사이드바, 광고, 관련 글 목록 등이 해당한다.</p>
<pre><code class="language-html">&lt;aside&gt;
  &lt;h3&gt;관련 글&lt;/h3&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Singleton 패턴&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;#&quot;&gt;Factory Method 패턴&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/aside&gt;</code></pre>
<h3 id="footer">footer</h3>
<p>페이지 또는 섹션의 바닥글이다. 저작권 정보, 연락처, 사이트맵 링크 등이 들어간다.</p>
<pre><code class="language-html">&lt;footer&gt;
  &lt;p&gt;© 2024 My Blog. All rights reserved.&lt;/p&gt;
  &lt;a href=&quot;/privacy&quot;&gt;개인정보처리방침&lt;/a&gt;
&lt;/footer&gt;</code></pre>
<hr>
<h2 id="article-vs-section">article vs section</h2>
<p>헷갈리기 쉬운 두 태그다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>article</th>
<th>section</th>
</tr>
</thead>
<tbody><tr>
<td>독립성</td>
<td>단독으로 떼어내도 의미 있음</td>
<td>페이지 맥락이 필요</td>
</tr>
<tr>
<td>예시</td>
<td>블로그 포스트, 댓글</td>
<td>탭 패널, 장(章) 구분</td>
</tr>
<tr>
<td>제목</td>
<td>있어도 없어도 됨</td>
<td>보통 제목 포함</td>
</tr>
</tbody></table>
<p>구분이 애매하면 &quot;이 내용을 RSS 피드로 뽑아냈을 때 의미가 있는가?&quot;를 기준으로 삼으면 된다. 의미 있으면 <code>&lt;article&gt;</code>, 아니면 <code>&lt;section&gt;</code>.</p>
<hr>
<h2 id="div와-span은-언제-쓰는가">div와 span은 언제 쓰는가</h2>
<p>시맨틱 태그가 맞는 것이 없을 때 <code>&lt;div&gt;</code>(블록)와 <code>&lt;span&gt;</code>(인라인)을 쓴다. CSS 스타일링을 위한 묶음 용도로는 여전히 자주 쓰인다.</p>
<pre><code class="language-html">&lt;div class=&quot;card&quot;&gt;
  &lt;span class=&quot;badge&quot;&gt;NEW&lt;/span&gt;
  &lt;p&gt;새로 나온 상품입니다.&lt;/p&gt;
&lt;/div&gt;</code></pre>
<hr>
<p>시맨틱 태그는 &quot;보이기 위한&quot; 태그가 아니라 &quot;의미를 전달하기 위한&quot; 태그다. 처음엔 <code>&lt;div&gt;</code>로 다 만들어도 동작하지만, 구조에 맞는 태그를 쓰는 습관이 결국 검색 최적화와 유지보수 모두에서 차이를 만든다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[폼(form)]]></title>
            <link>https://velog.io/@mskim_/%ED%8F%BCform</link>
            <guid>https://velog.io/@mskim_/%ED%8F%BCform</guid>
            <pubDate>Tue, 19 May 2026 07:14:24 GMT</pubDate>
            <description><![CDATA[<h1 id="폼--form-input-button">폼 — form, input, button</h1>
<p>로그인 화면, 회원가입, 검색창, 댓글 입력 — 사용자가 무언가를 입력하고 서버로 전송하는 곳이면 어디든 폼이 있다. HTML에서 사용자 입력을 받는 모든 요소가 폼과 관련된 태그들이다.</p>
<hr>
<h2 id="form-태그">form 태그</h2>
<p><code>&lt;form&gt;</code>은 입력 요소들을 감싸고, 데이터를 어디로 어떻게 전송할지 정의한다.</p>
<pre><code class="language-html">&lt;form action=&quot;/login&quot; method=&quot;post&quot;&gt;
  &lt;!-- 입력 요소들 --&gt;
&lt;/form&gt;</code></pre>
<ul>
<li><code>action</code> — 데이터를 전송할 서버 URL</li>
<li><code>method</code> — 전송 방식<ul>
<li><code>get</code> — URL에 데이터가 붙어서 전송 (검색, 조회)</li>
<li><code>post</code> — 요청 본문에 데이터가 담겨 전송 (로그인, 회원가입)</li>
</ul>
</li>
</ul>
<hr>
<h2 id="input-태그">input 태그</h2>
<p>가장 다양하게 쓰이는 입력 요소다. <code>type</code> 속성으로 종류를 지정한다.</p>
<pre><code class="language-html">&lt;!-- 텍스트 입력 --&gt;
&lt;input type=&quot;text&quot; placeholder=&quot;이름을 입력하세요&quot;&gt;

&lt;!-- 비밀번호 (입력 내용이 가려짐) --&gt;
&lt;input type=&quot;password&quot; placeholder=&quot;비밀번호&quot;&gt;

&lt;!-- 이메일 (형식 자동 검증) --&gt;
&lt;input type=&quot;email&quot; placeholder=&quot;이메일&quot;&gt;

&lt;!-- 숫자 --&gt;
&lt;input type=&quot;number&quot; min=&quot;0&quot; max=&quot;100&quot;&gt;

&lt;!-- 날짜 선택 --&gt;
&lt;input type=&quot;date&quot;&gt;

&lt;!-- 파일 업로드 --&gt;
&lt;input type=&quot;file&quot;&gt;

&lt;!-- 체크박스 --&gt;
&lt;input type=&quot;checkbox&quot;&gt; 동의합니다

&lt;!-- 라디오 버튼 (같은 name으로 묶어야 하나만 선택됨) --&gt;
&lt;input type=&quot;radio&quot; name=&quot;gender&quot; value=&quot;male&quot;&gt; 남성
&lt;input type=&quot;radio&quot; name=&quot;gender&quot; value=&quot;female&quot;&gt; 여성

&lt;!-- 숨겨진 값 (화면에 안 보임) --&gt;
&lt;input type=&quot;hidden&quot; name=&quot;userId&quot; value=&quot;123&quot;&gt;

&lt;!-- 범위 슬라이더 --&gt;
&lt;input type=&quot;range&quot; min=&quot;0&quot; max=&quot;100&quot; value=&quot;50&quot;&gt;

&lt;!-- 색상 선택 --&gt;
&lt;input type=&quot;color&quot;&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/c897f412-645d-4373-9cb0-0906dd5b3420/image.png" alt=""></p>
<hr>
<h2 id="label-태그">label 태그</h2>
<p><code>&lt;label&gt;</code>은 입력 요소에 설명을 붙인다. <code>&lt;label&gt;</code>을 클릭하면 연결된 입력 요소가 활성화된다.</p>
<pre><code class="language-html">&lt;!-- for 속성과 id로 연결 --&gt;
&lt;label for=&quot;username&quot;&gt;아이디&lt;/label&gt;
&lt;input type=&quot;text&quot; id=&quot;username&quot;&gt;

&lt;!-- input을 label 안에 넣는 방법 --&gt;
&lt;label&gt;
  비밀번호
  &lt;input type=&quot;password&quot;&gt;
&lt;/label&gt;</code></pre>
<p><code>&lt;label&gt;</code> 없이 placeholder만 쓰면 접근성이 떨어진다. 스크린 리더가 읽을 수 없기 때문이다.</p>
<hr>
<h2 id="textarea--여러-줄-입력">textarea — 여러 줄 입력</h2>
<pre><code class="language-html">&lt;textarea rows=&quot;5&quot; cols=&quot;40&quot; placeholder=&quot;내용을 입력하세요&quot;&gt;&lt;/textarea&gt;</code></pre>
<p><code>&lt;input&gt;</code>은 한 줄, <code>&lt;textarea&gt;</code>는 여러 줄 입력에 쓴다.</p>
<hr>
<h2 id="select--드롭다운">select — 드롭다운</h2>
<pre><code class="language-html">&lt;select name=&quot;city&quot;&gt;
  &lt;option value=&quot;&quot;&gt;도시를 선택하세요&lt;/option&gt;
  &lt;option value=&quot;seoul&quot;&gt;서울&lt;/option&gt;
  &lt;option value=&quot;busan&quot;&gt;부산&lt;/option&gt;
  &lt;option value=&quot;daegu&quot;&gt;대구&lt;/option&gt;
&lt;/select&gt;</code></pre>
<p><code>selected</code> 속성을 붙이면 기본 선택값이 된다.</p>
<pre><code class="language-html">&lt;option value=&quot;seoul&quot; selected&gt;서울&lt;/option&gt;</code></pre>
<hr>
<h2 id="button-태그">button 태그</h2>
<pre><code class="language-html">&lt;!-- 폼 제출 --&gt;
&lt;button type=&quot;submit&quot;&gt;로그인&lt;/button&gt;

&lt;!-- 폼 초기화 --&gt;
&lt;button type=&quot;reset&quot;&gt;다시 입력&lt;/button&gt;

&lt;!-- 폼 제출 없이 자바스크립트 실행용 --&gt;
&lt;button type=&quot;button&quot;&gt;클릭&lt;/button&gt;</code></pre>
<p><code>&lt;input type=&quot;submit&quot;&gt;</code>과 <code>&lt;button type=&quot;submit&quot;&gt;</code>은 같은 역할을 한다. <code>&lt;button&gt;</code>이 내부에 HTML을 넣을 수 있어 더 유연하다.</p>
<hr>
<h2 id="폼-전체-예시">폼 전체 예시</h2>
<pre><code class="language-html">&lt;form action=&quot;/signup&quot; method=&quot;post&quot;&gt;
  &lt;label for=&quot;name&quot;&gt;이름&lt;/label&gt;
  &lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;name&quot; required&gt;

  &lt;label for=&quot;email&quot;&gt;이메일&lt;/label&gt;
  &lt;input type=&quot;email&quot; id=&quot;email&quot; name=&quot;email&quot; required&gt;

  &lt;label for=&quot;password&quot;&gt;비밀번호&lt;/label&gt;
  &lt;input type=&quot;password&quot; id=&quot;password&quot; name=&quot;password&quot; minlength=&quot;8&quot; required&gt;

  &lt;label&gt;
    &lt;input type=&quot;checkbox&quot; name=&quot;agree&quot;&gt; 이용약관에 동의합니다
  &lt;/label&gt;

  &lt;button type=&quot;submit&quot;&gt;가입하기&lt;/button&gt;
&lt;/form&gt;</code></pre>
<ul>
<li><code>required</code> — 필수 입력 필드 지정</li>
<li><code>minlength</code> / <code>maxlength</code> — 최소/최대 글자 수</li>
<li><code>name</code> — 서버로 전송될 때의 키 이름</li>
</ul>
<hr>
<p>폼은 HTML에서 사용자와 가장 직접적으로 대화하는 부분이다. <code>action</code>으로 어디로 보낼지, <code>method</code>로 어떻게 보낼지, <code>name</code>으로 무엇이 전송되는지. 이 세 가지를 이해하면 폼의 핵심은 잡힌 것이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[표(table)]]></title>
            <link>https://velog.io/@mskim_/%ED%91%9C</link>
            <guid>https://velog.io/@mskim_/%ED%91%9C</guid>
            <pubDate>Tue, 19 May 2026 06:49:56 GMT</pubDate>
            <description><![CDATA[<h1 id="표--table">표 — table</h1>
<p>행과 열로 이루어진 데이터를 표현할 때 표를 쓴다. 시간표, 가격표, 비교표처럼 &quot;이 항목이 저 항목과 어떻게 다른가&quot;를 보여줄 때 특히 유용하다.</p>
<hr>
<h2 id="기본-구조">기본 구조</h2>
<pre><code class="language-html">&lt;table&gt;
  &lt;tr&gt;
    &lt;th&gt;이름&lt;/th&gt;
    &lt;th&gt;나이&lt;/th&gt;
    &lt;th&gt;직업&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;김자바&lt;/td&gt;
    &lt;td&gt;25&lt;/td&gt;
    &lt;td&gt;개발자&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;이파이썬&lt;/td&gt;
    &lt;td&gt;28&lt;/td&gt;
    &lt;td&gt;데이터 분석가&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</code></pre>
<ul>
<li><code>&lt;table&gt;</code> — 표 전체를 감싸는 태그</li>
<li><code>&lt;tr&gt;</code> — Table Row, 가로 한 줄</li>
<li><code>&lt;th&gt;</code> — Table Header, 제목 셀 (굵게, 가운데 정렬이 기본)</li>
<li><code>&lt;td&gt;</code> — Table Data, 일반 데이터 셀</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mskim_/post/6dcea68f-6c5b-4976-a570-e2659f357e9a/image.png" alt=""></p>
<hr>
<h2 id="thead-tbody-tfoot">thead, tbody, tfoot</h2>
<p>표가 커지면 구조를 명확히 나누기 위해 <code>&lt;thead&gt;</code>, <code>&lt;tbody&gt;</code>, <code>&lt;tfoot&gt;</code>을 사용한다.</p>
<pre><code class="language-html">&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;상품명&lt;/th&gt;
      &lt;th&gt;가격&lt;/th&gt;
      &lt;th&gt;수량&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;노트북&lt;/td&gt;
      &lt;td&gt;1,200,000원&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;마우스&lt;/td&gt;
      &lt;td&gt;35,000원&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
  &lt;tfoot&gt;
    &lt;tr&gt;
      &lt;td&gt;합계&lt;/td&gt;
      &lt;td&gt;1,270,000원&lt;/td&gt;
      &lt;td&gt;3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tfoot&gt;
&lt;/table&gt;</code></pre>
<p>시각적으로 크게 달라 보이지는 않지만, 스크린 리더나 인쇄 시 표 헤더를 반복하는 등 접근성과 기능 면에서 차이가 있다.</p>
<hr>
<h2 id="셀-병합">셀 병합</h2>
<h3 id="colspan--가로-병합">colspan — 가로 병합</h3>
<pre><code class="language-html">&lt;table&gt;
  &lt;tr&gt;
    &lt;td colspan=&quot;2&quot;&gt;두 칸을 합친 셀&lt;/td&gt;  &lt;!-- 2열 병합 --&gt;
    &lt;td&gt;세 번째 칸&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;첫 번째&lt;/td&gt;
    &lt;td&gt;두 번째&lt;/td&gt;
    &lt;td&gt;세 번째&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</code></pre>
<h3 id="rowspan--세로-병합">rowspan — 세로 병합</h3>
<pre><code class="language-html">&lt;table&gt;
  &lt;tr&gt;
    &lt;td rowspan=&quot;2&quot;&gt;두 행을 합친 셀&lt;/td&gt;  &lt;!-- 2행 병합 --&gt;
    &lt;td&gt;오른쪽 첫 번째 행&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;오른쪽 두 번째 행&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/615b2e4a-4555-45c5-9019-51647f58a161/image.png" alt=""></p>
<hr>
<h2 id="caption--표-제목">caption — 표 제목</h2>
<pre><code class="language-html">&lt;table&gt;
  &lt;caption&gt;2024년 분기별 매출&lt;/caption&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;분기&lt;/th&gt;
      &lt;th&gt;매출&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;1분기&lt;/td&gt;
      &lt;td&gt;1억&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;</code></pre>
<p><code>&lt;caption&gt;</code>은 <code>&lt;table&gt;</code> 바로 아래에 넣는다. 표 위에 제목처럼 표시된다.</p>
<hr>
<p>표는 <strong>데이터를 정리하는 용도</strong>로만 써야 한다. 과거에는 레이아웃을 잡기 위해 표를 쓰는 경우가 있었는데, 이제는 CSS(Flexbox, Grid)로 레이아웃을 처리한다. 표가 적절한 곳은 &quot;이 데이터가 행과 열의 관계로 설명되는가?&quot;를 물어보면 쉽게 판단된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[목록]]></title>
            <link>https://velog.io/@mskim_/%EB%AA%A9%EB%A1%9D</link>
            <guid>https://velog.io/@mskim_/%EB%AA%A9%EB%A1%9D</guid>
            <pubDate>Tue, 19 May 2026 06:48:22 GMT</pubDate>
            <description><![CDATA[<h1 id="목록--ul-ol-li">목록 — ul, ol, li</h1>
<p>메뉴, 순서 있는 단계, 항목 나열. 웹 페이지에서 목록은 생각보다 훨씬 자주 등장한다. 네비게이션 바도 사실 <code>&lt;ul&gt;</code> 목록을 CSS로 가로로 펼쳐놓은 것이다.</p>
<hr>
<h2 id="순서-없는-목록--ul">순서 없는 목록 — ul</h2>
<p><code>&lt;ul&gt;</code>(Unordered List)은 순서가 중요하지 않은 항목들을 나열할 때 쓴다. 기본적으로 각 항목 앞에 점(•)이 붙는다.</p>
<pre><code class="language-html">&lt;ul&gt;
  &lt;li&gt;사과&lt;/li&gt;
  &lt;li&gt;바나나&lt;/li&gt;
  &lt;li&gt;딸기&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>결과:</p>
<ul>
<li>사과</li>
<li>바나나</li>
<li>딸기</li>
</ul>
<hr>
<h2 id="순서-있는-목록--ol">순서 있는 목록 — ol</h2>
<p><code>&lt;ol&gt;</code>(Ordered List)은 순서가 의미를 갖는 항목들에 쓴다. 기본적으로 숫자가 붙는다.</p>
<pre><code class="language-html">&lt;ol&gt;
  &lt;li&gt;물을 끓인다&lt;/li&gt;
  &lt;li&gt;면을 넣는다&lt;/li&gt;
  &lt;li&gt;스프를 넣는다&lt;/li&gt;
  &lt;li&gt;3분 기다린다&lt;/li&gt;
&lt;/ol&gt;</code></pre>
<p>결과:</p>
<ol>
<li>물을 끓인다</li>
<li>면을 넣는다</li>
<li>스프를 넣는다</li>
<li>3분 기다린다</li>
</ol>
<h3 id="ol-속성">ol 속성</h3>
<pre><code class="language-html">&lt;!-- 시작 번호 변경 --&gt;
&lt;ol start=&quot;3&quot;&gt;
  &lt;li&gt;세 번째부터 시작&lt;/li&gt;
  &lt;li&gt;네 번째&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- 역순 --&gt;
&lt;ol reversed&gt;
  &lt;li&gt;3등&lt;/li&gt;
  &lt;li&gt;2등&lt;/li&gt;
  &lt;li&gt;1등&lt;/li&gt;
&lt;/ol&gt;

&lt;!-- 알파벳으로 표시 --&gt;
&lt;ol type=&quot;a&quot;&gt;
  &lt;li&gt;항목 a&lt;/li&gt;
  &lt;li&gt;항목 b&lt;/li&gt;
&lt;/ol&gt;</code></pre>
<hr>
<h2 id="목록-항목--li">목록 항목 — li</h2>
<p><code>&lt;li&gt;</code>(List Item)는 <code>&lt;ul&gt;</code> 또는 <code>&lt;ol&gt;</code> 안에서만 쓴다. 단독으로 쓰는 건 올바른 HTML이 아니다.</p>
<pre><code class="language-html">&lt;!-- 올바른 사용 --&gt;
&lt;ul&gt;
  &lt;li&gt;항목&lt;/li&gt;
&lt;/ul&gt;

&lt;!-- 잘못된 사용 --&gt;
&lt;li&gt;단독으로 쓴 li&lt;/li&gt;</code></pre>
<hr>
<h2 id="중첩-목록">중첩 목록</h2>
<p>목록 안에 목록을 넣을 수 있다. <code>&lt;li&gt;</code> 안에 새로운 <code>&lt;ul&gt;</code> 또는 <code>&lt;ol&gt;</code>을 넣으면 된다.</p>
<pre><code class="language-html">&lt;ul&gt;
  &lt;li&gt;프론트엔드
    &lt;ul&gt;
      &lt;li&gt;HTML&lt;/li&gt;
      &lt;li&gt;CSS&lt;/li&gt;
      &lt;li&gt;JavaScript&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;백엔드
    &lt;ul&gt;
      &lt;li&gt;Java&lt;/li&gt;
      &lt;li&gt;Python&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/b5079dd5-81ee-4884-9908-ee78f4558ad1/image.png" alt=""></p>
<hr>
<h2 id="정의-목록--dl-dt-dd">정의 목록 — dl, dt, dd</h2>
<p>용어와 그 설명을 짝으로 나타낼 때 쓰는 목록이다. 자주 쓰이진 않지만 용어 사전, FAQ 같은 구조에 적합하다.</p>
<pre><code class="language-html">&lt;dl&gt;
  &lt;dt&gt;HTML&lt;/dt&gt;
  &lt;dd&gt;웹 페이지의 구조를 정의하는 마크업 언어&lt;/dd&gt;

  &lt;dt&gt;CSS&lt;/dt&gt;
  &lt;dd&gt;웹 페이지의 스타일을 지정하는 언어&lt;/dd&gt;
&lt;/dl&gt;</code></pre>
<ul>
<li><code>&lt;dl&gt;</code> — Definition List</li>
<li><code>&lt;dt&gt;</code> — Definition Term (용어)</li>
<li><code>&lt;dd&gt;</code> — Definition Description (설명)</li>
</ul>
<hr>
<p>목록 태그를 고를 때 기준은 단순하다. 순서가 바뀌면 의미가 달라지면 <code>&lt;ol&gt;</code>, 순서가 상관없으면 <code>&lt;ul&gt;</code>. 이 기준 하나만 기억하면 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[링크와 이미지]]></title>
            <link>https://velog.io/@mskim_/%EB%A7%81%ED%81%AC%EC%99%80-%EC%9D%B4%EB%AF%B8%EC%A7%80</link>
            <guid>https://velog.io/@mskim_/%EB%A7%81%ED%81%AC%EC%99%80-%EC%9D%B4%EB%AF%B8%EC%A7%80</guid>
            <pubDate>Tue, 19 May 2026 06:46:59 GMT</pubDate>
            <description><![CDATA[<h1 id="링크와-이미지">링크와 이미지</h1>
<p>웹이 &#39;웹&#39;인 이유는 페이지들이 서로 연결되어 있기 때문이다. 그 연결을 만드는 태그가 <code>&lt;a&gt;</code>고, 텍스트 외에 시각적인 콘텐츠를 넣는 태그가 <code>&lt;img&gt;</code>다. 이 둘은 거의 모든 웹 페이지에서 빠지지 않는다.</p>
<hr>
<h2 id="링크--a">링크 — a</h2>
<p><code>&lt;a&gt;</code> 태그는 다른 페이지나 위치로 이동하는 하이퍼링크를 만든다.</p>
<pre><code class="language-html">&lt;a href=&quot;https://example.com&quot;&gt;외부 사이트로 이동&lt;/a&gt;
&lt;a href=&quot;about.html&quot;&gt;같은 폴더의 다른 페이지&lt;/a&gt;
&lt;a href=&quot;../index.html&quot;&gt;상위 폴더의 파일&lt;/a&gt;</code></pre>
<ul>
<li><code>href</code> — 이동할 주소 (HyperText REFerence)</li>
<li><code>https://</code>로 시작하면 외부 URL, 그냥 파일명이면 상대 경로</li>
</ul>
<h3 id="target-속성">target 속성</h3>
<pre><code class="language-html">&lt;!-- 현재 탭에서 열기 (기본값) --&gt;
&lt;a href=&quot;https://example.com&quot;&gt;링크&lt;/a&gt;

&lt;!-- 새 탭에서 열기 --&gt;
&lt;a href=&quot;https://example.com&quot; target=&quot;_blank&quot;&gt;새 탭으로 열기&lt;/a&gt;</code></pre>
<p><code>target=&quot;_blank&quot;</code>를 쓸 때는 보안상 <code>rel=&quot;noopener noreferrer&quot;</code>를 함께 쓰는 것이 권장된다.</p>
<pre><code class="language-html">&lt;a href=&quot;https://example.com&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;안전한 새 탭 링크&lt;/a&gt;</code></pre>
<h3 id="페이지-내부-이동">페이지 내부 이동</h3>
<p>같은 페이지 안의 특정 위치로 이동할 수 있다. 이동할 목적지에 <code>id</code>를 붙이고, <code>href</code>에 <code>#id명</code>을 쓴다.</p>
<pre><code class="language-html">&lt;a href=&quot;#section2&quot;&gt;2번 섹션으로 이동&lt;/a&gt;

...

&lt;h2 id=&quot;section2&quot;&gt;2번 섹션&lt;/h2&gt;</code></pre>
<h3 id="이메일-전화-링크">이메일, 전화 링크</h3>
<pre><code class="language-html">&lt;a href=&quot;mailto:hello@example.com&quot;&gt;이메일 보내기&lt;/a&gt;
&lt;a href=&quot;tel:010-1234-5678&quot;&gt;전화 걸기&lt;/a&gt;</code></pre>
<hr>
<h2 id="이미지--img">이미지 — img</h2>
<p><code>&lt;img&gt;</code>는 이미지를 삽입하는 빈 요소다. 닫는 태그가 없다.</p>
<pre><code class="language-html">&lt;img src=&quot;photo.jpg&quot; alt=&quot;강아지 사진&quot;&gt;</code></pre>
<ul>
<li><code>src</code> — 이미지 파일 경로 (source)</li>
<li><code>alt</code> — 이미지를 불러오지 못했을 때 표시할 대체 텍스트 (alternative text)</li>
</ul>
<p><code>alt</code>는 접근성을 위해 반드시 작성해야 한다. 시각 장애인이 쓰는 스크린 리더가 <code>alt</code> 텍스트를 읽어준다. 이미지가 단순 장식이라면 <code>alt=&quot;&quot;</code>로 비워두는 것이 맞다.</p>
<h3 id="크기-설정">크기 설정</h3>
<pre><code class="language-html">&lt;img src=&quot;photo.jpg&quot; alt=&quot;사진&quot; width=&quot;400&quot; height=&quot;300&quot;&gt;</code></pre>
<p>HTML 속성으로 크기를 지정할 수 있지만, 실제로는 CSS로 조절하는 경우가 더 많다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/75be5615-faf7-4e7a-8ba9-8f6a81068e28/image.png" alt=""></p>
<h3 id="경로-작성법">경로 작성법</h3>
<pre><code class="language-html">&lt;!-- 같은 폴더 --&gt;
&lt;img src=&quot;photo.jpg&quot; alt=&quot;사진&quot;&gt;

&lt;!-- 하위 폴더 --&gt;
&lt;img src=&quot;images/photo.jpg&quot; alt=&quot;사진&quot;&gt;

&lt;!-- 상위 폴더 --&gt;
&lt;img src=&quot;../photo.jpg&quot; alt=&quot;사진&quot;&gt;

&lt;!-- 외부 URL --&gt;
&lt;img src=&quot;https://example.com/photo.jpg&quot; alt=&quot;사진&quot;&gt;</code></pre>
<hr>
<h2 id="이미지에-링크-걸기">이미지에 링크 걸기</h2>
<p><code>&lt;a&gt;</code> 안에 <code>&lt;img&gt;</code>를 넣으면 이미지를 클릭했을 때 링크로 이동한다.</p>
<pre><code class="language-html">&lt;a href=&quot;https://example.com&quot;&gt;
  &lt;img src=&quot;banner.jpg&quot; alt=&quot;배너 이미지&quot;&gt;
&lt;/a&gt;</code></pre>
<hr>
<p>링크는 페이지를 연결하고, 이미지는 내용을 시각적으로 전달한다. 이 두 태그만으로도 웹의 기본적인 탐색 구조를 만들 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[텍스트 태그]]></title>
            <link>https://velog.io/@mskim_/%ED%85%8D%EC%8A%A4%ED%8A%B8-%ED%83%9C%EA%B7%B8</link>
            <guid>https://velog.io/@mskim_/%ED%85%8D%EC%8A%A4%ED%8A%B8-%ED%83%9C%EA%B7%B8</guid>
            <pubDate>Tue, 19 May 2026 06:45:35 GMT</pubDate>
            <description><![CDATA[<h1 id="텍스트-태그">텍스트 태그</h1>
<p>HTML에서 가장 많이 쓰는 태그들은 대부분 텍스트와 관련된 것들이다. 제목, 문단, 강조, 줄바꿈 — 텍스트를 어떻게 표현하느냐에 따라 태그가 달라진다.</p>
<hr>
<h2 id="제목-태그--h1--h6">제목 태그 — h1 ~ h6</h2>
<p><code>&lt;h1&gt;</code>부터 <code>&lt;h6&gt;</code>까지 여섯 단계의 제목 태그가 있다. 숫자가 클수록 글자가 작아진다.</p>
<pre><code class="language-html">&lt;h1&gt;가장 큰 제목&lt;/h1&gt;
&lt;h2&gt;두 번째 제목&lt;/h2&gt;
&lt;h3&gt;세 번째 제목&lt;/h3&gt;
&lt;h4&gt;네 번째 제목&lt;/h4&gt;
&lt;h5&gt;다섯 번째 제목&lt;/h5&gt;
&lt;h6&gt;가장 작은 제목&lt;/h6&gt;</code></pre>
<p><img src="https://velog.velcdn.com/images/mskim_/post/7bdbb122-c142-4f38-84dd-ac3a507c5ecd/image.png" alt=""></p>
<p><code>&lt;h1&gt;</code>은 페이지에서 가장 중요한 제목 하나에만 쓰는 것이 일반적이다. 단순히 글자 크기를 조절하려고 <code>&lt;h3&gt;</code>를 쓰는 건 올바른 사용법이 아니다. 글자 크기는 CSS로 조절하고, 태그는 의미에 맞게 선택해야 한다.</p>
<hr>
<h2 id="문단-태그--p">문단 태그 — p</h2>
<p><code>&lt;p&gt;</code>는 하나의 문단을 나타낸다. 앞뒤로 자동으로 여백이 생긴다.</p>
<pre><code class="language-html">&lt;p&gt;첫 번째 문단입니다. 문단은 줄바꿈이 아니라 태그로 구분합니다.&lt;/p&gt;
&lt;p&gt;두 번째 문단입니다.&lt;/p&gt;</code></pre>
<p>HTML에서는 코드에 줄바꿈을 아무리 많이 써도 브라우저에서는 무시된다. 줄을 나누고 싶다면 <code>&lt;br&gt;</code> 태그를 써야 한다.</p>
<hr>
<h2 id="줄바꿈--br">줄바꿈 — br</h2>
<pre><code class="language-html">&lt;p&gt;첫 번째 줄&lt;br&gt;두 번째 줄&lt;br&gt;세 번째 줄&lt;/p&gt;</code></pre>
<p><code>&lt;br&gt;</code>은 닫는 태그 없이 단독으로 쓰는 빈 요소다. 문단을 나누는 용도보다는 주소나 시처럼 같은 문단 안에서 줄을 나눠야 할 때 적합하다.</p>
<hr>
<h2 id="강조-태그--strong-em">강조 태그 — strong, em</h2>
<pre><code class="language-html">&lt;p&gt;이 내용은 &lt;strong&gt;매우 중요&lt;/strong&gt;합니다.&lt;/p&gt;
&lt;p&gt;이 부분은 &lt;em&gt;강조&lt;/em&gt;해서 읽어야 합니다.&lt;/p&gt;</code></pre>
<ul>
<li><code>&lt;strong&gt;</code> — <strong>굵게</strong> 표시. 의미적으로 &quot;중요하다&quot;는 뜻</li>
<li><code>&lt;em&gt;</code> — <em>기울임</em> 표시. 의미적으로 &quot;강조한다&quot;는 뜻</li>
</ul>
<p>시각적으로 굵게 보이게 하려고 <code>&lt;strong&gt;</code>을 쓰기보다, 실제로 중요한 내용에 써야 한다. 단순한 스타일링은 CSS로 처리하는 것이 맞다.</p>
<hr>
<h2 id="인라인-텍스트-태그들">인라인 텍스트 태그들</h2>
<pre><code class="language-html">&lt;p&gt;가격은 &lt;del&gt;50,000원&lt;/del&gt; → &lt;ins&gt;39,000원&lt;/ins&gt;입니다.&lt;/p&gt;
&lt;p&gt;H&lt;sub&gt;2&lt;/sub&gt;O는 물의 화학식입니다.&lt;/p&gt;
&lt;p&gt;E = mc&lt;sup&gt;2&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;&lt;mark&gt;형광펜&lt;/mark&gt;으로 강조한 텍스트입니다.&lt;/p&gt;
&lt;p&gt;단축키: &lt;kbd&gt;Ctrl&lt;/kbd&gt; + &lt;kbd&gt;C&lt;/kbd&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;System.out.println()&lt;/code&gt;은 출력 메서드입니다.&lt;/p&gt;</code></pre>
<table>
<thead>
<tr>
<th>태그</th>
<th>의미</th>
<th>표시 방식</th>
</tr>
</thead>
<tbody><tr>
<td><code>&lt;del&gt;</code></td>
<td>삭제된 텍스트</td>
<td><del>취소선</del></td>
</tr>
<tr>
<td><code>&lt;ins&gt;</code></td>
<td>추가된 텍스트</td>
<td>밑줄</td>
</tr>
<tr>
<td><code>&lt;sub&gt;</code></td>
<td>아래 첨자</td>
<td>H₂O</td>
</tr>
<tr>
<td><code>&lt;sup&gt;</code></td>
<td>위 첨자</td>
<td>mc²</td>
</tr>
<tr>
<td><code>&lt;mark&gt;</code></td>
<td>형광펜 강조</td>
<td>노란 배경</td>
</tr>
<tr>
<td><code>&lt;kbd&gt;</code></td>
<td>키보드 입력</td>
<td><code>Ctrl</code></td>
</tr>
<tr>
<td><code>&lt;code&gt;</code></td>
<td>코드 인라인</td>
<td>고정폭 폰트</td>
</tr>
</tbody></table>
<hr>
<h2 id="span--의미-없는-인라인-컨테이너">span — 의미 없는 인라인 컨테이너</h2>
<p><code>&lt;span&gt;</code>은 특별한 의미 없이 인라인 요소를 묶을 때 쓴다. 주로 CSS로 특정 텍스트에 스타일을 적용하기 위해 감싸는 용도다.</p>
<pre><code class="language-html">&lt;p&gt;가격은 &lt;span style=&quot;color: red;&quot;&gt;품절&lt;/span&gt; 상태입니다.&lt;/p&gt;</code></pre>
<hr>
<h2 id="hr--수평선">hr — 수평선</h2>
<p>내용을 구분하는 수평선을 그린다.</p>
<pre><code class="language-html">&lt;p&gt;첫 번째 섹션 내용&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;두 번째 섹션 내용&lt;/p&gt;</code></pre>
<hr>
<p>텍스트 태그를 고를 때 기준은 &quot;어떻게 보이게 할까?&quot;가 아니라 &quot;이 내용이 무슨 의미인가?&quot;다. 제목이면 <code>&lt;h&gt;</code>, 문단이면 <code>&lt;p&gt;</code>, 중요하면 <code>&lt;strong&gt;</code>. 의미에 맞는 태그를 쓰는 것이 HTML을 올바르게 쓰는 첫 번째 습관이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[HTML(HyperText Markup Language)]]></title>
            <link>https://velog.io/@mskim_/HTML-%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@mskim_/HTML-%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Tue, 19 May 2026 06:43:31 GMT</pubDate>
            <description><![CDATA[<h1 id="html이란--웹-페이지의-뼈대">HTML이란 — 웹 페이지의 뼈대</h1>
<p>웹 페이지를 처음 만들어보려고 하면 세 가지 파일이 등장한다. HTML, CSS, JavaScript. 이 셋은 각자 역할이 다르다.</p>
<ul>
<li><strong>HTML</strong> — 내용과 구조 (&quot;여기에 제목이 있고, 그 아래 문단이 있다&quot;)</li>
<li><strong>CSS</strong> — 디자인 (&quot;제목은 파란색, 글자 크기는 24px&quot;)</li>
<li><strong>JavaScript</strong> — 동작 (&quot;버튼을 누르면 팝업이 뜬다&quot;)</li>
</ul>
<p>HTML은 그중에서 가장 먼저 배워야 하는 뼈대다.</p>
<hr>
<h2 id="html이란">HTML이란</h2>
<p>HTML(HyperText Markup Language)은 웹 페이지의 <strong>구조와 내용을 정의하는 마크업 언어</strong>다. 프로그래밍 언어가 아니라 마크업 언어라는 점이 중요하다. 조건문이나 반복문 같은 로직 없이, 태그(tag)로 콘텐츠의 의미와 구조를 표현한다.</p>
<hr>
<h2 id="기본-구조">기본 구조</h2>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;ko&quot;&gt;
  &lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;
    &lt;title&gt;페이지 제목&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;안녕하세요&lt;/h1&gt;
    &lt;p&gt;첫 번째 웹 페이지입니다.&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>각 부분이 하는 일을 하나씩 보면 이렇다.</p>
<ul>
<li><code>&lt;!DOCTYPE html&gt;</code> — 이 파일이 HTML5 문서임을 브라우저에 알림</li>
<li><code>&lt;html lang=&quot;ko&quot;&gt;</code> — 문서 전체를 감싸는 루트 태그. <code>lang</code>은 언어 설정</li>
<li><code>&lt;head&gt;</code> — 브라우저에게 전달하는 정보 (화면에는 표시되지 않음)</li>
<li><code>&lt;meta charset=&quot;UTF-8&quot;&gt;</code> — 한글 등 다양한 문자를 깨지지 않게 표시</li>
<li><code>&lt;meta name=&quot;viewport&quot; ...&gt;</code> — 모바일 화면 대응을 위한 설정</li>
<li><code>&lt;title&gt;</code> — 브라우저 탭에 표시되는 제목</li>
<li><code>&lt;body&gt;</code> — 실제 화면에 보이는 모든 내용이 여기에 들어감</li>
</ul>
<p><img src="https://velog.velcdn.com/images/mskim_/post/83099421-f4dc-4a3a-beb4-b31b36d9961a/image.png" alt=""></p>
<hr>
<h2 id="태그의-구조">태그의 구조</h2>
<p>HTML은 <strong>태그(tag)</strong> 로 이루어진다. 대부분의 태그는 여는 태그와 닫는 태그 쌍으로 구성된다.</p>
<pre><code class="language-html">&lt;p&gt;이것은 문단입니다.&lt;/p&gt;</code></pre>
<ul>
<li><code>&lt;p&gt;</code> — 여는 태그</li>
<li><code>&lt;/p&gt;</code> — 닫는 태그 (슬래시가 붙음)</li>
<li>그 사이 내용이 해당 태그의 콘텐츠</li>
</ul>
<p>일부 태그는 닫는 태그 없이 단독으로 쓰인다. 이를 <strong>빈 요소(void element)</strong> 라고 한다.</p>
<pre><code class="language-html">&lt;br&gt;      &lt;!-- 줄바꿈 --&gt;
&lt;hr&gt;      &lt;!-- 수평선 --&gt;
&lt;img src=&quot;photo.jpg&quot; alt=&quot;사진&quot;&gt;  &lt;!-- 이미지 --&gt;
&lt;input type=&quot;text&quot;&gt;               &lt;!-- 입력 필드 --&gt;</code></pre>
<hr>
<h2 id="속성attribute">속성(Attribute)</h2>
<p>태그에 추가 정보를 넣을 때 <strong>속성</strong>을 사용한다. 여는 태그 안에 <code>속성명=&quot;값&quot;</code> 형식으로 작성한다.</p>
<pre><code class="language-html">&lt;a href=&quot;https://example.com&quot; target=&quot;_blank&quot;&gt;링크 텍스트&lt;/a&gt;
&lt;img src=&quot;photo.jpg&quot; alt=&quot;사진 설명&quot; width=&quot;300&quot;&gt;</code></pre>
<ul>
<li><code>href</code> — 링크 주소</li>
<li><code>target=&quot;_blank&quot;</code> — 새 탭에서 열기</li>
<li><code>src</code> — 이미지 파일 경로</li>
<li><code>alt</code> — 이미지를 불러오지 못했을 때 표시할 대체 텍스트</li>
</ul>
<hr>
<h2 id="주석">주석</h2>
<p>코드에 설명을 남길 때 주석을 쓴다. 브라우저는 주석을 무시하고 화면에 표시하지 않는다.</p>
<pre><code class="language-html">&lt;!-- 이것은 주석입니다 --&gt;
&lt;p&gt;이 문단은 화면에 보입니다.&lt;/p&gt;</code></pre>
<hr>
<p>HTML은 내용이 어떤 의미를 갖는지 태그로 표현하는 것이 전부다. 제목은 <code>&lt;h1&gt;</code>, 문단은 <code>&lt;p&gt;</code>, 링크는 <code>&lt;a&gt;</code>. 이 기본 감각을 잡고 나면 나머지 태그들도 같은 방식으로 읽힌다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[행동 - 4. Command]]></title>
            <link>https://velog.io/@mskim_/%ED%96%89%EB%8F%99-4.-Command</link>
            <guid>https://velog.io/@mskim_/%ED%96%89%EB%8F%99-4.-Command</guid>
            <pubDate>Tue, 19 May 2026 06:36:47 GMT</pubDate>
            <description><![CDATA[<h1 id="command-패턴">Command 패턴</h1>
<p>텍스트 편집기에서 Ctrl+Z를 누르면 방금 한 작업이 취소된다. 그리고 Ctrl+Y를 누르면 다시 실행된다. 이 기능을 구현하려면 &quot;방금 한 작업&quot;을 어딘가에 기록해둬야 한다. 작업이 무엇인지, 어떻게 되돌리는지도 함께.</p>
<p>Command 패턴은 <strong>요청(작업) 자체를 객체로 만드는 패턴</strong>이다.</p>
<hr>
<h2 id="command-패턴이란">Command 패턴이란</h2>
<p>메서드 호출을 객체로 캡슐화한다. 요청을 보내는 쪽(Invoker)과 실제로 처리하는 쪽(Receiver)을 분리하고, 그 사이에 Command 객체가 자리한다.</p>
<p>요청이 객체가 되면 저장하거나, 큐에 넣거나, 실행 취소(undo)하는 것이 가능해진다.</p>
<p><img src="https://velog.velcdn.com/images/mskim_/post/d6e78e9f-cb50-4c92-9076-4abb405bb5cf/image.png" alt=""></p>
<hr>
<h2 id="구조">구조</h2>
<p>텍스트 편집기의 글자 추가/삭제를 예로 든다.</p>
<pre><code class="language-java">// Command 인터페이스
public interface Command {
    void execute();
    void undo();
}

// Receiver — 실제 작업을 수행하는 객체
public class TextEditor {
    private StringBuilder text = new StringBuilder();

    public void addText(String content) {
        text.append(content);
        System.out.println(&quot;현재 텍스트: &quot; + text);
    }

    public void removeText(int length) {
        int start = text.length() - length;
        if (start &gt;= 0) {
            text.delete(start, text.length());
        }
        System.out.println(&quot;현재 텍스트: &quot; + text);
    }

    public String getText() {
        return text.toString();
    }
}</code></pre>
<pre><code class="language-java">// 구체 Command — 글자 추가
public class AddTextCommand implements Command {
    private TextEditor editor;
    private String content;

    public AddTextCommand(TextEditor editor, String content) {
        this.editor = editor;
        this.content = content;
    }

    @Override
    public void execute() {
        editor.addText(content);
    }

    @Override
    public void undo() {
        editor.removeText(content.length());
    }
}</code></pre>
<pre><code class="language-java">// Invoker — 커맨드를 실행하고 이력을 관리
public class CommandHistory {
    private Deque&lt;Command&gt; history = new ArrayDeque&lt;&gt;();

    public void execute(Command command) {
        command.execute();
        history.push(command);
    }

    public void undo() {
        if (!history.isEmpty()) {
            Command last = history.pop();
            last.undo();
        }
    }
}</code></pre>
<pre><code class="language-java">TextEditor editor = new TextEditor();
CommandHistory invoker = new CommandHistory();

invoker.execute(new AddTextCommand(editor, &quot;Hello&quot;));
// 현재 텍스트: Hello

invoker.execute(new AddTextCommand(editor, &quot;, World&quot;));
// 현재 텍스트: Hello, World

invoker.undo();
// 현재 텍스트: Hello

invoker.undo();
// 현재 텍스트: (빈 문자열)</code></pre>
<hr>
<h2 id="요청을-큐에-넣기">요청을 큐에 넣기</h2>
<p>Command가 객체이기 때문에 큐에 담아두고 나중에 일괄 실행하는 것도 자연스럽다.</p>
<pre><code class="language-java">Queue&lt;Command&gt; commandQueue = new LinkedList&lt;&gt;();

commandQueue.add(new AddTextCommand(editor, &quot;첫 번째 작업&quot;));
commandQueue.add(new AddTextCommand(editor, &quot; 두 번째 작업&quot;));
commandQueue.add(new AddTextCommand(editor, &quot; 세 번째 작업&quot;));

// 일괄 실행
while (!commandQueue.isEmpty()) {
    commandQueue.poll().execute();
}</code></pre>
<p>작업 예약, 배치 처리, 트랜잭션 로그 등에 이 방식이 활용된다.</p>
<hr>
<h2 id="언제-쓰는가">언제 쓰는가</h2>
<ul>
<li>실행 취소(undo), 재실행(redo) 기능이 필요할 때</li>
<li>작업을 큐에 넣거나, 로그로 남기거나, 나중에 실행해야 할 때</li>
<li>요청을 보내는 쪽과 처리하는 쪽을 완전히 분리해야 할 때</li>
</ul>
<hr>
<p>Command 패턴의 출발점은 단순하다. &quot;작업을 지금 당장 실행하는 대신, 객체로 만들어두면 뭘 할 수 있을까?&quot; 거기서부터 실행 취소, 큐잉, 로깅 같은 기능들이 자연스럽게 따라온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[행동 - 3. Template Method]]></title>
            <link>https://velog.io/@mskim_/%ED%96%89%EB%8F%99-3.-Template-Method</link>
            <guid>https://velog.io/@mskim_/%ED%96%89%EB%8F%99-3.-Template-Method</guid>
            <pubDate>Tue, 19 May 2026 06:35:25 GMT</pubDate>
            <description><![CDATA[<h1 id="template-method-패턴">Template Method 패턴</h1>
<p>라면을 끓이는 순서는 대체로 같다. 물을 끓이고, 면을 넣고, 스프를 넣는다. 신라면이든 짜파게티든 이 골격은 바뀌지 않는다. 달라지는 건 스프 종류나 토핑 같은 세부 과정이다.</p>
<p>Template Method는 이 구조를 그대로 코드로 옮긴 패턴이다.</p>
<hr>
<h2 id="template-method-패턴이란">Template Method 패턴이란</h2>
<p><strong>알고리즘의 골격(순서)을 상위 클래스에서 정의하고, 세부 구현은 서브클래스에 위임하는 패턴</strong>이다. 전체 흐름은 고정되고, 변하는 부분만 서브클래스가 채운다.</p>
<hr>
<h2 id="구조">구조</h2>
<p><img src="https://velog.velcdn.com/images/mskim_/post/5e6cb86d-a11d-4b0a-ae48-040dcae8ef0c/image.png" alt=""></p>
<pre><code class="language-java">// 추상 클래스 — 골격 정의
public abstract class DataProcessor {

    // 템플릿 메서드 — 전체 흐름을 여기서 고정
    public final void process() {
        readData();
        processData(); // 서브클래스마다 다름
        saveData();
    }

    private void readData() {
        System.out.println(&quot;데이터 읽기&quot;);
    }

    // 서브클래스가 반드시 구현해야 하는 부분
    protected abstract void processData();

    private void saveData() {
        System.out.println(&quot;데이터 저장&quot;);
    }
}</code></pre>
<pre><code class="language-java">// 구체 클래스 — 달라지는 부분만 구현
public class CsvProcessor extends DataProcessor {
    @Override
    protected void processData() {
        System.out.println(&quot;CSV 형식으로 파싱&quot;);
    }
}

public class JsonProcessor extends DataProcessor {
    @Override
    protected void processData() {
        System.out.println(&quot;JSON 형식으로 파싱&quot;);
    }
}</code></pre>
<pre><code class="language-java">DataProcessor csv = new CsvProcessor();
csv.process();
// 데이터 읽기
// CSV 형식으로 파싱
// 데이터 저장

DataProcessor json = new JsonProcessor();
json.process();
// 데이터 읽기
// JSON 형식으로 파싱
// 데이터 저장</code></pre>
<p><code>process()</code> 메서드에 <code>final</code>을 붙인 이유는 서브클래스가 전체 흐름 자체를 바꾸지 못하게 막기 위해서다.</p>
<hr>
<h2 id="hook-메서드">Hook 메서드</h2>
<p>반드시 오버라이드해야 하는 <code>abstract</code> 메서드 외에, <strong>선택적으로 오버라이드할 수 있는 훅(Hook) 메서드</strong>를 제공할 수도 있다.</p>
<pre><code class="language-java">public abstract class DataProcessor {

    public final void process() {
        readData();
        if (shouldValidate()) { // 훅 — 기본값은 true
            validate();
        }
        processData();
        saveData();
    }

    // 훅 메서드 — 서브클래스가 필요 시 오버라이드
    protected boolean shouldValidate() {
        return true;
    }

    protected abstract void processData();

    private void readData() { System.out.println(&quot;데이터 읽기&quot;); }
    private void validate() { System.out.println(&quot;유효성 검사&quot;); }
    private void saveData() { System.out.println(&quot;데이터 저장&quot;); }
}

// 검증이 필요 없는 경우
public class FastProcessor extends DataProcessor {
    @Override
    protected boolean shouldValidate() {
        return false; // 검증 단계 건너뜀
    }

    @Override
    protected void processData() {
        System.out.println(&quot;빠른 처리&quot;);
    }
}</code></pre>
<hr>
<h2 id="strategy-패턴과의-차이">Strategy 패턴과의 차이</h2>
<p>Template Method와 Strategy는 비슷해 보이지만 접근 방식이 다르다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>Template Method</th>
<th>Strategy</th>
</tr>
</thead>
<tbody><tr>
<td>변하는 부분 처리</td>
<td><strong>상속</strong> — 서브클래스가 오버라이드</td>
<td><strong>구성</strong> — 전략 객체를 주입</td>
</tr>
<tr>
<td>알고리즘 교체</td>
<td>서브클래스를 다르게 선택</td>
<td>런타임에 전략 객체 교체</td>
</tr>
<tr>
<td>결합도</td>
<td>상위 클래스에 묶임</td>
<td>느슨하게 결합</td>
</tr>
</tbody></table>
<p>Template Method는 &quot;뼈대는 내가, 세부는 네가&quot;라면, Strategy는 &quot;세부 전체를 외부에서 꽂아 넣는다&quot;는 차이다.</p>
<hr>
<h2 id="언제-쓰는가">언제 쓰는가</h2>
<ul>
<li>여러 클래스가 동일한 처리 순서를 공유하지만, 특정 단계만 다를 때</li>
<li>중복 코드를 상위 클래스로 올려 공통화하고 싶을 때</li>
<li>알고리즘의 전체 흐름을 서브클래스가 바꾸지 못하게 보호해야 할 때</li>
</ul>
<hr>
<p>공통 흐름이 있고 특정 단계만 구현체마다 달라진다면 Template Method를 떠올리면 된다. 뼈대를 한번 잘 잡아두면, 세부 구현은 서브클래스에서 자유롭게 확장된다.</p>
]]></description>
        </item>
    </channel>
</rss>