使用 Babylon.js 开发时如何通过 CSS 实现 UI 自适应
本文将介绍如何在 Babylon.js 开发中,通过预先定义的 CSS 文件实现 UI 的自适应布局,确保 UI 能够根据 Canvas 元素的尺寸动态调整。
场景描述
假设我们已经使用 HTML 和 CSS 构建了 Babylon.js 的 UI 界面,并且所有样式都定义在 CSS 文件中。现在,我们需要让这些 UI 元素能够根据 Canvas 的尺寸动态调整,以实现自适应的效果。
解决方案
1. 使用 CSS 变量(推荐)
CSS 变量(Custom Properties)是 CSS3 引入的特性,允许我们定义可动态更新的变量。通过结合 JavaScript,我们可以根据 Canvas 的尺寸动态调整 CSS 变量,从而实现 UI 的自适应。
1.1 在 CSS 文件中定义变量
首先,在 CSS 文件中定义一些变量,用于控制 UI 元素的尺寸、位置等属性。
:root {
--ui-width: 100px; /* 默认宽度 */
--ui-height: 50px; /* 默认高度 */
--ui-font-size: 16px; /* 默认字体大小 */
}
.ui-element {
width: var(--ui-width);
height: var(--ui-height);
font-size: var(--ui-font-size);
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 10px;
position: absolute;
top: 10%;
left: 10%;
}
1.2 在 JavaScript 中动态更新 CSS 变量
接下来,通过 JavaScript 监听 Canvas 的尺寸变化,并动态更新 CSS 变量。
const canvas = document.getElementById("renderCanvas");
// 监听 Canvas 尺寸变化
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
updateUIStyle(width, height);
}
});
observer.observe(canvas);
// 更新 CSS 变量
function updateUIStyle(width, height) {
const root = document.documentElement;
root.style.setProperty('--ui-width', `${width * 0.8}px`); // 80% 的 Canvas 宽度
root.style.setProperty('--ui-height', `${height * 0.1}px`); // 10% 的 Canvas 高度
root.style.setProperty('--ui-font-size', `${height * 0.02}px`); // 字体大小随高度变化
}
// 初始设置
window.addEventListener('load', () => {
updateUIStyle(canvas.width, canvas.height);
});
1.3 优点
- 代码简洁:通过 CSS 变量,可以轻松实现样式的动态调整。
- 易于维护:所有样式定义在 CSS 文件中,JavaScript 只负责更新变量。
2. 使用类名切换(备选)
如果不想使用 CSS 变量,可以通过动态添加或切换类名来实现自适应。
2.1 在 CSS 文件中定义不同尺寸的类
在 CSS 文件中定义多个类,分别对应不同的 Canvas 尺寸。
.ui-element {
background-color: rgba(255, 255, 255, 0.8);
text-align: center;
padding: 10px;
position: absolute;
top: 10%;
left: 10%;
}
/* 小尺寸 */
.ui-element.small {
width: 100px;
height: 50px;
font-size: 12px;
}
/* 中尺寸 */
.ui-element.medium {
width: 200px;
height: 100px;
font-size: 16px;
}
/* 大尺寸 */
.ui-element.large {
width: 300px;
height: 150px;
font-size: 20px;
}
2.2 在 JavaScript 中动态切换类名
根据 Canvas 的尺寸动态切换 UI 元素的类名。
const canvas = document.getElementById("renderCanvas");
const uiElement = document.querySelector('.ui-element');
// 监听 Canvas 尺寸变化
const observer = new ResizeObserver(entries => {
for (let entry of entries) {
const { width, height } = entry.contentRect;
updateUIClass(width, height);
}
});
observer.observe(canvas);
// 根据尺寸切换类名
function updateUIClass(width, height) {
if (width < 600) {
uiElement.classList.remove('medium', 'large');
uiElement.classList.add('small');
} else if (width < 1024) {
uiElement.classList.remove('small', 'large');
uiElement.classList.add('medium');
} else {
uiElement.classList.remove('small', 'medium');
uiElement.classList.add('large');
}
}
// 初始设置
window.addEventListener('load', () => {
updateUIClass(canvas.width, canvas.height);
});
2.3 优点
- 兼容性好:适用于不支持 CSS 变量的旧版浏览器。
- 灵活性高:可以通过定义多个类实现复杂的自适应逻辑。
补充一个最近开发时的案例
css文件参考:
body{
background-color:#000723;
}
canvas{
width: 100%;
height: 100%;
position:absolute;
top:0px;
left:0px;
background-color: #000723;
z-index: -100;
}
#containerSel3DIcon {
position: absolute; /* 或者使用 relative/fixed */
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
overflow: hidden;
}
.Sel3DIcon{
position: absolute;
text-align: left;
vertical-align: top;
pointer-events: auto;
cursor: pointer;
z-index: -99;
}
.Sel3DIcon img{
width: 32px;
height: 32px;
}
.Sel3DIcon span{
font-size: 18px;
color: #fff;
text-align: left;
vertical-align: top;
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.9);
}
js文件中UI自适应部分的代码参考:
function AdaptiveStyles(){
const styleSheets = document.styleSheets;
const iconSize = Math.round(canvas.height * 0.026);
const contentSize = Math.round(canvas.height * 0.016);
for (let i = 0; i < styleSheets.length; i++) {
const styleSheet = styleSheets[i];
const rules = styleSheet.cssRules;
for (let j = 0; j < rules.length; j++) {
const rule = rules[j];
if (rule.selectorText === '.Sel3DIcon img') {
console.log("img");
rule.style.width = `${iconSize}px`;
rule.style.height = `${iconSize}px`;
}else if (rule.selectorText === '.Sel3DIcon span') {
console.log("span");
rule.style.fontSize = `${contentSize}px`;
}
}
}
}
AdaptiveStyles();
window.addEventListener('resize', function() {
engine.resize();
AdaptiveStyles();
});
在该段代码中使用了模板字符串,关于模板字符串的使用方法,请参看以下链接:
模板字符串VS普通字符串:核心区别与使用场景