javafx-ui-designer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

JavaFX UI Designer — Renamer App

JavaFX UI 设计师——Renamer App

Purpose: Guide the design of visually polished, usable, and consistent JavaFX interfaces for the Renamer App. Covers layout composition, color palettes, typography, spacing systems, CSS styling, control theming, accessibility, and responsive design.
Supporting files in this directory:
  • css-control-patterns.md
    — CSS property reference + full control styling patterns (sections 7–8)
  • theming-and-motion.md
    — theming architecture, responsive design, CSS transitions (sections 9, 11–12)

目的:指导Renamer App打造视觉精致、易用且一致的JavaFX界面,涵盖布局组合、调色板、排版、间距系统、CSS样式、控件主题、可访问性及响应式设计。
本目录下的支持文件
  • css-control-patterns.md
    — CSS属性参考+完整控件样式模式(第7-8节)
  • theming-and-motion.md
    — 主题架构、响应式设计、CSS过渡效果(第9、11-12节)

1. Project Context

1. 项目背景

yaml
project_name:       "Renamer App"
javafx_version:     25
java_version:       25
build_tool:         maven
css_location:       app/ui/src/main/resources/styles/     # create this dir; no CSS files exist yet
fxml_location:      app/ui/src/main/resources/fxml/
target_platform:    desktop
design_style:       modern-flat
color_scheme:       light                                  # dark/auto as future option
primary_color:      "#2196F3"                              # placeholder — replace when theme is chosen
secondary_color:    "#FF9800"
base_font_family:   "System"                               # platform default; replace with Inter/Segoe later
base_font_size:     14px
spacing_unit:       8px
min_window_width:   900
min_window_height:  600
scene_builder_used: false                                  # Guice controllers; no fx:controller attribute
existing_theme:     none                                   # Modena default — no AtlantaFX/JMetro
yaml
project_name:       "Renamer App"
javafx_version:     25
java_version:       25
build_tool:         maven
css_location:       app/ui/src/main/resources/styles/     # create this dir; no CSS files exist yet
fxml_location:      app/ui/src/main/resources/fxml/
target_platform:    desktop
design_style:       modern-flat
color_scheme:       light                                  # dark/auto as future option
primary_color:      "#2196F3"                              # placeholder — replace when theme is chosen
secondary_color:    "#FF9800"
base_font_family:   "System"                               # platform default; replace with Inter/Segoe later
base_font_size:     14px
spacing_unit:       8px
min_window_width:   900
min_window_height:  600
scene_builder_used: false                                  # Guice controllers; no fx:controller attribute
existing_theme:     none                                   # Modena default — no AtlantaFX/JMetro

Critical Project Notes

关键项目说明

  • No CSS files exist yet. All current styling is either inline (
    node.setStyle(...)
    ) or stored in
    ua.renamer.app.ui.enums.TableStyles
    . Creating the first CSS file requires adding
    scene.getStylesheets().add(...)
    in
    RenamerApplication.start()
    before the stage is shown.
  • TableStyles
    enum
    holds hardcoded inline style strings for error/ready row states. When introducing a CSS file, migrate these to style classes (
    .error
    ,
    .ready
    ) applied programmatically in
    ApplicationMainViewController
    's row factory.
  • Stylesheet load point:
    RenamerApplication
    — the
    Application
    subclass at
    ua.renamer.app.RenamerApplication
    . Launcher entry point:
    ua.renamer.app.Launcher
    .
  • CSS file location: place all stylesheets under
    app/ui/src/main/resources/styles/
    . Load order matters — see
    theming-and-motion.md
    for the correct sequence.

  • 目前无CSS文件。当前所有样式要么是内联样式(
    node.setStyle(...)
    ),要么存储在
    ua.renamer.app.ui.enums.TableStyles
    中。创建首个CSS文件需要在
    RenamerApplication.start()
    方法中,在显示舞台之前添加
    scene.getStylesheets().add(...)
  • TableStyles
    枚举
    保存了用于错误/就绪行状态的硬编码内联样式字符串。引入CSS文件时,需将这些样式迁移到样式类(
    .error
    ,
    .ready
    ),并在
    ApplicationMainViewController
    的行工厂中以编程方式应用。
  • 样式表加载点
    RenamerApplication
    ——位于
    ua.renamer.app.RenamerApplication
    Application
    子类。启动入口点:
    ua.renamer.app.Launcher
  • CSS文件位置:将所有样式表放在
    app/ui/src/main/resources/styles/
    下。加载顺序很重要——请查看
    theming-and-motion.md
    获取正确顺序。

