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:
| Property | Mô tả | Bao gồm scrollbar |
|---|---|---|
window.innerWidth | Chiều rộng viewport | Có |
window.innerHeight | Chiều cao viewport | Có |
document.documentElement.clientWidth | Chiều rộng viewport (không scrollbar) | Không |
document.documentElement.clientHeight | Chiều cao viewport (không scrollbar) | Không |
screen.width | Chiều rộng màn hình vật lý | - |
screen.height | Chiều cao màn hình vật lý | - |
window.outerWidth | Chiều rộng cửa sổ browser (kể viền, toolbar) | - |
window.outerHeight | Chiề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/Heightbao 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):
windowundefined → dùnguseEffecthoặcdynamic import