flex 布局里地图高度为 0,只剩一条灰边
页面顶部是标题栏,下面留一格放地图,结果地图只有几个像素高,瓦片挤成一条线。
现象
地图容器的边框能看到,但高度几乎为零。打印尺寸得到 0:
console.log(map.getSize());
// Point {x: 1280, y: 0}
map.getCenter() 的经纬度是对的,缩放级别也对,
只是可视区域高度为零,任何瓦片都落不进视野。
原因
地图容器写了 height: 100%,但父级是 flex 布局且没有确定高度。
百分比高度在“父级高度由内容决定”的情况下无法解析,浏览器按 auto 处理,
容器里又没有内容,最终高度就是 0。
另一种情况是父级 flex: 1,但子项默认 min-height: auto,
被内部绝对定位的元素撑得无法收缩,或者反过来被压成 0。
排查过程
从地图容器向上逐级打印 clientHeight,找到第一个为 0 的层级:
var el = document.getElementById('map');
var node = el;
while (node && node !== document.documentElement) {
console.log(node.tagName, node.className, node.clientHeight, getComputedStyle(node).display);
node = node.parentElement;
}
解决方案
CSS 上给出一条确定的高度链。html、body 到主容器都要有高度,
flex 子项补 min-height: 0:
html, body {
height: 100%;
margin: 0;
}
.layout {
display: flex;
flex-direction: column;
height: 100%;
}
.layout .header {
flex: 0 0 56px;
}
.layout .map-wrap {
flex: 1 1 auto;
min-height: 0; /* 允许收缩到剩余空间 */
position: relative;
}
#map {
position: absolute;
inset: 0;
}
容器尺寸在初始化之后才确定时(例如抽屉展开、标签页切换), 必须通知 Leaflet 重新计算:
var map = L.map('map', { center: [39.907, 116.391], zoom: 11 });
L.tileLayer('https://tile.example.cn/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© Example'
}).addTo(map);
// 容器尺寸变化后
var ro = new ResizeObserver(function () {
map.invalidateSize({ animate: false });
});
ro.observe(document.getElementById('map'));
在隐藏面板里创建地图时,等可见再初始化,避免一开始就按 0 尺寸绘制:
var panel = document.querySelector('#map-panel');
var observer = new MutationObserver(function () {
if (panel.clientHeight > 0) {
observer.disconnect();
map.invalidateSize();
}
});
observer.observe(panel, { attributes: true, attributeFilter: ['style', 'class'] });
验证
map.getSize() 的 y 值等于实际容器高度。
打开页面后瓦片铺满整个区域,不再只有顶部一条。
拖动窗口改变高度,地图跟随变化且瓦片不拉伸。
最小改动:只给 #map { height: 100vh } 也能立刻显示,
但在有标题栏的布局里会超出视口,出现滚动条。
正确做法是让容器高度来自 flex 布局,而不是写死视口高度。
经纬志(2026)。《flex 布局里地图高度为 0,只剩一条灰边》。https://www.jingweizhi.com/cookbook/leaflet-flex-height-zero.html(访问日期 2026-11-03)。