2. Design Philosophy

2. 设计理念

Apply these principles in order of priority:
Clarity first — Every element should communicate its purpose immediately. Avoid decorative complexity that obscures function. Use whitespace generously to let content breathe.
Consistency — Establish a design system (colors, spacing, typography scale) and apply it uniformly. A consistent interface builds trust and reduces cognitive load. Define tokens once in CSS looked-up colors on
.root
and reference them everywhere.
Hierarchy — Guide the user's eye through size, weight, color contrast, and spatial grouping. Primary actions should be visually prominent; secondary actions should be visually subdued.
Feedback — Every interactive element should respond to user interaction. JavaFX CSS supports pseudo-classes (
:hover
,
:focused
,
:pressed
,
:disabled
,
:selected
) and CSS transitions (JavaFX 23+, available in this project on JavaFX 25) for smooth state changes.
Platform respect — Desktop applications have different expectations than web or mobile. Users expect keyboard navigation, focus indicators, tooltips, context menus, and window resizing. Design for these affordances.

按优先级应用以下原则:
清晰度优先——每个元素应立即传达其用途。避免会掩盖功能的装饰性复杂设计。充分利用留白让内容更易阅读。
一致性——建立设计系统(颜色、间距、排版比例)并统一应用。一致的界面能建立信任并降低认知负荷。在
.root
的CSS查找颜色中定义一次令牌,然后在各处引用。
层级结构——通过尺寸、字重、颜色对比度和空间分组引导用户视线。主要操作应在视觉上突出;次要操作应在视觉上弱化。
反馈机制——每个交互元素都应响应用户操作。JavaFX CSS支持伪类(
:hover
,
:focused
,
:pressed
,
:disabled
,
:selected
)和CSS过渡效果(JavaFX 23+,本项目基于JavaFX 25支持该特性),实现平滑的状态切换。
适配平台特性——桌面应用与网页或移动应用的预期不同。用户期望支持键盘导航、焦点指示器、工具提示、上下文菜单和窗口调整大小。设计时需考虑这些特性。

3. Layout System & Composition

3. 布局系统与组合

Layout Pane Selection Guide

布局面板选择指南

VBox — Stack children vertically with uniform spacing. Use for forms, lists of controls, sidebar menus, or any top-to-bottom flow. Set
-fx-spacing
for gaps and
-fx-alignment
for horizontal positioning.
HBox — Stack children horizontally. Use for toolbars, button rows, inline form fields.
BorderPane — Classic 5-region layout (top, bottom, left, right, center). Use as the root layout for application windows. The center region grows to fill available space. Toolbars go in top, status bars in bottom, navigation in left.
GridPane — Two-dimensional grid for structured forms and data entry layouts. Use
columnConstraints
and
rowConstraints
for sizing control. Use
hgap
/
vgap
for gutters.
StackPane — Layer children on top of each other. Use for overlays, loading indicators, or combining a background with foreground elements.
FlowPane — Wrapping flow layout. Children wrap to the next row when space runs out. Use for tag clouds, icon grids, or chip/badge collections.
TilePane — Like FlowPane but all tiles are uniform size. Good for dashboards, image galleries, or card grids.
AnchorPane — Pin children to edges with pixel offsets. Use sparingly — creates rigid layouts that don't adapt to resizing.
VBox——垂直堆叠子元素,间距均匀。适用于表单、控件列表、侧边栏菜单或任何从上到下的流布局。设置
-fx-spacing
控制间隙,
-fx-alignment
控制水平位置。
HBox——水平堆叠子元素。适用于工具栏、按钮行、内联表单字段。
BorderPane——经典的5区域布局(顶部、底部、左侧、右侧、中心)。用作应用窗口的根布局。中心区域会自动填充可用空间。工具栏放在顶部,状态栏放在底部,导航栏放在左侧。
GridPane——二维网格,适用于结构化表单和数据输入布局。使用
columnConstraints
rowConstraints
控制尺寸。使用
hgap
/
vgap
控制 gutter( gutter指网格间的间隙)。
StackPane——将子元素层叠放置。适用于覆盖层、加载指示器,或结合背景与前景元素。
FlowPane——自动换行的流式布局。当空间不足时,子元素会换行到下一行。适用于标签云、图标网格或芯片/徽章集合。
TilePane——类似FlowPane,但所有 tiles(指布局块)尺寸统一。适用于仪表板、图片画廊或卡片网格。
AnchorPane——通过像素偏移将子元素固定到边缘。谨慎使用——会创建无法自适应调整大小的刚性布局。

Layout Composition Rules

