학생 공부 시키면서 나도 공부하기 float vs flex

소개

코드 리뷰를 시켰는데 현대적인 대안이라면서 최근에 사용하는 방법을 설명해 주더라구요.

음... 나도 공부 좀 해야 겠는데 싶어서 나도 공부하고, 학생들에게도 보여줄 자료를 만들어 보자 싶었습니다.

진행 방법

어떤 도구를 사용했고, 어떻게 활용하셨나요?

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>

결과와 배운 점

자주 활용하던 방식이 아니라서 낯설지만 예제를 만들어서 살펴보면 좋을 것 같다는 생각이 들었습니다.

현대적인 방식으로 코드를 짜 달라고 부탁해야지 싶습니다.

할 일이 계속 늘어나네요.

좋은 거겠죠?

밀어주고 끌어주는

온·오프라인 AI 스터디

AI로 어디까지 할 수 있는지
직접 확인하실 분만 신청하세요.