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

Window innerWidth và innerHeight trong JavaScript

window.innerWidth và window.innerHeight trả về **kích thước viewport** (khu vực hiển thị nội dung) của cửa sổ trình duyệt **tính bằng pixel**, bao gồm thanh cuộn (scrollbar) nếu có.

Đối so sánh:

PropertyMô tảBao gồm scrollbar
window.innerWidthChiều rộng viewportCó
window.innerHeightChiều cao viewportCó
document.documentElement.clientWidthChiều rộng viewport (không scrollbar)Không
document.documentElement.clientHeightChiều cao viewport (không scrollbar)Không
screen.widthChiều rộng màn hình vật lý-
screen.heightChiều cao màn hình vật lý-
window.outerWidthChiều rộng cửa sổ browser (kể viền, toolbar)-
window.outerHeightChiều cao cửa sổ browser-

Ví dụ minh họa

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Window Dimensions</title>
  <style>
    body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; padding: 20px; }
    .result { font-size: 18px; font-weight: 500; margin: 10px 0; color: green; font-family: monospace; }
    button { padding: 8px 16px; cursor: pointer; }
    .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 10px; margin-top: 20px; }
    .card { background: #f5f5f5; padding: 15px; border-radius: 8px; border-left: 4px solid #2196f3; }
    .card.warning { border-left-color: #ff9800; }
  </style>
</head>
<body>
  <h1>Window innerWidth / innerHeight</h1>
  <button class="Btn" id="btn">LẤY KÍCH THƯỚC</button>
  <h3> Nhấn nút để lấy kích thước viewport </h3>
  <div class="result" id="result"></div>
  
  <div class="grid" id="details"></div>
  
  <script>
    const resEle = document.querySelector("#result");
    const detailsEle = document.querySelector("#details");
    
    function getAllDimensions() {
      return {
        'innerWidth': window.innerWidth,
        'innerHeight': window.innerHeight,
        'clientWidth (no scrollbar)': document.documentElement.clientWidth,
        'clientHeight (no scrollbar)': document.documentElement.clientHeight,
        'outerWidth': window.outerWidth,
        'outerHeight': window.outerHeight,
        'screen.width': screen.width,
        'screen.height': screen.height,
        'devicePixelRatio': window.devicePixelRatio,
        'scrollX': window.scrollX,
        'scrollY': window.scrollY
      };
    }
    
    function renderDimensions() {
      const dims = getAllDimensions();
      resEle.innerHTML = `Viewport: ${dims.innerWidth} × ${dims.innerHeight} px`;
      
      detailsEle.innerHTML = '';
      for (const [key, value] of Object.entries(dims)) {
        const card = document.createElement('div');
        card.className = 'card' + (key.includes('scroll') ? ' warning' : '');
        card.innerHTML = `${key}: ${value}`;
        detailsEle.appendChild(card);
      }
    }
    
    document.querySelector("#btn").addEventListener("click", renderDimensions);
    
    // Live update khi resize
    let resizeTimeout;
    window.addEventListener('resize', () => {
      clearTimeout(resizeTimeout);
      resizeTimeout = setTimeout(renderDimensions, 100);
    });
    
    // Initial
    renderDimensions();
  </script>
</body>
</html>

Kết quả

Hiển thị kích thước viewport real-time. Thay đổi kích thước cửa sổ → tự động cập nhật (debounced).

Ứng dụng thực tế:

// 1. Responsive breakpoints
function getBreakpoint() {
  const w = window.innerWidth;
  if (w < 640) return 'mobile';
  if (w < 1024) return 'tablet';
  if (w < 1280) return 'desktop';
  return 'wide';
}

// 2. Kiểm tra mobile
const isMobile = () => window.innerWidth < 768;

// 3. Center modal/popup
function centerElement(el) {
  el.style.position = 'fixed';
  el.style.left = (window.innerWidth - el.offsetWidth) / 2 + 'px';
  el.style.top = (window.innerHeight - el.offsetHeight) / 2 + 'px';
}

// 4. Detect orientation change
window.addEventListener('resize', () => {
  const isLandscape = window.innerWidth > window.innerHeight;
  document.body.classList.toggle('landscape', isLandscape);
});

// 5. Lazy load images khi near viewport
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) loadImage(entry.target);
  });
}, { rootMargin: `${window.innerHeight * 0.5}px` });

Resize Observer (Modern, hiệu năng tốt hơn):

const resizeObserver = new ResizeObserver(entries => {
  for (const entry of entries) {
    const { inlineSize, blockSize } = entry.contentRect;
    console.log('Element size:', inlineSize, blockSize);
  }
});
resizeObserver.observe(document.body);

Lưu ý:

  • innerWidth/Height bao gồm scrollbar → có thể gây layout shift 1-2px khi scrollbar xuất hiện/biến mất
  • Trên mobile: bao gồm address bar khi ẩn/hiện (viewport units: dvh, svh, lvh)
  • SSR (Next.js, Nuxt): window undefined → dùng useEffect hoặc dynamic import