布局组合规则

Nest layouts purposefully:
BorderPane (root)
├── top: VBox
│   ├── MenuBar
│   └── HBox (toolbar)
├── left: VBox (sidebar/navigation)
├── center: StackPane
│   └── ScrollPane
│       └── VBox (content)
├── bottom: HBox (status bar)
Set grow priorities to control which children expand on resize:
java
HBox.setHgrow(contentArea, Priority.ALWAYS);
VBox.setVgrow(scrollPane, Priority.ALWAYS);
In FXML:
xml
<HBox>
    <Label text="Fixed" />
    <Region HBox.hgrow="ALWAYS" />  <!-- spacer -->
    <Button text="Action" />
</HBox>
In this project:
ApplicationMainView.fxml
uses
BorderPane
as root. Mode views use
VBox/HBox/GridPane
. Prefer constraint-based growth over
AnchorPane
. The
FxStateMirror
drives
TableView
data — do not replace the
ObservableList
binding on the table.

有目的地嵌套布局:
BorderPane (root)
├── top: VBox
│   ├── MenuBar
│   └── HBox (toolbar)
├── left: VBox (sidebar/navigation)
├── center: StackPane
│   └── ScrollPane
│       └── VBox (content)
├── bottom: HBox (status bar)
设置增长优先级以控制窗口调整大小时哪些子元素会扩展:
java
HBox.setHgrow(contentArea, Priority.ALWAYS);
VBox.setVgrow(scrollPane, Priority.ALWAYS);
在FXML中:
xml
<HBox>
    <Label text="Fixed" />
    <Region HBox.hgrow="ALWAYS" />  <!-- spacer -->
    <Button text="Action" />
</HBox>
本项目说明
ApplicationMainView.fxml
使用
BorderPane
作为根布局。模式视图使用
VBox/HBox/GridPane
。优先使用基于约束的增长方式,而非
AnchorPane
FxStateMirror
驱动
TableView
数据——请勿替换表格上的
ObservableList
绑定。

4. Color System

4. 颜色系统

Defining Colors with Looked-Up Colors

使用查找颜色定义颜色

JavaFX CSS supports "looked-up colors" — define all tokens on
.root
, reference them everywhere. This is the foundation of themeable design.
css
.root {
    /* ── Primary palette ── */
    -fx-primary:          #2196F3;
    -fx-primary-hover:    derive(-fx-primary, -10%);
    -fx-primary-pressed:  derive(-fx-primary, -20%);
    -fx-primary-subtle:   derive(-fx-primary, 85%);

    /* ── Neutral palette ── */
    -fx-bg-base:          #FFFFFF;
    -fx-bg-surface:       #F8F9FA;
    -fx-bg-elevated:      #FFFFFF;
    -fx-border-default:   #DEE2E6;
    -fx-border-subtle:    #E9ECEF;

    /* ── Text palette ── */
    -fx-text-primary:     #212529;
    -fx-text-secondary:   #6C757D;
    -fx-text-tertiary:    #ADB5BD;
    -fx-text-on-primary:  #FFFFFF;

    /* ── Semantic palette ── */
    -fx-success:          #28A745;
    -fx-warning:          #FFC107;
    -fx-danger:           #DC3545;
    -fx-info:             #17A2B8;

    /* ── Assign to built-in looked-up colors ── */
    -fx-base:             -fx-bg-base;
    -fx-background:       -fx-bg-surface;
    -fx-accent:           -fx-primary;
    -fx-focus-color:      derive(-fx-primary, 40%);
    -fx-faint-focus-color: transparent;
}
JavaFX CSS支持“查找颜色”——在
.root
上定义所有令牌,然后在各处引用。这是可主题化设计的基础。
css
.root {
    /* ── Primary palette ── */
    -fx-primary:          #2196F3;
    -fx-primary-hover:    derive(-fx-primary, -10%);
    -fx-primary-pressed:  derive(-fx-primary, -20%);
    -fx-primary-subtle:   derive(-fx-primary, 85%);

    /* ── Neutral palette ── */
    -fx-bg-base:          #FFFFFF;
    -fx-bg-surface:       #F8F9FA;
    -fx-bg-elevated:      #FFFFFF;
    -fx-border-default:   #DEE2E6;
    -fx-border-subtle:    #E9ECEF;

    /* ── Text palette ── */
    -fx-text-primary:     #212529;
    -fx-text-secondary:   #6C757D;
    -fx-text-tertiary:    #ADB5BD;
    -fx-text-on-primary:  #FFFFFF;

    /* ── Semantic palette ── */
    -fx-success:          #28A745;
    -fx-warning:          #FFC107;
    -fx-danger:           #DC3545;
    -fx-info:             #17A2B8;

    /* ── Assign to built-in looked-up colors ── */
    -fx-base:             -fx-bg-base;
    -fx-background:       -fx-bg-surface;
    -fx-accent:           -fx-primary;
    -fx-focus-color:      derive(-fx-primary, 40%);
    -fx-faint-focus-color: transparent;
}

