CesiumWidget 尺寸为 0,地球建不出来
页面一打开就报错,容器明明写了 width: 100%; height: 100%,
浏览器算出来的却是 0×0。
现象
控制台报出一条来自 CesiumWidget 构造过程的错误,
之后整个地图区域保持空白:
DeveloperError: Expected width to be greater than 0, actual value was 0
at CesiumWidget.draw (CesiumWidget.js:1042)
at Viewer.resize (Viewer.js:1301)
同时 viewer.canvas.width 为 0,缩放手柄、版权信息也全部错位在左上角。
原因
Cesium 在构造时读取容器的 clientWidth 与 clientHeight 来创建 WebGL 画布。
百分比高度只有在父级有确定高度时才成立,以下三种情况都会让结果变成 0:
- 容器或任一祖先节点处于
display: none,常见于标签页、抽屉、弹窗未展开时初始化。 - 父级是 flex 布局,子项设了
flex: 1却没有min-height: 0,被内容压成 0。 - 脚本在
DOMContentLoaded之前执行,样式表还没应用。
排查过程
在初始化前打印容器尺寸,并逐级向上查找第一个高度为 0 的祖先:
var el = document.getElementById('cesiumContainer');
console.log(el.clientWidth, el.clientHeight); // 0 0
var p = el;
while (p && p !== document.body) {
console.log(p.tagName, p.className, p.clientHeight);
p = p.parentElement;
}
解决方案
CSS 侧给容器一个明确的尺寸来源。height: 100% 必须有一连串确定高度的父级:
html, body {
height: 100%;
margin: 0;
}
#app {
display: flex;
flex-direction: column;
height: 100%;
}
#cesiumContainer {
flex: 1;
min-height: 0; /* 关键:允许 flex 子项收缩 */
position: relative;
}
容器在隐藏状态下创建时,等它可见再初始化,而不是先建再补尺寸:
function initWhenVisible(el, callback) {
if (el.clientWidth > 0 && el.clientHeight > 0) {
callback();
return;
}
var ro = new ResizeObserver(function () {
if (el.clientWidth > 0 && el.clientHeight > 0) {
ro.disconnect();
callback();
}
});
ro.observe(el);
}
initWhenVisible(document.getElementById('cesiumContainer'), function () {
window.viewer = new Cesium.Viewer('cesiumContainer');
});
已经创建了 viewer,只是窗口或面板尺寸变化,直接调 resize 即可:
var ro = new ResizeObserver(function () {
viewer.resize();
viewer.scene.requestRender();
});
ro.observe(document.getElementById('cesiumContainer'));
验证
viewer.canvas.width 与容器 clientWidth × devicePixelRatio 一致;
拖动窗口改变宽度,画布跟着变化且不出现拉伸;
在弹窗中打开地图,首次显示就铺满而不是缩在角落。
顺序很重要:先让容器有尺寸,再 new Viewer。
反过来先创建再调 resize,Cesium 内部的一些缓冲区已按 0 尺寸初始化,
部分版本仍会出现画面缺失,需要重建 viewer。
经纬志(2026)。《CesiumWidget 尺寸为 0,地球建不出来》。https://www.jingweizhi.com/cookbook/cesium-widget-zero-size.html(访问日期 2026-11-03)。