HTML Viewport 设置
<meta name="viewport"
content="width=device-width,
initial-scale=1.0,
minimum-scale=1.0,
maximum-scale=1.0,
user-scalable=no,
viewport-fit=cover">
CSS 媒体查询适配
基于方向检测
/* 竖屏样式 */
@media screen and (orientation: portrait) {
.openclaw-container {
flex-direction: column;
}
.toolbar {
height: 50px;
width: 100%;
}
.content-area {
height: calc(100vh - 50px);
}
}
/* 横屏样式 */
@media screen and (orientation: landscape) {
.openclaw-container {
flex-direction: row;
}
.toolbar {
width: 60px;
height: 100%;
}
.content-area {
width: calc(100vw - 60px);
}
/* 横屏时可能需要调整字体大小 */
body {
font-size: 14px;
}
}
JavaScript 方向检测与处理
// 检测屏幕方向
function detectOrientation() {
const isPortrait = window.innerHeight > window.innerWidth;
const orientation = screen.orientation || {};
return {
isPortrait,
isLandscape: !isPortrait,
angle: orientation.angle || 0,
type: orientation.type || (isPortrait ? 'portrait' : 'landscape')
};
}
// 监听方向变化
function setupOrientationListeners() {
// 标准方式
if (screen.orientation) {
screen.orientation.addEventListener('change', handleOrientationChange);
}
// 回退方案
else {
window.addEventListener('resize', handleOrientationChange);
window.addEventListener('orientationchange', handleOrientationChange);
}
}
// 方向变化处理
function handleOrientationChange() {
const orientation = detectOrientation();
// 添加/移除 CSS 类
document.body.classList.toggle('portrait', orientation.isPortrait);
document.body.classList.toggle('landscape', orientation.isLandscape);
// 触发自定义事件
const event = new CustomEvent('orientationchange', {
detail: { orientation }
});
window.dispatchEvent(event);
// 更新 UI 布局
updateLayoutForOrientation(orientation);
}
// 初始化
window.addEventListener('DOMContentLoaded', () => {
setupOrientationListeners();
handleOrientationChange(); // 初始检测
});
React/Vue 适配方案
React 示例
import { useState, useEffect } from 'react';
function useOrientation() {
const [orientation, setOrientation] = useState({
isPortrait: window.innerHeight > window.innerWidth,
isLandscape: window.innerWidth > window.innerHeight
});
useEffect(() => {
const handleResize = () => {
setOrientation({
isPortrait: window.innerHeight > window.innerWidth,
isLandscape: window.innerWidth > window.innerHeight
});
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return orientation;
}
// 使用组件
function OpenClawApp() {
const { isPortrait } = useOrientation();
return (
<div className={`openclaw-app ${isPortrait ? 'portrait' : 'landscape'}`}>
{isPortrait ? (
<MobileLayout />
) : (
<DesktopLayout />
)}
</div>
);
}
响应式布局策略
Flexbox 布局适配
.openclaw-wrapper {
display: flex;
min-height: 100vh;
}
/* 竖屏:垂直排列 */
@media (orientation: portrait) {
.openclaw-wrapper {
flex-direction: column;
}
.sidebar {
width: 100%;
height: 60px;
order: 1;
}
.main-content {
flex: 1;
order: 2;
}
}
/* 横屏:水平排列 */
@media (orientation: landscape) {
.openclaw-wrapper {
flex-direction: row;
}
.sidebar {
width: 200px;
height: 100vh;
order: 1;
}
.main-content {
flex: 1;
order: 2;
}
}
特殊场景处理
键盘弹出处理(移动端)
// 检测虚拟键盘状态
function handleKeyboard() {
const originalHeight = window.innerHeight;
window.addEventListener('resize', () => {
const currentHeight = window.innerHeight;
const keyboardVisible = currentHeight < originalHeight;
if (keyboardVisible) {
// 键盘弹出时调整布局
document.body.classList.add('keyboard-open');
} else {
document.body.classList.remove('keyboard-open');
}
});
}
安全区域适配(全面屏)
/* 适配刘海屏、圆角等 */
.safe-area {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
/* 横屏时的安全区域 */
@media (orientation: landscape) {
.toolbar {
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}
}
性能优化建议
-
防抖处理

const debouncedOrientationChange = debounce(handleOrientationChange, 200); window.addEventListener('resize', debouncedOrientationChange); -
CSS 硬件加速
.transform-element { will-change: transform; transform: translateZ(0); } -
懒加载资源
// 根据方向加载不同资源 function loadOrientationAssets(orientation) { if (orientation.isLandscape) { // 加载横屏专用资源 import('./landscape-components.js'); } }
测试工具
// 开发调试工具
function orientationDebug() {
console.log({
width: window.innerWidth,
height: window.innerHeight,
orientation: detectOrientation(),
devicePixelRatio: window.devicePixelRatio
});
}
// 模拟不同设备
function simulateDevice(deviceType) {
const devices = {
iphone: { width: 375, height: 812 },
ipad: { width: 1024, height: 1366 }
};
// 在开发环境中模拟
if (process.env.NODE_ENV === 'development') {
Object.assign(window, {
innerWidth: devices[deviceType].width,
innerHeight: devices[deviceType].height
});
handleOrientationChange();
}
}
注意事项
- 保持功能一致性:横竖屏下核心功能应保持一致
- 状态保持:切换方向时应保持用户操作状态
- 动画过渡:方向切换时添加合适的过渡动画
- 测试覆盖:在所有目标设备上测试横竖屏表现
- 后备方案:提供用户手动锁定方向的选项
// 锁定方向(如果应用支持)
function lockOrientation(mode) {
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock(mode)
.catch(err => console.log('Orientation lock failed:', err));
}
}
这个方案覆盖了 OpenClaw 横竖屏适配的主要方面,可根据具体需求进行调整和扩展。
版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。