The
derive()
and
ladder()
Functions

derive()
ladder()
函数

derive(color, percentage)
— Brightens (positive %) or darkens (negative %) a color. Use to create hover/pressed states from a single base color without manually picking shades.
ladder(color, stop1, stop2, ...)
— Chooses a color based on the brightness of the first argument. Extremely useful for making text automatically adapt to its background:
css
.label {
    -fx-text-fill: ladder(-fx-background,
        -fx-text-on-primary 49%,
        -fx-text-primary     50%
    );
}
derive(color, percentage)
——提亮(正百分比)或加深(负百分比)颜色。用于从单一基础颜色创建悬停/按下状态,无需手动选择色调。
ladder(color, stop1, stop2, ...)
——根据第一个参数的亮度选择颜色。非常适合让文本自动适应其背景:
css
.label {
    -fx-text-fill: ladder(-fx-background,
        -fx-text-on-primary 49%,
        -fx-text-primary     50%
    );
}

Color Contrast Guidelines

颜色对比度指南

  • Body text: at least 4.5:1 contrast ratio (WCAG AA)
  • Large text (18px+ or 14px+ bold): at least 3:1 contrast ratio
  • Use
    derive()
    to generate accessible hover/pressed states from base colors
  • Test palette in both light and dark contexts if supporting both themes
  • 正文文本:对比度至少为4.5:1(WCAG AA标准)
  • 大文本(18px+或14px+粗体):对比度至少为3:1
  • 使用
    derive()
    从基础颜色生成符合可访问性要求的悬停/按下状态
  • 如果支持双主题,需在浅色和深色环境下测试调色板

Anti-Patterns

反模式

  • Never hardcode hex colors directly on controls — always reference looked-up color tokens
  • Avoid pure black (
    #000000
    ) on pure white (
    #FFFFFF
    ) — use slightly tinted neutrals
  • Avoid more than 3–4 distinct hues — rely on shades/tints of a few base colors

  • 切勿在控件上直接硬编码十六进制颜色——始终引用查找颜色令牌
  • 避免在纯白(
    #FFFFFF
    )背景上使用纯黑(
    #000000
    )——使用略带色调的中性色
  • 避免使用超过3-4种不同色调——依赖少数基础颜色的深浅/色调变化

5. Typography

5. 排版

Font Loading

字体加载

java
// Load before scene creation
Font.loadFont(getClass().getResourceAsStream("/fonts/Inter-Regular.ttf"), 14);
Font.loadFont(getClass().getResourceAsStream("/fonts/Inter-Bold.ttf"), 14);
css
@font-face {
    font-family: 'Inter';
    src: url('/fonts/Inter-Regular.ttf');
}
java
// Load before scene creation
Font.loadFont(getClass().getResourceAsStream("/fonts/Inter-Regular.ttf"), 14);
Font.loadFont(getClass().getResourceAsStream("/fonts/Inter-Bold.ttf"), 14);
css
@font-face {
    font-family: 'Inter';
    src: url('/fonts/Inter-Regular.ttf');
}

Type Scale

字体比例

Define on
.root
and apply via style classes. 1.25 ratio (Major Third) for harmonious sizing:
css
.root {
    -fx-font-family:      "System";
    -fx-font-size:        14px;

    /* ── Type scale (1.25 ratio) ── */
    -fx-font-size-xs:     10px;
    -fx-font-size-sm:     12px;
    -fx-font-size-base:   14px;
    -fx-font-size-md:     16px;
    -fx-font-size-lg:     18px;
    -fx-font-size-xl:     22px;
    -fx-font-size-2xl:    28px;
    -fx-font-size-3xl:    34px;
}

.h1 {
    -fx-font-size: -fx-font-size-3xl;
    -fx-font-weight: bold;
    -fx-text-fill: -fx-text-primary;
}

.h2 {
    -fx-font-size: -fx-font-size-2xl;
    -fx-font-weight: bold;
    -fx-text-fill: -fx-text-primary;
}

.h3 {
    -fx-font-size: -fx-font-size-xl;
    -fx-font-weight: 600;
    -fx-text-fill: -fx-text-primary;
}

