소개
코드 리뷰를 시켰는데 현대적인 대안이라면서 최근에 사용하는 방법을 설명해 주더라구요.
음... 나 도 공부 좀 해야 겠는데 싶어서 나도 공부하고, 학생들에게도 보여줄 자료를 만들어 보자 싶었습니다.
진행 방법
어떤 도구를 사용했고, 어떻게 활용하셨나요?
claude code 사용해서 개발을 했습니다.
Tip: 사용한 프롬프트 전문을 꼭 포함하고, 내용을 짧게 소개해 주세요.
개선된 기존 float와 flex에 대해서 설명하는 html 단일 파일 좀 만들어줘
한국어 메뉴 스크린샷
Tip: 활용 이미지나 캡처 화면을 꼭 남겨주세요.
루트 대 레드박스
Tip: 코드 전문은 코드블록에 감싸서 작성해주세요. ( / 을 눌러 '코드 블록'을 선택)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>float vs flexbox 비교</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', 'Malgun Gothic', sans-serif;
background: #f8f9fc;
color: #2d3748;
line-height: 1.7;
}
/* ── 히어로 ── */
.hero {
background: linear-gradient(135deg, #1a202c, #2d3748);
color: white;
text-align: center;
padding: 48px 24px 36px;
}
.hero .badge {
display: inline-block;
background: #e53e3e;
font-size: 12px;
font-weight: 700;
letter-spacing: 1px;
padding: 4px 14px;
border-radius: 20px;
margin-bottom: 16px;
}
.hero h1 { font-size: 26px; margin-bottom: 8px; }
.hero p { color: #a0aec0; font-size: 14px; }
/* ── 공통 섹션 ── */
.wrap {
max-width: 960px;
margin: 0 auto;
padding: 0 24px;
}
.section { margin: 48px 0; }
.section-title {
font-size: 20px;
font-weight: 700;
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 10px;
}
.section-title .num {
width: 30px; height: 30px;
background: #4299e1;
color: white;
border-radius: 50%;
display: flex; align-items: center; justify-content: center;
font-size: 14px; font-weight: 700; flex-shrink: 0;
}
/* ── 비교 카드 (Before / After) ── */
.compare-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 640px) {
.compare-grid { grid-template-columns: 1fr; }
}
.card {
border-radius: 12px;
overflow: hidden;
border: 1px solid #e2e8f0;
background: white;
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
}
.card-head {
padding: 12px 16px;
font-weight: 700;
font-size: 14px;
display: flex;
align-items: center;
gap: 8px;
}
.card-head .dot {
width: 10px; height: 10px;
border-radius: 50%;
}
.card-old .card-head { background: #fff5f5; color: #c53030; }
.card-old .dot { background: #fc8181; }
.card-new .card-head { background: #f0fff4; color: #276749; }
.card-new .dot { background: #68d391; }
.card-body { padding: 16px; }
pre {
background: #1a202c;
color: #e2e8f0;
border-radius: 8px;
padding: 14px 16px;
font-size: 12.5px;
overflow-x: auto;
line-height: 1.7;
font-family: 'Consolas', 'D2Coding', monospace;
}
.kw { color: #f6ad55; }
.val { color: #68d391; }
.sel { color: #63b3ed; }
.cm { color: #718096; font-style: italic; }
.hl { background: rgba(255,255,100,0.15); border-radius: 3px; padding: 1px 3px; }
.desc {
font-size: 13.5px;
color: #4a5568;
margin-bottom: 12px;
}
.point-box {
background: #fffbeb;
border-left: 4px solid #f6ad55;
border-radius: 0 8px 8px 0;
padding: 10px 14px;
font-size: 13px;
color: #744210;
margin-top: 12px;
}
.point-box strong { display: block; color: #c05621; margin-bottom: 2px; }
.ok-box {
background: #f0fff4;
border-left: 4px solid #68d391;
border-radius: 0 8px 8px 0;
padding: 10px 14px;
font-size: 13px;
color: #276749;
margin-top: 12px;
}
.ok-box strong { display: block; color: #2f855a; margin-bottom: 2px; }
/* ── 라이브 데모 ── */
.demo-wrap {
border: 1px solid #e2e8f0;
border-radius: 12px;
overflow: hidden;
background: white;
}
.demo-tab {
display: flex;
border-bottom: 1px solid #e2e8f0;
}
.demo-tab button {
flex: 1;
padding: 12px;
border: none;
background: #f7fafc;
font-size: 13px;
font-weight: 700;
cursor: pointer;
color: #718096;
transition: all 0.2s;
}
.demo-tab button.active {
background: white;
color: #2d3748;
border-bottom: 3px solid #4299e1;
}
.demo-panel { padding: 20px; display: none; }
.demo-panel.active { display: block; }
/* float 데모 */
.float-container {
border: 2px dashed #fed7d7;
border-radius: 8px;
padding: 12px;
font-size: 13px;
overflow: hidden; /* clearfix */
}
.float-container::after { content: ''; display: block; clear: both; }
.float-left {
float: left;
width: 38%;
background: #fff5f5;
border: 1px solid #fc8181;
border-radius: 6px;
padding: 12px;
text-align: center;
}
.float-right {
float: left;
width: 55%;
margin-left: 7%;
background: #fff5f5;
border: 1px solid #fc8181;
border-radius: 6px;
padding: 12px;
text-align: center;
}
.float-problem {
margin-top: 16px;
background: #fff5f5;
border: 1px solid #fc8181;
border-radius: 6px;
padding: 10px;
font-size: 12px;
color: #c53030;
}
/* flex 데모 */
.flex-container {
border: 2px dashed #c6f6d5;
border-radius: 8px;
padding: 12px;
font-size: 13px;
display: flex;
gap: 16px;
}
.flex-left {
flex: 0 0 38%;
background: #f0fff4;
border: 1px solid #68d391;
border-radius: 6px;
padding: 12px;
text-align: center;
}
.flex-right {
flex: 1;
background: #f0fff4;
border: 1px solid #68d391;
border-radius: 6px;
padding: 12px;
text-align: center;
}
.flex-good {
margin-top: 16px;
background: #f0fff4;
border: 1px solid #68d391;
border-radius: 6px;
padding: 10px;
font-size: 12px;
color: #276749;
}
/* 헤더 네비 데모 */
.nav-old { list-style: none; border: 2px dashed #fed7d7; padding: 10px; border-radius: 8px; }
.nav-old li {
display: inline-block;
font-size: 13px;
background: #fff5f5;
border: 1px solid #fc8181;
padding: 6px 12px;
border-radius: 4px;
margin-right: 6px;
margin-bottom: 4px;
}
.nav-new { list-style: none; display: flex; gap: 8px; flex-wrap: wrap; border: 2px dashed #c6f6d5; padding: 10px; border-radius: 8px; }
.nav-new li {
font-size: 13px;
background: #f0fff4;
border: 1px solid #68d391;
padding: 6px 12px;
border-radius: 4px;
}
/* 목록 정렬 데모 */
.news-old li {
list-style: none;
border-bottom: 1px solid #e2e8f0;
padding: 10px 4px;
overflow: hidden;
font-size: 13px;
}
.news-old li h4 { float: left; }
.news-old li span { float: right; font-size: 11px; background: #fed7d7; border-radius: 4px; padding: 2px 8px; }
.news-new { list-style: none; }
.news-new li {
border-bottom: 1px solid #e2e8f0;
padding: 10px 4px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
}
.news-new li span { font-size: 11px; background: #c6f6d5; border-radius: 4px; padding: 2px 8px; flex-shrink: 0; }
/* ── 개념 요약 표 ── */
.summary-table {
width: 100%;
border-collapse: collapse;
font-size: 13.5px;
}
.summary-table th {
background: #2d3748;
color: white;
padding: 10px 14px;
text-align: left;
}
.summary-table td {
padding: 10px 14px;
border-bottom: 1px solid #e2e8f0;
vertical-align: top;
}
.summary-table tr:nth-child(even) td { background: #f7fafc; }
.tag-old { display: inline-block; background: #fed7d7; color: #c53030; border-radius: 4px; padding: 1px 8px; font-size: 11px; font-weight: 700; }
.tag-new { display: inline-block; background: #c6f6d5; color: #276749; border-radius: 4px; padding: 1px 8px; font-size: 11px; font-weight: 700; }
/* ── 체크리스트 ── */
.checklist { list-style: none; display: flex; flex-direction: column; gap: 10px; }
.checklist li { display: flex; align-items: flex-start; gap: 10px; font-size: 14px; }
.checklist .icon { flex-shrink: 0; font-size: 16px; margin-top: 1px; }
footer {
background: #1a202c;
color: #718096;
text-align: center;
padding: 24px;
font-size: 13px;
margin-top: 60px;
}
</style>
</head>
<body>
<div class="hero">
<div class="badge">CSS Layout</div>
<h1>float vs flexbox</h1>
<p>news.html 개선 전·후 코드를 비교하며 배우는 레이아웃</p>
</div>
<div class="wrap">
<!-- ① float의 문제점 -->
<div class="section">
<div class="section-title"><span class="num">1</span>float 란? — 원래 목적과 문제점</div>
<p class="desc">
<code>float</code>는 원래 신문처럼 <strong>이미지 옆에 텍스트를 흘려보내기</strong> 위해 만들어진 속성입니다.
레이아웃 도구로는 설계되지 않았지만, flex/grid가 없던 시절에 컬럼 배치에 억지로 사용했습니다.
</p>
<div class="compare-grid">
<div class="card card-old">
<div class="card-head"><div class="dot"></div>기존 코드 (float)</div>
<div class="card-body">
<pre><span class="sel">.menu</span> {
<span class="kw">width</span>: <span class="val">40%</span>;
<span class="kw">float</span>: <span class="val hl">left</span>; <span class="cm">/* 왼쪽으로 띄움 */</span>
}
<span class="sel">.list</span> {
<span class="kw">width</span>: <span class="val">55%</span>;
<span class="kw">float</span>: <span class="val hl">left</span>; <span class="cm">/* 옆에 붙도록 */</span>
}</pre>
<div class="point-box">
<strong>문제점</strong>
float한 요소는 문서 흐름에서 "뜨기" 때문에 부모 컨테이너가 높이를 인식하지 못합니다. clearfix 같은 꼼수가 필요합니다.
</div>
</div>
</div>
<div class="card card-new">
<div class="card-head"><div class="dot"></div>개선 코드 (flex)</div>
<div class="card-body">
<pre><span class="sel">.body</span> {
<span class="kw">display</span>: <span class="val hl">flex</span>; <span class="cm">/* 자식을 가로 배치 */</span>
<span class="kw">flex</span>: <span class="val">1</span>; <span class="cm">/* 남 은 높이 채움 */</span>
}
<span class="cm">/* .menu, .list에 float 없음 */</span>
<span class="sel">.menu</span> { <span class="kw">width</span>: <span class="val">40%</span>; }
<span class="sel">.list</span> { <span class="kw">width</span>: <span class="val">60%</span>; }</pre>
<div class="ok-box">
<strong>해결</strong>
flex 컨테이너는 자식 높이를 정확히 인식합니다. clearfix 없이 깔끔하게 2컬럼을 만들 수 있습니다.
</div>
</div>
</div>
</div>
</div>
<!-- ② 라이브 데모 -->
<div class="section">
<div class="section-title"><span class="num">2</span>직접 비교해보기 — 같은 결과, 다른 방식</div>
<!-- 2-1: 2컬럼 -->
<p class="desc" style="margin-bottom:12px;"><strong>2컬럼 레이아웃</strong> — .menu / .list 나란히 배치</p>
<div class="demo-wrap" style="margin-bottom:24px;">
<div class="demo-tab">
<button class="active" onclick="switchTab(this, 'col-old')">float (기존)</button>
<button onclick="switchTab(this, 'col-new')">flexbox (개선)</button>
</div>
<div class="demo-panel active" id="col-old">
<div class="float-container">
<div class="float-left">
<strong>.menu</strong><br>float: left<br>width: 40%
</div>
<div class="float-right">
<strong>.list</strong><br>float: left<br>width: 55%
</div>
</div>
<div class="float-problem">
⚠️ 부모(.body)의 실제 높이 = 0 → 자식들이 "떠있기" 때문에 높이를 잡지 못함<br>
해결하려면 부모에 <code>overflow: hidden</code> 또는 clearfix가 필요
</div>
</div>
<div class="demo-panel" id="col-new">
<div class="flex-container">
<div class="flex-left">
<strong>.menu</strong><br>flex-child<br>width: 40%
</div>
<div class="flex-right">
<strong>.list</strong><br>flex: 1<br>(나머지 공간)
</div>
</div>
<div class="flex-good">
✅ 부모(.body)가 자식 높이를 정확히 인식 → 별도 처리 불필요
</div>
</div>
</div>
<!-- 2-2: 네비게이션 -->
<p class="desc" style="margin-bottom:12px;"><strong>가로 나열 네비게이션</strong> — .header li 배치</p>
<div class="demo-wrap" style="margin-bottom:24px;">
<div class="demo-tab">
<button class="active" onclick="switchTab(this, 'nav-old')">inline-block (기존)</button>
<button onclick="switchTab(this, 'nav-new')">flex (개선)</button>
</div>
<div class="demo-panel active" id="nav-old">
<ul class="nav-old">
<li>오늘의 뉴스</li><li>많이본뉴스</li><li>연예</li>
<li>Life</li><li>IT/과학</li><li>FUNFUN</li><li>자동차</li>
</ul>
<div class="point-box" style="margin-top:12px;">
<strong>inline-block의 단점</strong>
HTML 줄바꿈이 공백(4px)으로 렌더링됩니다. 간격을 맞추려면 font-size:0 같은 꼼수가 필요합니다.
</div>
</div>
<div class="demo-panel" id="nav-new">
<ul class="nav-new">
<li>오늘의 뉴스</li><li>많이본뉴스</li><li>연예</li>
<li>Life</li><li>IT/과학</li><li>FUNFUN</li><li>자동차</li>
</ul>
<div class="ok-box" style="margin-top:12px;">
<strong>flex + gap의 장점</strong>
<code>gap: 20px</code> 하나로 균등한 간격을 지정합니다. 공백 문제가 없습니다.
</div>
</div>
</div>
<!-- 2-3: 뉴스 한 줄 -->
<p class="desc" style="margin-bottom:12px;"><strong>뉴스 한 줄</strong> — 제목 왼쪽 / 로고 오른쪽</p>
<div class="demo-wrap">
<div class="demo-tab">
<button class="active" onclick="switchTab(this, 'news-old')">float (기존)</button>
<button onclick="switchTab(this, 'news-new')">flex (개선)</button>
</div>
<div class="demo-panel active" id="news-old">
<ul class="news-old">
<li><h4>"알파고가 인간 통제 못 하게" 美.日.유럽...</h4><span>조선일보</span></li>
<li><h4>햄버거 굽는 AI 로봇 '플리피' 어떻게 생겼나...</h4><span>ZDNet</span></li>
<li><h4>삼겹살 기름 안 닦고 굽는 방법</h4><span>[AD]</span></li>
</ul>
<pre style="margin-top:12px;"><span class="sel">.list h1</span> { <span class="kw">float</span>: <span class="val">left</span>; }
<span class="sel">.list img</span> { <span class="kw">float</span>: <span class="val">right</span>; }
<span class="sel">.list b</span> { <span class="kw">float</span>: <span class="val">right</span>; }</pre>
</div>
<div class="demo-panel" id="news-new">
<ul class="news-new">
<li><h4>"알파고가 인간 통제 못 하게" 美.日.유럽...</h4><span>조선일보</span></li>
<li><h4>햄버거 굽는 AI 로봇 '플리피' 어떻게 생겼나...</h4><span>ZDNet</span></li>
<li><h4>삼겹살 기름 안 닦고 굽는 방법</h4><span>[AD]</span></li>
</ul>
<pre style="margin-top:12px;"><span class="sel">.list li</span> {
<span class="kw">display</span>: <span class="val">flex</span>;
<span class="kw">justify-content</span>: <span class="val">space-between</span>;
<span class="kw">align-items</span>: <span class="val">center</span>;
}</pre>
</div>
</div>
</div>
<!-- ③ flex 핵심 속성 -->
<div class="section">
<div class="section-title"><span class="num">3</span>flexbox 핵심 속성 정리</div>
<table class="summary-table">
<thead>
<tr>
<th>속성</th>
<th>값</th>
<th>설명</th>
<th>코드에서 사용한 곳</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>display: flex</code></td>
<td>—</td>
<td>이 요소를 flex 컨테이너로 만듦. 자식이 flex item이 됨</td>
<td><code>#box</code>, <code>.body</code>, <code>.header</code>, <code>.list li</code></td>
</tr>
<tr>
<td><code>flex-direction</code></td>
<td><code>row</code> / <code>column</code></td>
<td>자식을 가로(row) 또는 세로(column)로 배치</td>
<td><code>#box { flex-direction: column }</code></td>
</tr>
<tr>
<td><code>justify-content</code></td>
<td><code>center</code> / <code>space-between</code> 등</td>
<td>주축(가로) 방향 정렬</td>
<td><code>.list li { justify-content: space-between }</code></td>
</tr>
<tr>
<td><code>align-items</code></td>
<td><code>center</code> / <code>flex-end</code> 등</td>
<td>교차축(세로) 방향 정렬</td>
<td><code>.header { align-items: flex-end }</code></td>
</tr>
<tr>
<td><code>gap</code></td>
<td><code>20px</code> 등</td>
<td>자식 사이 간격 (margin 없이)</td>
<td><code>.header ul { gap: 20px }</code></td>
</tr>
<tr>
<td><code>flex: 1</code></td>
<td>숫자</td>
<td>남은 공간을 해당 비율로 채움</td>
<td><code>.body { flex: 1 }</code> — header 제외 나머지 높이</td>
</tr>
</tbody>
</table>
</div>
<!-- ④ 언제 뭘 쓸까 -->
<div class="section">
<div class="section-title"><span class="num">4</span>정리 — 언제 무엇을 쓸까</div>
<ul class="checklist">
<li>
<span class="icon">✅</span>
<span><strong>flexbox</strong> — 한 방향(가로 또는 세로)으로 요소를 나열할 때. 네비게이션, 카드 목록, 뉴스 한 줄처럼 1차원 레이아웃에 적합합니다.</span>
</li>
<li>
<span class="icon">✅</span>
<span><strong>grid</strong> — 행과 열을 동시에 다루는 2차원 레이아웃에 적합합니다. 전체 페이지 틀, 대시보드처럼 격자 구조에 사용합니다.</span>
</li>
<li>
<span class="icon">⚠️</span>
<span><strong>float</strong> — 레이아웃 목적으로는 사용을 피하세요. 이미지 옆에 텍스트를 흘릴 때처럼 원래 목적에만 사용합니다.</span>
</li>
<li>
<span class="icon">📌</span>
<span>기존 코드를 읽을 때는 float를 이해해야 합니다. 실무 레거시 코드에 여전히 많이 남아 있습니다.</span>
</li>
</ul>
</div>
</div><!-- /wrap -->
<footer>
news.html 개선 — float → flexbox 비교 학습 자료
</footer>
<script>
function switchTab(btn, panelId) {
const wrap = btn.closest('.demo-wrap');
wrap.querySelectorAll('.demo-tab button').forEach(b => b.classList.remove('active'));
wrap.querySelectorAll('.demo-panel').forEach(p => p.classList.remove('active'));
btn.classList.add('active');
wrap.querySelector('#' + panelId).classList.add('active');
}
</script>
</body>
</html>
결과와 배운 점
자주 활용하던 방식이 아니라서 낯설지만 예제를 만들어서 살펴보면 좋을 것 같다는 생각이 들었습니다.
현대적인 방식으로 코드를 짜 달라고 부탁해야지 싶습니다.
할 일이 계속 늘어나네요.
좋은 거겠죠?