SuperAPI AI 工具集

responsive-layouts

前端与建站

查看项目

更新于 10-16 06:26

技能介绍

用途

该技能用于指导 Claude 在 Vaadin 25 中构建响应式布局,使 UI 能够适配不同的屏幕尺寸。在用户要求“make a layout…”等涉及响应式布局的场景时使用。

当对具体 API 细节不确定时,使用 Vaadin MCP 工具(search_vaadin_docs、get_component_java_api)查阅最新文档,并始终将 vaadin_version 设为 "25"、ui_language 设为 "java"。

设计理念

Vaadin 中的响应式意味着让 UI 最好地利用可用屏幕空间,而不只是压缩或拉伸元素。目标是针对每种视口尺寸呈现恰当的信息量和交互方式。

按投入递增,有三种策略:

  1. 在小屏幕上减少功能——隐藏次要筛选器、折叠面板。适合移动端只是偶尔访问方式的场景。
  2. 构建响应式 UI——功能相同,布局不同。使用 CSS media/container queries 与响应式组件。这是多数应用推荐的方案。
  3. 构建独立 UI——移动端与桌面端体验各自独立。只有当交互模式存在根本差异(例如基于滑动的移动端 vs 数据网格桌面端)时才值得投入。

除非有充分理由,应从策略 2 开始。

内置响应式组件

在编写自定义响应式逻辑之前,优先利用这些会自动处理适配的组件:

  • AppLayout——在小视口中抽屉自动折叠为汉堡菜单
  • Dashboard——网格布局自动随屏幕尺寸调整
  • FormLayout——根据宽度调整列数与标签位置
  • MenuBar——当项目放不下时显示溢出菜单
  • Tabs——标签溢出时出现水平滚动按钮
  • Context Menu——移动端停靠在屏幕底部
  • Dialog / Confirm Dialog——窄视口下按钮工具栏切换为垂直排列
  • CRUD——小视口下编辑器切换为覆盖层
  • Date Picker / Select——移动端覆盖层停靠到底部

CSS 媒体查询

基于视口进行响应式处理的主要工具。定义在特定视口宽度下激活的样式。

/* In your view's CSS file */
.filter-panel {
    display: flex;
}

@media (max-width: 640px) {
    .filter-panel {
        display: none;
    }
}

从 Java 应用 CSS 类名,让 CSS 处理响应式逻辑。这样能把响应式行为留在它应在的 CSS 中,而不是在服务端尝试检测屏幕尺寸。

CSS 容器查询

当响应式应基于组件所属容器的宽度而非视口时使用。适用于可调整大小的面板、出现在不同上下文中的可复用组件以及仪表盘小部件。

.sidepanel {
    container-type: inline-size;
    container-name: sidepanel;
}

.sidepanel .footer {
    display: none;
}

@container sidepanel (min-width: 400px) {
    .footer {
        display: flex;
    }
}

容器查询让组件自成一体——它们适应自身可用空间,而不是假定某个特定视口尺寸。

响应式设计的工具类(仅 Lumo)

Vaadin 的 Lumo 工具类提供类似 Tailwind CSS 的移动优先响应式系统,是无需编写自定义 CSS 即可添加响应式行为的最快方式。

注意:这些工具类仅适用于 Lumo 主题。如果使用 Aura,请改用 CSS 媒体查询或容器查询。

在 Vaadin 25 中的设置(必需):

@StyleSheet(Lumo.STYLESHEET)
@StyleSheet(Lumo.UTILITY_STYLESHEET)
@StyleSheet("styles.css")
public class Application implements AppShellConfigurator {
}

注意:Vaadin 25 不再支持通过 theme.json 加载 Lumo Utility Classes,请改用 @StyleSheet 导入。

断点(移动优先):