.subtitle {
    -fx-font-size: -fx-font-size-md;
    -fx-text-fill: -fx-text-secondary;
}

.caption {
    -fx-font-size: -fx-font-size-xs;
    -fx-text-fill: -fx-text-tertiary;
}

.monospace {
    -fx-font-family: "JetBrains Mono", "Consolas", monospace;
}
.root
上定义并通过样式类应用。使用1.25比例(大三度)实现和谐的尺寸层级:
css
.root {
    -fx-font-family:      "System";
    -fx-font-size:        14px;

    /* ── Type scale (1.25 ratio) ── */
    -fx-font-size-xs:     10px;
    -fx-font-size-sm:     12px;
    -fx-font-size-base:   14px;
    -fx-font-size-md:     16px;
    -fx-font-size-lg:     18px;
    -fx-font-size-xl:     22px;
    -fx-font-size-2xl:    28px;
    -fx-font-size-3xl:    34px;
}

.h1 {
    -fx-font-size: -fx-font-size-3xl;
    -fx-font-weight: bold;
    -fx-text-fill: -fx-text-primary;
}

.h2 {
    -fx-font-size: -fx-font-size-2xl;
    -fx-font-weight: bold;
    -fx-text-fill: -fx-text-primary;
}

.h3 {
    -fx-font-size: -fx-font-size-xl;
    -fx-font-weight: 600;
    -fx-text-fill: -fx-text-primary;
}

.subtitle {
    -fx-font-size: -fx-font-size-md;
    -fx-text-fill: -fx-text-secondary;
}

.caption {
    -fx-font-size: -fx-font-size-xs;
    -fx-text-fill: -fx-text-tertiary;
}

.monospace {
    -fx-font-family: "JetBrains Mono", "Consolas", monospace;
}

Typography Best Practices

排版最佳实践

  • Set
    -fx-font-size
    on
    .root
    to establish the base — all em-relative sizes scale from it
  • Use no more than 2 font families (one for UI, one for code/data)
  • Limit font weights to regular (400) and bold (700); semi-bold (600) for subheadings
  • JavaFX text properties:
    -fx-font-family
    ,
    -fx-font-size
    ,
    -fx-font-weight
    ,
    -fx-font-style
    ,
    -fx-text-fill
    ,
    -fx-text-alignment
    ,
    -fx-line-spacing

  • .root
    上设置
    -fx-font-size
    以建立基础——所有相对em尺寸都以此为基准缩放
  • 使用不超过2种字体(一种用于UI,一种用于代码/数据)
  • 限制字重为常规(400)和粗体(700);半粗体(600)用于副标题
  • JavaFX文本属性:
    -fx-font-family
    ,
    -fx-font-size
    ,
    -fx-font-weight
    ,
    -fx-font-style
    ,
    -fx-text-fill
    ,
    -fx-text-alignment
    ,
    -fx-line-spacing

6. Spacing & Sizing System

6. 间距与尺寸系统

Spacing Scale

间距比例

Use 8px as base unit. Define as looked-up values on
.root
:
css
.root {
    /* ── Spacing scale (8px base) ── */
    -fx-spacing-xs:   4px;
    -fx-spacing-sm:   8px;
    -fx-spacing-md:   12px;
    -fx-spacing-lg:   16px;
    -fx-spacing-xl:   24px;
    -fx-spacing-2xl:  32px;
    -fx-spacing-3xl:  48px;
}
Apply via style classes or directly:
css
.card {
    -fx-padding: -fx-spacing-lg;
    -fx-spacing: -fx-spacing-md;
}
以8px为基础单位。在
.root
上定义为查找值:
css
.root {
    /* ── Spacing scale (8px base) ── */
    -fx-spacing-xs:   4px;
    -fx-spacing-sm:   8px;
    -fx-spacing-md:   12px;
    -fx-spacing-lg:   16px;
    -fx-spacing-xl:   24px;
    -fx-spacing-2xl:  32px;
    -fx-spacing-3xl:  48px;
}
通过样式类或直接应用:
css
.card {
    -fx-padding: -fx-spacing-lg;
    -fx-spacing: -fx-spacing-md;
}

Sizing Controls

控件尺寸

Three constraints:
minWidth/Height
,
prefWidth/Height
,
maxWidth/Height
.
  • Set
    prefWidth/Height
    for ideal size
  • Set
    maxWidth
    to
    Infinity
    in CSS (or
    Double.MAX_VALUE
    in Java) to allow stretching
  • Use
    Region.USE_COMPUTED_SIZE
    (-1) to let JavaFX compute automatically
  • Avoid hardcoding pixel sizes unless the element truly must be fixed
