Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Flexbox và cuộn dọc trong ứng dụng full-height với Flexbox API mới


Vấn đề: Full-height app với Flexbox

Khi xây dựng layout full-height (header + content + footer), content cần cuộn dọc (overflow-y: auto) trong khi header/footer cố định. Flexbox giải quyết thanh lịch.

HTML Structure

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <title>Flexbox Full Height Layout</title>
  <style>
    * { margin: 0; padding: 0; box-sizing: border-box; }
    
    html, body { height: 100%; }
    
    #app {
      display: flex;
      flex-direction: column;
      min-height: 100vh; /* Quan trọng: min-height không phải height */
    }
    
    header {
      background: #2c3e50;
      color: white;
      padding: 1rem 2rem;
      flex-shrink: 0; /* Không co lại */
    }
    
    main {
      flex: 1 1 auto; /* flex-grow: 1, flex-shrink: 1, flex-basis: auto */
      overflow-y: auto; /* Cuộn dọc tại đây */
      padding: 2rem;
      background: #f8f9fa;
    }
    
    footer {
      background: #34495e;
      color: white;
      padding: 1rem 2rem;
      text-align: center;
      flex-shrink: 0;
    }
    
    .content-block {
      background: white;
      padding: 1.5rem;
      margin-bottom: 1.5rem;
      border-radius: 8px;
      box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    }
  </style>
</head>
<body>
  <div id="app">
    <header>
      <h1>Header - Cố định</h1>
    </header>
    
    <main>
      <div class="content-block">
        <h2>Nội dung 1</h2>
        <p>Lorem ipsum dolor sit amet...</p>
      </div>
      <div class="content-block">
        <h2>Nội dung 2</h2>
        <p>Lorem ipsum dolor sit amet...</p>
      </div>
      <!-- Nhiều block để test scroll -->
    </main>
    
    <footer>
      © 2024 Footer - Cố định
    </footer>
  </div>
</body>
</html>

Giải thích Flex Properties

main {
  /* Shorthand: flex-grow | flex-shrink | flex-basis */
  flex: 1 1 auto;
  
  /* Tương đương: */
  flex-grow: 1;      /* Mở rộng lấp đầy không gian còn lại */
  flex-shrink: 1;    /* Có thể co lại nếu cần (thường không xảy ra do min-height) */
  flex-basis: auto;  /* Kích thước ban đầu dựa trên content */
  
  overflow-y: auto;  /* Cuộn dọc khi content cao hơn viewport */
}

Tại sao dùng min-height: 100vh thay vì height: 100vh?

  • height: 100vh: Ép container đúng 100vh. Nếu content ít, footer dính dưới. Nếu content nhiều, overflow ra ngoài viewport (không scroll trong main).
  • min-height: 100vh: Container tối thiểu 100vh. Content ít → footer ở dưới cùng. Content nhiều → container mở rộng, main scroll nội bộ.

Biến thể: Sidebar + Content

<div id="app">
  <header>Header</header>
  <div class="layout">
    <aside class="sidebar">Sidebar</aside>
    <main class="content">Content scrollable</main>
  </div>
  <footer>Footer</footer>
</div>

<style>
  .layout {
    display: flex;
    flex: 1;
    overflow: hidden; /* Quan trọng: ngăn layout overflow */
  }
  
  .sidebar {
    width: 260px;
    flex-shrink: 0;
    background: #f8f9fa;
    border-right: 1px solid #ddd;
    overflow-y: auto; /* Sidebar tự scroll nếu cần */
    max-height: 100%;
  }
  
  .content {
    flex: 1;
    overflow-y: auto; /* Content scroll */
    padding: 2rem;
  }
</style>

Legacy Flexbox (2012) - Prefixes cũ

Chỉ cần nếu hỗ trợ IE10, Android Browser cũ:

#container {
  display: -webkit-box;      /* Old WebKit */
  display: -ms-flexbox;      /* IE10 */
  display: -webkit-flex;     /* New WebKit */
  display: flex;             /* Standard */
  
  -webkit-box-orient: vertical;
  -webkit-flex-direction: column;
  -ms-flex-direction: column;
  flex-direction: column;
}

main {
  -webkit-box-flex: 1;
  -webkit-flex: 1 1 auto;
  -ms-flex: 1 1 auto;
  flex: 1 1 auto;
  overflow-y: auto;
}

Lưu ý quan trọng

  • overflow: hidden trên flex container cha nếu con có overflow: auto (tránh double scroll)
  • flex-shrink: 0 trên header/footer/sidebar cố định
  • Tránh height: 100% trên flex item (gây overflow), dùng flex: 1 + overflow: auto
  • min-height: 0 trên flex item nếu content có thể nhỏ hơn (fix Firefox bug)

Debug Flexbox

/* DevTools: Enable "Flexbox" badge trong Elements panel */
/* CSS Debug helper */
.flex-debug * {
  outline: 1px solid rgba(255,0,0,0.1);
}
.flex-debug .flex-container {
  outline: 2px solid red;
}
.flex-debug .flex-item {
  outline: 2px solid blue;
}