Breakpoint Min width Java constant prefix
(default) 0px LumoUtility.Display.FLEX etc.
Small 640px Display.Breakpoint.Small.*
Medium 768px Display.Breakpoint.Medium.*
Large 1024px Display.Breakpoint.Large.*
XLarge 1280px Display.Breakpoint.XLarge.*
XXLarge 1536px Display.Breakpoint.XXLarge.*

示例——仅在小屏幕上显示移动端工具栏:

mobileToolbar.addClassNames(
    LumoUtility.Display.FLEX,               // visible by default (mobile)
    LumoUtility.Display.Breakpoint.Small.HIDDEN  // hidden at 640px+
);

示例——在断点处从垂直布局切换为水平布局:

container.addClassNames(
    LumoUtility.Display.FLEX,
    LumoUtility.FlexDirection.COLUMN,                          // stack vertically (mobile)
    LumoUtility.FlexDirection.Breakpoint.Medium.ROW            // row at 768px+
);

工具类遵循移动优先模式:将移动端样式定义为默认,然后在更大的断点处覆盖。这与 CSS 约定一致,代码更清晰。

响应式模式

模式:可折叠筛选面板(Lumo 工具类)

桌面端显示筛选侧栏,移动端将其隐藏在切换按钮之后。

// Lumo theme only — uses LumoUtility classes
// Filter panel — hidden on mobile, shown on desktop
VerticalLayout filterPanel = new VerticalLayout();
filterPanel.addClassNames(
    LumoUtility.Display.HIDDEN,                           // hidden by default
    LumoUtility.Display.Breakpoint.Medium.FLEX             // shown at 768px+
);

// Toggle button — shown on mobile, hidden on desktop
Button filterToggle = new Button("Filters");
filterToggle.addClassNames(
    LumoUtility.Display.INLINE_FLEX,                       // shown by default
    LumoUtility.Display.Breakpoint.Medium.HIDDEN           // hidden at 768px+
);

模式:响应式卡片网格

使用 CSS Grid 实现可调整列数的卡片布局。

.card-grid {
    display: grid;
    gap: 1rem;  /* or use theme token: var(--lumo-space-m) for Lumo */
    grid-template-columns: 1fr;  /* 1 column on mobile */
}

@media (min-width: 640px) {
    .card-grid {
        grid-template-columns: repeat(2, 1fr);  /* 2 columns */
    }
}

@media (min-width: 1024px) {
    .card-grid {
        grid-template-columns: repeat(3, 1fr);  /* 3 columns */
    }
}
Div cardGrid = new Div();
cardGrid.addClassName("card-grid");
// Add Card components to cardGrid

模式:桌面侧栏 → 移动端底部面板

使用带 drawer placement 的 AppLayout。在小视口中,AppLayout 会自动将抽屉转换为覆盖层。如需完全自定义,可结合媒体查询将导航移至底部栏。

最佳实践

  • 使用 CSS 实现响应式,而非服务端检测——避免用 Page.retrieveExtendedClientDetails() 或 UI.getCurrent().getPage().addBrowserWindowResizeListener() 做布局决策。CSS media/container queries 性能更好,且不需要服务端往返。
  • 移动优先——将移动端布局定义为默认,再为更大屏幕增加复杂度。这与 Lumo 工具类断点的工作方式一致。
  • 利用内置响应式组件——AppLayout、FormLayout、Dashboard、MenuBar 已处理适配,不要重复造轮子。
  • 可复用组件优先使用容器查询——如果组件可能出现在不同宽度的容器中,容器查询能让它自适应。
  • 面向流式尺寸设计——不要针对特定设备分辨率。用户会调整浏览器大小、使用分屏和缩放。应在多种宽度下测试,而不只是“手机”和“桌面”。
  • 测试换行行为——对 HorizontalLayout 使用 setWrap(true) 或在 CSS 中使用 flex-wrap 时,验证项目在中间尺寸下也能优雅换行,而不只是目标断点处。

详细参考

关于 Lumo 工具类断点与响应式常量的完整列表,参见 references/responsive-patterns.md。