css
.stretch-button {
    -fx-max-width: Infinity;
}

.sidebar {
    -fx-pref-width: 240px;
    -fx-min-width: 200px;
    -fx-max-width: 280px;
}
三个约束:
minWidth/Height
,
prefWidth/Height
,
maxWidth/Height
  • 设置
    prefWidth/Height
    为理想尺寸
  • 在CSS中设置
    maxWidth
    Infinity
    (或Java中的
    Double.MAX_VALUE
    )以允许拉伸
  • 使用
    Region.USE_COMPUTED_SIZE
    (-1)让JavaFX自动计算
  • 除非元素确实需要固定尺寸,否则避免硬编码像素尺寸
css
.stretch-button {
    -fx-max-width: Infinity;
}

.sidebar {
    -fx-pref-width: 240px;
    -fx-min-width: 200px;
    -fx-max-width: 280px;
}

The Box Model in JavaFX

JavaFX中的盒模型

Every
Region
is painted bottom to top:
┌─────────────────────────────────────┐
│           background-color          │
│  ┌───────────────────────────────┐  │  ← background-insets
│  │         border-color          │  │
│  │  ┌─────────────────────────┐  │  │  ← border-width + border-insets
│  │  │        padding          │  │  │
│  │  │  ┌───────────────────┐  │  │  │  ← padding
│  │  │  │    CONTENT AREA   │  │  │  │
│  │  │  └───────────────────┘  │  │  │
│  │  └─────────────────────────┘  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘
Multiple backgrounds can be layered with comma-separated values for depth effects:
css
.card-elevated {
    -fx-background-color:
        derive(-fx-border-default, -5%),   /* outer shadow layer */
        -fx-border-default,                 /* border layer */
        -fx-bg-elevated;                    /* content background */
    -fx-background-insets: -1, 0, 1;
    -fx-background-radius:  9,  8, 7;
}

每个
Region
从下到上绘制:
┌─────────────────────────────────────┐
│           background-color          │
│  ┌───────────────────────────────┐  │  ← background-insets
│  │         border-color          │  │
│  │  ┌─────────────────────────┐  │  │  ← border-width + border-insets
│  │  │        padding          │  │  │
│  │  │  ┌───────────────────┐  │  │  │  ← padding
│  │  │  │    CONTENT AREA   │  │  │  │
│  │  │  └───────────────────┘  │  │  │
│  │  └─────────────────────────┘  │  │
│  └───────────────────────────────┘  │
└─────────────────────────────────────┘
可以使用逗号分隔的值设置多层背景以实现深度效果:
css
.card-elevated {
    -fx-background-color:
        derive(-fx-border-default, -5%),   /* outer shadow layer */
        -fx-border-default,                 /* border layer */
        -fx-bg-elevated;                    /* content background */
    -fx-background-insets: -1, 0, 1;
    -fx-background-radius:  9,  8, 7;
}

10. Accessibility & Usability

10. 可访问性与可用性

Focus Indicators

焦点指示器

Never remove focus indicators entirely. Style them to match your design:
css
.button:focused {
    -fx-border-color: -fx-primary;
    -fx-border-width: 2px;
}
Override global focus appearance on
.root
:
css
.root {
    -fx-focus-color: derive(-fx-primary, 20%);
    -fx-faint-focus-color: transparent;  /* removes outer glow */
}
切勿完全移除焦点指示器。根据设计风格设置其样式:
css
.button:focused {
    -fx-border-color: -fx-primary;
    -fx-border-width: 2px;
}
.root
上覆盖全局焦点外观:
css
.root {
    -fx-focus-color: derive(-fx-primary, 20%);
    -fx-faint-focus-color: transparent;  /* removes outer glow */
}

Keyboard Navigation

键盘导航

  • All interactive controls must be reachable via Tab / Shift+Tab
  • Use
    focusTraversable="true"
    on custom interactive nodes
  • Group related controls so Tab order is logical (top-to-bottom, left-to-right)
  • Provide mnemonics:
    _Save
    creates Alt+S shortcut
  • Use
    accelerator
    properties for keyboard shortcuts
  • 所有交互控件必须可通过Tab/Shift+Tab访问
  • 在自定义交互节点上设置
    focusTraversable="true"
  • 对相关控件进行分组,使Tab顺序符合逻辑(从上到下,从左到右)
  • 提供助记符:
    _Save
    创建Alt+S快捷键
  • 使用
    accelerator
    属性设置键盘快捷键

Tooltips

工具提示

Add tooltips to icon-only buttons and controls whose purpose isn't immediately obvious:
css
.tooltip {
    -fx-background-color: -fx-text-primary;
    -fx-text-fill: -fx-bg-base;
    -fx-font-size: -fx-font-size-sm;
    -fx-background-radius: 4px;
    -fx-padding: 4px 8px;
}
Existing pattern: controllers create
Tooltip
in Java via
control.setTooltip(new Tooltip(...))
. The CSS
.tooltip { }
rule styles them globally without changing any Java code.
为仅含图标的按钮和用途不明确的控件添加工具提示:
css
.tooltip {
    -fx-background-color: -fx-text-primary;
    -fx-text-fill: -fx-bg-base;
    -fx-font-size: -fx-font-size-sm;
    -fx-background-radius: 4px;
    -fx-padding: 4px 8px;
}
现有模式:控制器通过Java代码创建
Tooltip
,即
control.setTooltip(new Tooltip(...))
。CSS中的
.tooltip { }
规则可全局设置其样式,无需修改任何Java代码。

Minimum Target Sizes

最小目标尺寸

Interactive elements should have a minimum clickable area of 32×32 pixels:
css
.icon-button {
    -fx-min-width: 36px;
    -fx-min-height: 36px;
    -fx-padding: 8px;
}
交互元素的最小可点击区域应为32×32像素:
css
.icon-button {
    -fx-min-width: 36px;
    -fx-min-height: 36px;
    -fx-padding: 8px;
}

Color Accessibility

颜色可访问性

  • Don't convey information through color alone — combine with icons, text, or patterns
  • Test color palettes for colorblind accessibility (protanopia, deuteranopia, tritanopia)
  • Error states must have both color change AND an icon/text indicator

  • 不要仅通过颜色传达信息——结合图标、文本或图案
  • 测试调色板的色盲友好性(红色盲、绿色盲、蓝色盲)
  • 错误状态必须同时改变颜色并添加图标/文本指示器

13. Design Audit Checklist

13. 设计审核清单

Color & Contrast

颜色与对比度

  • All colors come from looked-up color tokens defined on
    .root
  • No hardcoded hex colors on individual controls
  • Text has sufficient contrast against its background (4.5:1 minimum)
  • Color is not the sole indicator of state (error, success, etc.)
  • Hover and pressed states are visually distinct from default state
  • 所有颜色均来自
    .root
    上定义的查找颜色令牌
  • 单个控件上无硬编码十六进制颜色
  • 文本与背景的对比度足够(最小4.5:1)
  • 颜色不是状态(错误、成功等)的唯一指示器
  • 悬停和按下状态与默认状态在视觉上有明显区别

Typography

排版

  • A single base font size is set on
    .root
  • A consistent type scale is used (no arbitrary font sizes)
  • No more than 2 font families in use
  • Text truncation is handled gracefully (
    -fx-text-overrun: ellipsis
    )
  • Long text wraps or scrolls where appropriate
  • .root
    上设置了单一基础字体大小
  • 使用了一致的字体比例(无任意字体大小)
  • 使用的字体不超过2种
  • 文本截断处理得当(
    -fx-text-overrun: ellipsis
  • 长文本在适当位置换行或滚动

Spacing & Layout

间距与布局

  • Consistent spacing scale is applied (not arbitrary padding values)
  • Visual grouping through spacing: related items are closer, groups are separated
  • Content doesn't touch container edges (adequate padding on all regions)
  • Layout adapts when window is resized (no overlap, no hidden content)
  • Minimum window size is set and prevents broken layouts
  • 应用了一致的间距比例(无任意内边距值)
  • 通过间距实现视觉分组:相关元素间距更近,组与组之间分隔开
  • 内容未接触容器边缘(所有区域都有足够的内边距)
  • 窗口调整大小时布局能自适应(无重叠、无隐藏内容)
  • 设置了最小窗口尺寸,防止布局损坏

Interactivity

交互性

  • All interactive elements have
    :hover
    state
  • Focus indicators are visible and styled appropriately
  • Disabled states are visually distinct (reduced opacity)
  • Clickable items use hand cursor (
    -fx-cursor: hand
    )
  • Interactive targets are at least 32×32px
  • Tooltips on icon-only buttons
  • 所有交互元素都有
    :hover
    状态
  • 焦点指示器可见且样式合适
  • 禁用状态在视觉上有明显区别(降低透明度)
  • 可点击元素使用手型光标(
    -fx-cursor: hand
  • 交互目标尺寸至少为32×32px
  • 仅含图标的按钮有工具提示

Consistency

一致性

  • All buttons of the same type look identical
  • Form fields have uniform height, border radius, and padding
  • Spacing between form labels and fields is uniform
  • Card/panel styling is consistent across all views
  • One primary action style per view (visual hierarchy is clear)

  • 同一类型的所有按钮外观相同
  • 表单字段的高度、边框半径和内边距统一
  • 表单标签与字段之间的间距统一
  • 所有视图中的卡片/面板样式一致
  • 每个视图只有一种主要操作样式(视觉层级清晰)

14. Common Patterns & Anti-Patterns

14. 常见模式与反模式

Patterns (Do This)

推荐模式(应遵循)

Token-based design — Define all visual values (colors, sizes, radii, spacing) as looked-up colors on
.root
. Makes themes trivial and ensures consistency.
Layered backgrounds for depth — Use multiple
-fx-background-color
values with
-fx-background-insets
to create border and shadow effects. Performs better than
-fx-effect
.
Style class composition — Give controls multiple style classes that combine:
xml
<Button styleClass="button, primary, large" text="Submit" />
css
.large { -fx-padding: 12px 24px; -fx-font-size: -fx-font-size-lg; }
CSS-only states — Use pseudo-classes and looked-up colors to express all states in CSS. Add/remove style classes for application states (
.error
,
.success
,
.loading
).
Consistent border radius — Pick 2–3 values and use them everywhere:
css
.root {
    -fx-radius-sm:   4px;
    -fx-radius-md:   8px;
    -fx-radius-lg:   12px;
    -fx-radius-full: 100px;  /* for pills and circles */
}
基于令牌的设计——在
.root
上定义所有视觉值(颜色、尺寸、圆角、间距)为查找颜色。使主题切换变得简单,并确保一致性。
分层背景实现深度——使用多个
-fx-background-color
值结合
-fx-background-insets
创建边框和阴影效果。性能优于
-fx-effect
样式类组合——为控件添加多个样式类进行组合:
xml
<Button styleClass="button, primary, large" text="Submit" />
css
.large { -fx-padding: 12px 24px; -fx-font-size: -fx-font-size-lg; }
纯CSS状态——使用伪类和查找颜色在CSS中表达所有状态。为应用状态(
.error
,
.success
,
.loading
)添加/移除样式类。
一致的边框半径——选择2-3个值并在各处使用:
css
.root {
    -fx-radius-sm:   4px;
    -fx-radius-md:   8px;
    -fx-radius-lg:   12px;
    -fx-radius-full: 100px;  /* for pills and circles */
}

Anti-Patterns (Avoid This)

反模式(应避免)

Inline styles in Java
node.setStyle("-fx-background-color: red")
creates unmaintainable, unthemeable UI. Use style classes instead.
Overriding
-fx-base
per control
— Changing
-fx-base
on individual controls cascades unpredictably through Modena's derived colors. Use specific properties instead.
-fx-effect: dropshadow(...)
everywhere
— Drop shadow effects are expensive. Use background-color layering for card borders; reserve actual effects for dialogs and popovers.
Ignoring Modena defaults — Fighting the default stylesheet causes inconsistencies. Either commit to a full custom theme that resets all controls, or work within Modena's structure.
AnchorPane
for everything
— Creates rigid, non-responsive layouts. Prefer VBox/HBox with grow priorities, BorderPane for page structure, and GridPane for forms.
Pixel-perfect fixed layouts — JavaFX runs on varying screen sizes and DPI settings. Design with flexible sizing and test at different window sizes.

Java中的内联样式——
node.setStyle("-fx-background-color: red")
会创建难以维护、无法主题化的UI。改用样式类。
为单个控件覆盖
-fx-base
——在单个控件上修改
-fx-base
会导致Modena派生颜色出现不可预测的级联变化。改用特定属性。
到处使用
-fx-effect: dropshadow(...)
——阴影效果性能开销大。使用背景颜色分层实现卡片边框;仅在对话框和弹出框中使用实际效果。
忽略Modena默认样式——与默认样式表对抗会导致不一致。要么完全自定义主题重置所有控件,要么在Modena的结构内进行设计。
所有布局都用
AnchorPane
——会创建刚性、非响应式布局。优先使用带有增长优先级的VBox/HBox,使用BorderPane构建页面结构,使用GridPane构建表单。
像素级完美的固定布局——JavaFX运行在不同的屏幕尺寸和DPI设置下。设计时应使用灵活的尺寸,并在不同窗口尺寸下测试。

Official References

官方参考