Table of Contents
- Introduction to JavaFX CSS
- Basic CSS Styling
- CSS Selectors and Specificity
- Layout and Positioning
- Colors and Gradients
- Typography and Fonts
- Borders and Backgrounds
- Animations and Transitions
- Custom Controls and Skinning
- Best Practices and Patterns
Introduction to JavaFX CSS
JavaFX uses CSS for styling user interfaces, providing a powerful way to customize the appearance of applications. Unlike web CSS, JavaFX CSS has some unique properties and selectors specific to JavaFX controls.
Key Features:
- Styleable properties: Most JavaFX controls have CSS-styleable properties
- Type-safe styling: CSS properties are validated against control types
- Scene graph styling: Styles can be applied at different levels
- Runtime styling: Styles can be changed dynamically
- Custom properties: Support for custom CSS properties
Basic CSS Styling
1. Basic JavaFX Application with CSS
// BasicCssApplication.java
public class BasicCssApplication extends Application {
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(20);
root.setPadding(new Insets(20));
root.setAlignment(Pos.CENTER);
// Apply CSS to the scene
Scene scene = new Scene(root, 400, 300);
scene.getStylesheets().add(getClass().getResource("/styles/basic.css").toExternalForm());
// Create controls
Label titleLabel = new Label("JavaFX CSS Styling");
titleLabel.getStyleClass().add("title-label");
Button primaryButton = new Button("Primary Action");
primaryButton.getStyleClass().add("primary-button");
Button secondaryButton = new Button("Secondary Action");
secondaryButton.getStyleClass().add("secondary-button");
TextField textField = new TextField();
textField.setPromptText("Enter text here...");
CheckBox checkBox = new CheckBox("Enable feature");
ProgressBar progressBar = new ProgressBar(0.75);
// Add controls to layout
root.getChildren().addAll(
titleLabel, primaryButton, secondaryButton,
textField, checkBox, progressBar
);
primaryStage.setTitle("JavaFX CSS Styling Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/basic.css */
.root {
-fx-background-color: linear-gradient(to bottom, #667eea 0%, #764ba2 100%);
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
.title-label {
-fx-text-fill: white;
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 10, 0.5, 0, 2);
}
.primary-button {
-fx-background-color: #4CAF50;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 10 20;
-fx-background-radius: 5px;
-fx-border-radius: 5px;
-fx-cursor: hand;
}
.primary-button:hover {
-fx-background-color: #45a049;
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
}
.primary-button:pressed {
-fx-background-color: #3d8b40;
-fx-scale-x: 0.95;
-fx-scale-y: 0.95;
}
.secondary-button {
-fx-background-color: transparent;
-fx-text-fill: white;
-fx-border-color: white;
-fx-border-width: 2px;
-fx-border-radius: 5px;
-fx-background-radius: 5px;
-fx-padding: 8 18;
-fx-cursor: hand;
}
.secondary-button:hover {
-fx-background-color: rgba(255,255,255,0.1);
-fx-text-fill: #f0f0f0;
}
.text-field {
-fx-background-color: white;
-fx-background-radius: 5px;
-fx-border-color: #ddd;
-fx-border-radius: 5px;
-fx-padding: 8 12;
-fx-font-size: 14px;
}
.text-field:focused {
-fx-border-color: #667eea;
-fx-border-width: 2px;
-fx-effect: dropshadow(gaussian, rgba(102,126,234,0.3), 10, 0.5, 0, 0);
}
.check-box {
-fx-text-fill: white;
-fx-font-size: 14px;
}
.check-box .box {
-fx-background-color: white;
-fx-border-color: #ddd;
-fx-border-radius: 3px;
}
.check-box:selected .mark {
-fx-background-color: #4CAF50;
}
.progress-bar {
-fx-accent: #4CAF50;
-fx-background-color: rgba(255,255,255,0.2);
-fx-background-radius: 5px;
}
.progress-bar .track {
-fx-background-color: rgba(255,255,255,0.3);
-fx-background-radius: 5px;
}
.progress-bar .bar {
-fx-background-color: linear-gradient(to right, #4CAF50, #45a049);
-fx-background-radius: 5px;
}
2. Inline Styles and Dynamic Styling
// DynamicStylingExample.java
public class DynamicStylingExample extends Application {
private int clickCount = 0;
private Label counterLabel;
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(15);
root.setPadding(new Insets(20));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 500, 400);
scene.getStylesheets().add(getClass().getResource("/styles/dynamic.css").toExternalForm());
// Title with inline style
Label title = new Label("Dynamic Styling Demo");
title.setStyle("-fx-font-size: 28px; -fx-text-fill: #2c3e50; -fx-font-weight: bold;");
// Counter label
counterLabel = new Label("Clicks: 0");
counterLabel.getStyleClass().add("counter-label");
// Interactive buttons
Button incrementBtn = new Button("Increment");
incrementBtn.getStyleClass().add("action-button");
incrementBtn.setOnAction(e -> incrementCounter());
Button resetBtn = new Button("Reset");
resetBtn.getStyleClass().add("reset-button");
resetBtn.setOnAction(e -> resetCounter());
// Style toggle buttons
ToggleButton darkModeToggle = new ToggleButton("Dark Mode");
darkModeToggle.getStyleClass().add("toggle-button");
darkModeToggle.selectedProperty().addListener((obs, oldVal, newVal) -> {
toggleDarkMode(scene, newVal);
});
// Color picker for dynamic styling
ColorPicker colorPicker = new ColorPicker(Color.BLUE);
colorPicker.getStyleClass().add("color-picker");
colorPicker.setOnAction(e -> {
updateButtonColor(incrementBtn, colorPicker.getValue());
});
// Progress indicator that changes with clicks
ProgressIndicator progress = new ProgressIndicator(0);
progress.getStyleClass().add("progress-indicator");
// Layout
HBox buttonBox = new HBox(10, incrementBtn, resetBtn);
buttonBox.setAlignment(Pos.CENTER);
root.getChildren().addAll(title, counterLabel, buttonBox, darkModeToggle, colorPicker, progress);
primaryStage.setTitle("Dynamic CSS Styling");
primaryStage.setScene(scene);
primaryStage.show();
}
private void incrementCounter() {
clickCount++;
updateCounterDisplay();
updateProgressAnimation();
}
private void resetCounter() {
clickCount = 0;
updateCounterDisplay();
updateProgressAnimation();
}
private void updateCounterDisplay() {
counterLabel.setText("Clicks: " + clickCount);
// Dynamic style based on count
if (clickCount > 10) {
counterLabel.setStyle("-fx-text-fill: #e74c3c; -fx-font-weight: bold;");
} else if (clickCount > 5) {
counterLabel.setStyle("-fx-text-fill: #f39c12; -fx-font-weight: bold;");
} else {
counterLabel.setStyle("-fx-text-fill: #2c3e50; -fx-font-weight: normal;");
}
}
private void updateProgressAnimation() {
double progress = Math.min(clickCount / 20.0, 1.0);
// This would update a progress bar in a real implementation
}
private void toggleDarkMode(Scene scene, boolean darkMode) {
if (darkMode) {
scene.getStylesheets().add(getClass().getResource("/styles/dark-theme.css").toExternalForm());
} else {
scene.getStylesheets().remove(getClass().getResource("/styles/dark-theme.css").toExternalForm());
}
}
private void updateButtonColor(Button button, Color color) {
String hexColor = String.format("#%02X%02X%02X",
(int) (color.getRed() * 255),
(int) (color.getGreen() * 255),
(int) (color.getBlue() * 255));
button.setStyle("-fx-background-color: " + hexColor + "; -fx-text-fill: white;");
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/dynamic.css */
.root {
-fx-background-color: #ecf0f1;
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
.counter-label {
-fx-font-size: 18px;
-fx-text-fill: #2c3e50;
-fx-font-weight: bold;
}
.action-button {
-fx-background-color: #3498db;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 10 20;
-fx-background-radius: 25px;
-fx-border-radius: 25px;
-fx-cursor: hand;
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.3), 10, 0.5, 0, 2);
-fx-transition: all 0.3s;
}
.action-button:hover {
-fx-background-color: #2980b9;
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.5), 15, 0.5, 0, 4);
}
.reset-button {
-fx-background-color: #e74c3c;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 10 20;
-fx-background-radius: 25px;
-fx-border-radius: 25px;
-fx-cursor: hand;
}
.reset-button:hover {
-fx-background-color: #c0392b;
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
}
.toggle-button {
-fx-background-color: #9b59b6;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-padding: 8 16;
-fx-background-radius: 5px;
-fx-cursor: hand;
}
.toggle-button:selected {
-fx-background-color: #8e44ad;
-fx-text-fill: #ecf0f1;
}
.color-picker {
-fx-background-color: white;
-fx-border-color: #bdc3c7;
-fx-border-radius: 5px;
-fx-padding: 5;
}
.progress-indicator {
-fx-progress-color: #3498db;
}
/* styles/dark-theme.css */
.root {
-fx-background-color: #2c3e50;
}
.counter-label {
-fx-text-fill: #ecf0f1;
}
.action-button {
-fx-background-color: #34495e;
-fx-text-fill: #ecf0f1;
}
.action-button:hover {
-fx-background-color: #3d566e;
}
CSS Selectors and Specificity
1. Advanced Selector Examples
// SelectorExample.java
public class SelectorExample extends Application {
@Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
root.setPadding(new Insets(20));
root.setHgap(15);
root.setVgap(15);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 600, 500);
scene.getStylesheets().add(getClass().getResource("/styles/selectors.css").toExternalForm());
// Different types of buttons with various selectors
Button btnDefault = new Button("Default Button");
Button btnPrimary = new Button("Primary Button");
btnPrimary.getStyleClass().add("primary");
Button btnDanger = new Button("Danger Button");
btnDanger.getStyleClass().addAll("btn", "danger");
Button btnSuccess = new Button("Success Button");
btnSuccess.getStyleClass().addAll("btn", "success");
Button btnLarge = new Button("Large Button");
btnLarge.getStyleClass().addAll("btn", "large");
Button btnDisabled = new Button("Disabled Button");
btnDisabled.setDisable(true);
// Text fields with different states
TextField normalField = new TextField();
normalField.setPromptText("Normal field");
TextField focusedField = new TextField();
focusedField.setPromptText("Will be focused");
TextField errorField = new TextField();
errorField.setPromptText("Error state");
errorField.getStyleClass().add("error");
// Checkboxes and radio buttons
CheckBox check1 = new CheckBox("Standard Checkbox");
CheckBox check2 = new CheckBox("Custom Checkbox");
check2.getStyleClass().add("custom-check");
ToggleGroup group = new ToggleGroup();
RadioButton radio1 = new RadioButton("Option 1");
radio1.setToggleGroup(group);
RadioButton radio2 = new RadioButton("Option 2");
radio2.setToggleGroup(group);
radio2.getStyleClass().add("custom-radio");
// Special container with ID
VBox specialContainer = new VBox(10);
specialContainer.setId("special-container");
specialContainer.getChildren().addAll(
new Label("Special Container"),
new Button("Container Button")
);
// Layout
root.add(btnDefault, 0, 0);
root.add(btnPrimary, 1, 0);
root.add(btnDanger, 0, 1);
root.add(btnSuccess, 1, 1);
root.add(btnLarge, 0, 2);
root.add(btnDisabled, 1, 2);
root.add(normalField, 2, 0);
root.add(focusedField, 2, 1);
root.add(errorField, 2, 2);
root.add(check1, 0, 3);
root.add(check2, 1, 3);
root.add(radio1, 0, 4);
root.add(radio2, 1, 4);
root.add(specialContainer, 2, 3, 1, 2);
// Programmatically focus a field to demonstrate :focused selector
Platform.runLater(focusedField::requestFocus);
primaryStage.setTitle("CSS Selectors Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/selectors.css */
/* Type Selector - applies to all buttons */
.button {
-fx-background-color: #bdc3c7;
-fx-text-fill: #2c3e50;
-fx-padding: 8 16;
-fx-background-radius: 4px;
-fx-cursor: hand;
-fx-font-size: 12px;
}
/* Class Selector - applies to elements with class "primary" */
.primary {
-fx-background-color: #3498db;
-fx-text-fill: white;
-fx-font-weight: bold;
}
/* Multiple Class Selector - applies to elements with both "btn" and "danger" classes */
.btn.danger {
-fx-background-color: #e74c3c;
-fx-text-fill: white;
-fx-font-weight: bold;
}
.btn.success {
-fx-background-color: #2ecc71;
-fx-text-fill: white;
-fx-font-weight: bold;
}
.btn.large {
-fx-font-size: 16px;
-fx-padding: 12 24;
}
/* Pseudo-class Selector - disabled state */
.button:disabled {
-fx-background-color: #ecf0f1;
-fx-text-fill: #bdc3c7;
-fx-cursor: default;
}
/* Hover state for buttons */
.button:hover {
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
}
/* Focused state */
.text-field:focused {
-fx-border-color: #3498db;
-fx-border-width: 2px;
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.3), 10, 0.5, 0, 0);
}
/* Class-based styling for text fields */
.text-field.error {
-fx-border-color: #e74c3c;
-fx-background-color: #fadbd8;
}
/* ID Selector - very specific */
#special-container {
-fx-background-color: #34495e;
-fx-padding: 15;
-fx-background-radius: 8px;
-fx-border-color: #3498db;
-fx-border-width: 2px;
-fx-border-radius: 8px;
}
/* Child Selector - buttons inside #special-container */
#special-container .button {
-fx-background-color: #3498db;
-fx-text-fill: white;
}
/* Custom checkbox styling */
.check-box.custom-check .box {
-fx-background-color: #ecf0f1;
-fx-border-color: #3498db;
-fx-border-width: 2px;
-fx-border-radius: 3px;
}
.check-box.custom-check:selected .box {
-fx-background-color: #3498db;
}
.check-box.custom-check:selected .mark {
-fx-background-color: white;
}
/* Custom radio button styling */
.radio-button.custom-radio .radio {
-fx-background-color: #ecf0f1;
-fx-border-color: #9b59b6;
-fx-border-width: 2px;
-fx-border-radius: 50%;
}
.radio-button.custom-radio:selected .radio {
-fx-background-color: #9b59b6;
}
.radio-button.custom-radio:selected .dot {
-fx-background-color: white;
}
/* Adjacent sibling selector simulation */
/* Note: JavaFX CSS doesn't support adjacent sibling selectors like + */
/* We use class combinations instead */
/* First-child simulation */
.grid-pane > .button:first-child {
-fx-background-color: #f1c40f;
}
/* nth-child simulation using classes */
/* This would need to be handled programmatically in Java */
/* Attribute selector simulation */
.text-field[promptText*="Error"] {
-fx-border-color: #e74c3c;
}
Layout and Positioning
1. Advanced Layout Styling
// LayoutStylingExample.java
public class LayoutStylingExample extends Application {
@Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add(getClass().getResource("/styles/layout.css").toExternalForm());
// Header
HBox header = createHeader();
root.setTop(header);
// Sidebar
VBox sidebar = createSidebar();
root.setLeft(sidebar);
// Main content
ScrollPane mainContent = createMainContent();
root.setCenter(mainContent);
// Footer
HBox footer = createFooter();
root.setBottom(footer);
primaryStage.setTitle("Advanced Layout Styling");
primaryStage.setScene(scene);
primaryStage.show();
}
private HBox createHeader() {
HBox header = new HBox();
header.getStyleClass().add("header");
Label logo = new Label("Dashboard");
logo.getStyleClass().add("logo");
HBox nav = new HBox(20);
nav.getStyleClass().add("navigation");
Button[] navButtons = {
createNavButton("Home"),
createNavButton("Dashboard"),
createNavButton("Analytics"),
createNavButton("Settings")
};
nav.getChildren().addAll(navButtons);
HBox userArea = new HBox(10);
userArea.getStyleClass().add("user-area");
userArea.setAlignment(Pos.CENTER_RIGHT);
Label userName = new Label("John Doe");
userName.getStyleClass().add("user-name");
Circle avatar = new Circle(20);
avatar.getStyleClass().add("avatar");
userArea.getChildren().addAll(userName, avatar);
HBox.setHgrow(nav, Priority.ALWAYS);
header.getChildren().addAll(logo, nav, userArea);
return header;
}
private Button createNavButton(String text) {
Button btn = new Button(text);
btn.getStyleClass().add("nav-button");
return btn;
}
private VBox createSidebar() {
VBox sidebar = new VBox();
sidebar.getStyleClass().add("sidebar");
String[] menuItems = {
"Overview", "Users", "Products", "Orders",
"Inventory", "Reports", "Integrations", "Settings"
};
for (String item : menuItems) {
Button menuBtn = new Button(item);
menuBtn.getStyleClass().add("menu-button");
menuBtn.setMaxWidth(Double.MAX_VALUE);
sidebar.getChildren().add(menuBtn);
}
return sidebar;
}
private ScrollPane createMainContent() {
VBox content = new VBox(20);
content.getStyleClass().add("main-content");
content.setPadding(new Insets(20));
// Stats cards
HBox statsRow = new HBox(15);
statsRow.getStyleClass().add("stats-row");
VBox[] statCards = {
createStatCard("Total Users", "1,234", "#3498db", "users-icon"),
createStatCard("Revenue", "$45,678", "#2ecc71", "revenue-icon"),
createStatCard("Orders", "567", "#e74c3c", "orders-icon"),
createStatCard("Growth", "+12.5%", "#f39c12", "growth-icon")
};
statsRow.getChildren().addAll(statCards);
// Charts section
VBox chartsSection = new VBox(10);
chartsSection.getStyleClass().add("charts-section");
Label chartsTitle = new Label("Analytics");
chartsTitle.getStyleClass().add("section-title");
HBox chartsRow = new HBox(15);
VBox chart1 = createChartPlaceholder("Sales Trend");
VBox chart2 = createChartPlaceholder("User Activity");
chartsRow.getChildren().addAll(chart1, chart2);
chartsSection.getChildren().addAll(chartsTitle, chartsRow);
content.getChildren().addAll(statsRow, chartsSection);
ScrollPane scrollPane = new ScrollPane(content);
scrollPane.getStyleClass().add("scroll-pane");
scrollPane.setFitToWidth(true);
return scrollPane;
}
private VBox createStatCard(String title, String value, String color, String iconClass) {
VBox card = new VBox(10);
card.getStyleClass().add("stat-card");
card.setStyle("-fx-border-color: " + color + ";");
HBox header = new HBox(10);
header.setAlignment(Pos.CENTER_LEFT);
Pane icon = new Pane();
icon.getStyleClass().addAll("stat-icon", iconClass);
icon.setStyle("-fx-background-color: " + color + ";");
Label titleLabel = new Label(title);
titleLabel.getStyleClass().add("stat-title");
header.getChildren().addAll(icon, titleLabel);
Label valueLabel = new Label(value);
valueLabel.getStyleClass().add("stat-value");
card.getChildren().addAll(header, valueLabel);
return card;
}
private VBox createChartPlaceholder(String title) {
VBox chart = new VBox();
chart.getStyleClass().add("chart-placeholder");
Label titleLabel = new Label(title);
titleLabel.getStyleClass().add("chart-title");
Pane chartArea = new Pane();
chartArea.getStyleClass().add("chart-area");
chart.getChildren().addAll(titleLabel, chartArea);
VBox.setVgrow(chartArea, Priority.ALWAYS);
return chart;
}
private HBox createFooter() {
HBox footer = new HBox();
footer.getStyleClass().add("footer");
Label copyright = new Label("© 2024 MyApplication. All rights reserved.");
copyright.getStyleClass().add("footer-text");
HBox links = new HBox(15);
links.setAlignment(Pos.CENTER_RIGHT);
String[] footerLinks = {"Privacy Policy", "Terms of Service", "Contact", "Help"};
for (String link : footerLinks) {
Label linkLabel = new Label(link);
linkLabel.getStyleClass().add("footer-link");
links.getChildren().add(linkLabel);
}
HBox.setHgrow(links, Priority.ALWAYS);
footer.getChildren().addAll(copyright, links);
return footer;
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/layout.css */
/* Root and general styles */
.root {
-fx-background-color: #f8f9fa;
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
/* Header Styles */
.header {
-fx-background-color: white;
-fx-padding: 15 25;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0, 0, 2);
-fx-border-color: #e9ecef;
-fx-border-width: 0 0 1 0;
}
.logo {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: #3498db;
}
.navigation {
-fx-alignment: center-left;
-fx-padding: 0 40;
}
.nav-button {
-fx-background-color: transparent;
-fx-text-fill: #6c757d;
-fx-font-size: 14px;
-fx-font-weight: 500;
-fx-padding: 8 16;
-fx-cursor: hand;
-fx-border-width: 0;
-fx-background-radius: 6px;
}
.nav-button:hover {
-fx-background-color: #e9ecef;
-fx-text-fill: #495057;
}
.nav-button:pressed {
-fx-background-color: #dee2e6;
}
.user-area {
-fx-padding: 0 10;
}
.user-name {
-fx-font-size: 14px;
-fx-text-fill: #495057;
-fx-font-weight: 500;
}
.avatar {
-fx-fill: #3498db;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 5, 0, 0, 2);
}
/* Sidebar Styles */
.sidebar {
-fx-background-color: #2c3e50;
-fx-padding: 20 0;
-fx-spacing: 5;
-fx-pref-width: 250px;
}
.menu-button {
-fx-background-color: transparent;
-fx-text-fill: #bdc3c7;
-fx-font-size: 14px;
-fx-padding: 12 25;
-fx-alignment: center-left;
-fx-cursor: hand;
-fx-border-width: 0;
-fx-background-radius: 0;
}
.menu-button:hover {
-fx-background-color: #34495e;
-fx-text-fill: #ecf0f1;
}
.menu-button:pressed {
-fx-background-color: #3498db;
-fx-text-fill: white;
}
/* Main Content Styles */
.scroll-pane {
-fx-background-color: transparent;
-fx-border-width: 0;
-fx-padding: 0;
}
.scroll-pane .viewport {
-fx-background-color: transparent;
}
.main-content {
-fx-background-color: transparent;
}
.stats-row {
-fx-alignment: center;
}
.stat-card {
-fx-background-color: white;
-fx-padding: 20;
-fx-pref-width: 200px;
-fx-pref-height: 100px;
-fx-border-width: 0 0 0 4px;
-fx-border-radius: 0;
-fx-background-radius: 8px;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0, 0, 2);
}
.stat-icon {
-fx-pref-width: 30px;
-fx-pref-height: 30px;
-fx-background-radius: 6px;
}
.stat-title {
-fx-font-size: 14px;
-fx-text-fill: #6c757d;
-fx-font-weight: 500;
}
.stat-value {
-fx-font-size: 24px;
-fx-text-fill: #2c3e50;
-fx-font-weight: bold;
}
/* Charts Section */
.charts-section {
-fx-padding: 20 0;
}
.section-title {
-fx-font-size: 20px;
-fx-text-fill: #2c3e50;
-fx-font-weight: bold;
}
.chart-placeholder {
-fx-background-color: white;
-fx-padding: 20;
-fx-pref-width: 350px;
-fx-pref-height: 250px;
-fx-background-radius: 8px;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0, 0, 2);
}
.chart-title {
-fx-font-size: 16px;
-fx-text-fill: #495057;
-fx-font-weight: 600;
}
.chart-area {
-fx-background-color: #f8f9fa;
-fx-border-color: #e9ecef;
-fx-border-width: 1px;
-fx-border-radius: 4px;
}
/* Footer Styles */
.footer {
-fx-background-color: #2c3e50;
-fx-padding: 15 25;
-fx-border-color: #34495e;
-fx-border-width: 1 0 0 0;
}
.footer-text {
-fx-text-fill: #bdc3c7;
-fx-font-size: 12px;
}
.footer-link {
-fx-text-fill: #3498db;
-fx-font-size: 12px;
-fx-cursor: hand;
}
.footer-link:hover {
-fx-text-fill: #2980b9;
-fx-underline: true;
}
Colors and Gradients
1. Advanced Color and Gradient Styling
// ColorGradientExample.java
public class ColorGradientExample extends Application {
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(20);
root.setPadding(new Insets(20));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 700, 600);
scene.getStylesheets().add(getClass().getResource("/styles/colors-gradients.css").toExternalForm());
// Title
Label title = new Label("Colors & Gradients Gallery");
title.getStyleClass().add("gallery-title");
// Solid Colors Section
Label solidColorsTitle = new Label("Solid Colors");
solidColorsTitle.getStyleClass().add("section-title");
HBox solidColors = new HBox(15);
solidColors.setAlignment(Pos.CENTER);
String[] solidColorClasses = {"color-primary", "color-secondary", "color-success",
"color-danger", "color-warning", "color-info"};
String[] solidColorNames = {"Primary", "Secondary", "Success", "Danger", "Warning", "Info"};
for (int i = 0; i < solidColorClasses.length; i++) {
VBox colorCard = createColorCard(solidColorNames[i], solidColorClasses[i], "solid");
solidColors.getChildren().add(colorCard);
}
// Gradient Section
Label gradientsTitle = new Label("Gradients");
gradientsTitle.getStyleClass().add("section-title");
HBox gradients = new HBox(15);
gradients.setAlignment(Pos.CENTER);
String[] gradientClasses = {"gradient-sunset", "gradient-ocean", "gradient-forest",
"gradient-lavender", "gradient-sunrise", "gradient-midnight"};
String[] gradientNames = {"Sunset", "Ocean", "Forest", "Lavender", "Sunrise", "Midnight"};
for (int i = 0; i < gradientClasses.length; i++) {
VBox gradientCard = createColorCard(gradientNames[i], gradientClasses[i], "gradient");
gradients.getChildren().add(gradientCard);
}
// Transparency Section
Label transparencyTitle = new Label("Transparency & Effects");
transparencyTitle.getStyleClass().add("section-title");
HBox transparency = new HBox(15);
transparency.setAlignment(Pos.CENTER);
String[] transparencyClasses = {"transparent-10", "transparent-25", "transparent-50",
"transparent-75", "blur-effect", "shadow-effect"};
String[] transparencyNames = {"10%", "25%", "50%", "75%", "Blur", "Shadow"};
for (int i = 0; i < transparencyClasses.length; i++) {
VBox transparencyCard = createColorCard(transparencyNames[i], transparencyClasses[i], "effect");
transparency.getChildren().add(transparencyCard);
}
// Color Picker Demo
Label pickerTitle = new Label("Interactive Color Picker");
pickerTitle.getStyleClass().add("section-title");
HBox colorPickerDemo = createColorPickerDemo();
root.getChildren().addAll(
title, solidColorsTitle, solidColors,
gradientsTitle, gradients,
transparencyTitle, transparency,
pickerTitle, colorPickerDemo
);
primaryStage.setTitle("Colors & Gradients");
primaryStage.setScene(scene);
primaryStage.show();
}
private VBox createColorCard(String name, String styleClass, String type) {
VBox card = new VBox(10);
card.getStyleClass().add("color-card");
card.setAlignment(Pos.CENTER);
Pane colorDisplay = new Pane();
colorDisplay.getStyleClass().addAll("color-display", styleClass);
colorDisplay.setPrefSize(80, 80);
if ("effect".equals(type)) {
colorDisplay.getStyleClass().add("effect-display");
}
Label nameLabel = new Label(name);
nameLabel.getStyleClass().add("color-name");
card.getChildren().addAll(colorDisplay, nameLabel);
return card;
}
private HBox createColorPickerDemo() {
HBox demo = new HBox(20);
demo.setAlignment(Pos.CENTER);
VBox controls = new VBox(10);
controls.setAlignment(Pos.CENTER_LEFT);
Label demoLabel = new Label("Dynamic Styling Demo");
demoLabel.getStyleClass().add("demo-label");
ColorPicker bgPicker = new ColorPicker(Color.web("#3498db"));
bgPicker.getStyleClass().add("demo-picker");
bgPicker.setPromptText("Background Color");
ColorPicker textPicker = new ColorPicker(Color.web("#2c3e50"));
textPicker.getStyleClass().add("demo-picker");
textPicker.setPromptText("Text Color");
Slider borderRadius = new Slider(0, 50, 5);
borderRadius.getStyleClass().add("demo-slider");
borderRadius.setShowTickLabels(true);
borderRadius.setShowTickMarks(true);
Label borderRadiusLabel = new Label("Border Radius: 5px");
Pane preview = new Pane();
preview.getStyleClass().add("demo-preview");
preview.setPrefSize(200, 120);
// Bind properties
bgPicker.valueProperty().addListener((obs, oldVal, newVal) -> {
String hex = toHex(newVal);
preview.setStyle("-fx-background-color: " + hex + ";");
});
textPicker.valueProperty().addListener((obs, oldVal, newVal) -> {
String hex = toHex(newVal);
demoLabel.setStyle("-fx-text-fill: " + hex + ";");
});
borderRadius.valueProperty().addListener((obs, oldVal, newVal) -> {
int radius = newVal.intValue();
preview.setStyle(preview.getStyle() + "-fx-background-radius: " + radius + "px;");
borderRadiusLabel.setText("Border Radius: " + radius + "px");
});
// Set initial style
preview.setStyle("-fx-background-color: #3498db; -fx-background-radius: 5px;");
controls.getChildren().addAll(demoLabel, bgPicker, textPicker, borderRadius, borderRadiusLabel);
demo.getChildren().addAll(controls, preview);
return demo;
}
private String toHex(Color color) {
return String.format("#%02X%02X%02X",
(int) (color.getRed() * 255),
(int) (color.getGreen() * 255),
(int) (color.getBlue() * 255));
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/colors-gradients.css */
.root {
-fx-background-color: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
.gallery-title {
-fx-text-fill: white;
-fx-font-size: 32px;
-fx-font-weight: bold;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 10, 0.5, 0, 2);
}
.section-title {
-fx-text-fill: white;
-fx-font-size: 20px;
-fx-font-weight: 600;
-fx-padding: 10 0 5 0;
}
.color-card {
-fx-background-color: rgba(255,255,255,0.1);
-fx-background-radius: 10px;
-fx-padding: 15;
-fx-border-color: rgba(255,255,255,0.2);
-fx-border-width: 1px;
-fx-border-radius: 10px;
}
.color-display {
-fx-background-radius: 8px;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.2), 5, 0.5, 0, 2);
}
.color-name {
-fx-text-fill: white;
-fx-font-size: 12px;
-fx-font-weight: 500;
}
/* Solid Colors */
.color-primary {
-fx-background-color: #3498db;
}
.color-secondary {
-fx-background-color: #95a5a6;
}
.color-success {
-fx-background-color: #2ecc71;
}
.color-danger {
-fx-background-color: #e74c3c;
}
.color-warning {
-fx-background-color: #f39c12;
}
.color-info {
-fx-background-color: #9b59b6;
}
/* Gradient Colors */
.gradient-sunset {
-fx-background-color: linear-gradient(to right, #ff6b6b, #ffa726);
}
.gradient-ocean {
-fx-background-color: linear-gradient(to right, #4facfe, #00f2fe);
}
.gradient-forest {
-fx-background-color: linear-gradient(to right, #43e97b, #38f9d7);
}
.gradient-lavender {
-fx-background-color: linear-gradient(to right, #a18cd1, #fbc2eb);
}
.gradient-sunrise {
-fx-background-color: linear-gradient(to right, #fa709a, #fee140);
}
.gradient-midnight {
-fx-background-color: linear-gradient(to right, #4c669f, #3b5998, #192f6a);
}
/* Transparency & Effects */
.transparent-10 {
-fx-background-color: rgba(52, 152, 219, 0.1);
}
.transparent-25 {
-fx-background-color: rgba(52, 152, 219, 0.25);
}
.transparent-50 {
-fx-background-color: rgba(52, 152, 219, 0.5);
}
.transparent-75 {
-fx-background-color: rgba(52, 152, 219, 0.75);
}
.blur-effect {
-fx-background-color: #3498db;
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.5), 15, 0.5, 0, 5);
}
.shadow-effect {
-fx-background-color: #3498db;
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 5);
}
.effect-display {
-fx-background-color: #3498db;
}
/* Color Picker Demo Styles */
.demo-label {
-fx-font-size: 16px;
-fx-font-weight: bold;
-fx-text-fill: #2c3e50;
}
.demo-picker {
-fx-background-color: white;
-fx-background-radius: 5px;
-fx-border-color: #bdc3c7;
-fx-border-radius: 5px;
-fx-padding: 5;
}
.demo-slider {
-fx-pref-width: 200px;
}
.demo-slider .track {
-fx-background-color: #bdc3c7;
-fx-background-radius: 2px;
}
.demo-slider .thumb {
-fx-background-color: #3498db;
-fx-background-radius: 10px;
}
.demo-preview {
-fx-background-color: #3498db;
-fx-background-radius: 5px;
-fx-border-color: rgba(255,255,255,0.3);
-fx-border-width: 2px;
-fx-border-radius: 5px;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 10, 0.5, 0, 3);
}
/* Additional Color Utilities */
.hover-glow:hover {
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.5), 20, 0.5, 0, 0);
-fx-scale-x: 1.02;
-fx-scale-y: 1.02;
}
.pulse-animation {
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.7), 20, 0.5, 0, 0);
-fx-animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.7), 20, 0.5, 0, 0);
}
50% {
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.3), 25, 0.5, 0, 0);
}
100% {
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.7), 20, 0.5, 0, 0);
}
}
/* Glass morphism effect */
.glass-effect {
-fx-background-color: rgba(255, 255, 255, 0.1);
-fx-background-radius: 15px;
-fx-border-color: rgba(255, 255, 255, 0.2);
-fx-border-width: 1px;
-fx-border-radius: 15px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.1), 10, 0.5, 0, 4);
}
.glass-effect:hover {
-fx-background-color: rgba(255, 255, 255, 0.15);
-fx-border-color: rgba(255, 255, 255, 0.3);
}
Typography and Fonts
1. Advanced Typography Styling
// TypographyExample.java
public class TypographyExample extends Application {
@Override
public void start(Stage primaryStage) {
ScrollPane root = new ScrollPane();
VBox content = new VBox(20);
content.setPadding(new Insets(20));
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().addAll(
getClass().getResource("/styles/typography.css").toExternalForm(),
"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Montserrat:wght@400;600;700&family=Open+Sans:wght@300;400;600&display=swap"
);
// Headers Section
VBox headersSection = createHeadersSection();
// Body Text Section
VBox bodyTextSection = createBodyTextSection();
// Font Weights Section
VBox fontWeightsSection = createFontWeightsSection();
// Text Effects Section
VBox textEffectsSection = createTextEffectsSection();
// Custom Fonts Section
VBox customFontsSection = createCustomFontsSection();
content.getChildren().addAll(
headersSection, bodyTextSection, fontWeightsSection,
textEffectsSection, customFontsSection
);
root.setContent(content);
root.setFitToWidth(true);
primaryStage.setTitle("Typography & Fonts");
primaryStage.setScene(scene);
primaryStage.show();
}
private VBox createHeadersSection() {
VBox section = new VBox(10);
section.getStyleClass().add("typography-section");
Label sectionTitle = new Label("Headers");
sectionTitle.getStyleClass().add("section-title");
Label h1 = new Label("Heading 1 - The Quick Brown Fox");
h1.getStyleClass().add("h1");
Label h2 = new Label("Heading 2 - The Quick Brown Fox");
h2.getStyleClass().add("h2");
Label h3 = new Label("Heading 3 - The Quick Brown Fox");
h3.getStyleClass().add("h3");
Label h4 = new Label("Heading 4 - The Quick Brown Fox");
h4.getStyleClass().add("h4");
Label h5 = new Label("Heading 5 - The Quick Brown Fox");
h5.getStyleClass().add("h5");
Label h6 = new Label("Heading 6 - The Quick Brown Fox");
h6.getStyleClass().add("h6");
section.getChildren().addAll(sectionTitle, h1, h2, h3, h4, h5, h6);
return section;
}
private VBox createBodyTextSection() {
VBox section = new VBox(10);
section.getStyleClass().add("typography-section");
Label sectionTitle = new Label("Body Text");
sectionTitle.getStyleClass().add("section-title");
Label largeText = new Label("Large Body Text - Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
largeText.getStyleClass().add("body-large");
Label normalText = new Label("Normal Body Text - Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
normalText.getStyleClass().add("body-normal");
Label smallText = new Label("Small Body Text - Ut enim ad minim veniam, quis nostrud exercitation ullamco.");
smallText.getStyleClass().add("body-small");
Label caption = new Label("Caption Text - This is a caption or helper text");
caption.getStyleClass().add("caption");
section.getChildren().addAll(sectionTitle, largeText, normalText, smallText, caption);
return section;
}
private VBox createFontWeightsSection() {
VBox section = new VBox(10);
section.getStyleClass().add("typography-section");
Label sectionTitle = new Label("Font Weights");
sectionTitle.getStyleClass().add("section-title");
String[] weights = {"light", "normal", "medium", "semibold", "bold", "black"};
String[] weightNames = {"Light (300)", "Normal (400)", "Medium (500)", "Semibold (600)", "Bold (700)", "Black (900)"};
for (int i = 0; i < weights.length; i++) {
Label weightLabel = new Label(weightNames[i] + " - The Quick Brown Fox");
weightLabel.getStyleClass().addAll("font-weight", "weight-" + weights[i]);
section.getChildren().add(weightLabel);
}
return section;
}
private VBox createTextEffectsSection() {
VBox section = new VBox(10);
section.getStyleClass().add("typography-section");
Label sectionTitle = new Label("Text Effects");
sectionTitle.getStyleClass().add("section-title");
Label shadow = new Label("Text with Shadow Effect");
shadow.getStyleClass().add("text-shadow");
Label glow = new Label("Text with Glow Effect");
glow.getStyleClass().add("text-glow");
Label outline = new Label("Text with Outline");
outline.getStyleClass().add("text-outline");
Label gradient = new Label("Gradient Text Effect");
gradient.getStyleClass().add("text-gradient");
Label reflection = new Label("Text with Reflection");
reflection.getStyleClass().add("text-reflection");
section.getChildren().addAll(sectionTitle, shadow, glow, outline, gradient, reflection);
return section;
}
private VBox createCustomFontsSection() {
VBox section = new VBox(10);
section.getStyleClass().add("typography-section");
Label sectionTitle = new Label("Custom Font Families");
sectionTitle.getStyleClass().add("section-title");
Label roboto = new Label("Roboto - The Quick Brown Fox");
roboto.getStyleClass().add("font-roboto");
Label montserrat = new Label("Montserrat - The Quick Brown Fox");
montserrat.getStyleClass().add("font-montserrat");
Label openSans = new Label("Open Sans - The Quick Brown Fox");
openSans.getStyleClass().add("font-open-sans");
Label codeFont = new Label("Monospace - System.out.println('Hello World');");
codeFont.getStyleClass().add("font-monospace");
section.getChildren().addAll(sectionTitle, roboto, montserrat, openSans, codeFont);
return section;
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/typography.css */
.root {
-fx-background-color: #f8f9fa;
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
.typography-section {
-fx-background-color: white;
-fx-padding: 20;
-fx-background-radius: 10px;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.1), 10, 0.5, 0, 2);
-fx-border-color: #e9ecef;
-fx-border-width: 1px;
-fx-border-radius: 10px;
}
.section-title {
-fx-text-fill: #2c3e50;
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-padding: 0 0 10 0;
-fx-border-color: #3498db;
-fx-border-width: 0 0 3 0;
}
/* Headers */
.h1 {
-fx-font-family: "Montserrat", "Segoe UI", sans-serif;
-fx-font-size: 48px;
-fx-font-weight: bold;
-fx-text-fill: #2c3e50;
-fx-line-spacing: 1.1;
}
.h2 {
-fx-font-family: "Montserrat", "Segoe UI", sans-serif;
-fx-font-size: 36px;
-fx-font-weight: 600;
-fx-text-fill: #2c3e50;
-fx-line-spacing: 1.2;
}
.h3 {
-fx-font-family: "Montserrat", "Segoe UI", sans-serif;
-fx-font-size: 28px;
-fx-font-weight: 600;
-fx-text-fill: #34495e;
-fx-line-spacing: 1.3;
}
.h4 {
-fx-font-size: 24px;
-fx-font-weight: 600;
-fx-text-fill: #34495e;
-fx-line-spacing: 1.3;
}
.h5 {
-fx-font-size: 20px;
-fx-font-weight: 600;
-fx-text-fill: #34495e;
-fx-line-spacing: 1.4;
}
.h6 {
-fx-font-size: 16px;
-fx-font-weight: 600;
-fx-text-fill: #34495e;
-fx-line-spacing: 1.4;
}
/* Body Text */
.body-large {
-fx-font-size: 18px;
-fx-text-fill: #495057;
-fx-line-spacing: 1.5;
}
.body-normal {
-fx-font-size: 16px;
-fx-text-fill: #495057;
-fx-line-spacing: 1.5;
}
.body-small {
-fx-font-size: 14px;
-fx-text-fill: #6c757d;
-fx-line-spacing: 1.4;
}
.caption {
-fx-font-size: 12px;
-fx-text-fill: #868e96;
-fx-font-style: italic;
}
/* Font Weights */
.font-weight {
-fx-font-size: 16px;
-fx-text-fill: #2c3e50;
}
.weight-light {
-fx-font-weight: 300;
}
.weight-normal {
-fx-font-weight: 400;
}
.weight-medium {
-fx-font-weight: 500;
}
.weight-semibold {
-fx-font-weight: 600;
}
.weight-bold {
-fx-font-weight: 700;
}
.weight-black {
-fx-font-weight: 900;
}
/* Text Effects */
.text-shadow {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: #2c3e50;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 8, 0.5, 2, 2);
}
.text-glow {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: #3498db;
-fx-effect: dropshadow(gaussian, rgba(52,152,219,0.7), 15, 0.7, 0, 0);
}
.text-outline {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: white;
-fx-effect: dropshadow(three-pass-box, black, 4, 0, 0, 0);
}
.text-gradient {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: linear-gradient(to right, #ff6b6b, #ffa726);
}
.text-reflection {
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-text-fill: #2c3e50;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 8, 0.5, 2, 2),
innershadow(gaussian, rgba(255,255,255,0.5), 0, 0, 0, 1);
}
/* Custom Font Families */
.font-roboto {
-fx-font-family: "Roboto", sans-serif;
-fx-font-size: 18px;
-fx-text-fill: #2c3e50;
}
.font-montserrat {
-fx-font-family: "Montserrat", sans-serif;
-fx-font-size: 18px;
-fx-font-weight: 600;
-fx-text-fill: #2c3e50;
}
.font-open-sans {
-fx-font-family: "Open Sans", sans-serif;
-fx-font-size: 18px;
-fx-text-fill: #2c3e50;
}
.font-monospace {
-fx-font-family: "Consolas", "Monaco", "Courier New", monospace;
-fx-font-size: 16px;
-fx-text-fill: #e74c3c;
-fx-background-color: #f8f9fa;
-fx-padding: 10;
-fx-background-radius: 5px;
-fx-border-color: #e9ecef;
-fx-border-width: 1px;
-fx-border-radius: 5px;
}
/* Text Alignment Classes */
.text-left {
-fx-text-alignment: left;
}
.text-center {
-fx-text-alignment: center;
}
.text-right {
-fx-text-alignment: right;
}
.text-justify {
-fx-text-alignment: justify;
}
/* Text Transformation */
.text-uppercase {
-fx-text-transform: uppercase;
}
.text-lowercase {
-fx-text-transform: lowercase;
}
.text-capitalize {
-fx-text-transform: capitalize;
}
/* Letter and Word Spacing */
.letter-spacing-wide {
-fx-letter-spacing: 2px;
}
.letter-spacing-tight {
-fx-letter-spacing: -1px;
}
.word-spacing-wide {
-fx-word-spacing: 8px;
}
/* Text Decoration */
.text-underline {
-fx-underline: true;
}
.text-line-through {
-fx-strikethrough: true;
}
.text-overline {
/* JavaFX doesn't support overline directly */
-fx-border-color: currentColor;
-fx-border-width: 1 0 0 0;
}
Borders and Backgrounds
1. Advanced Border and Background Styling
// BorderBackgroundExample.java
public class BorderBackgroundExample extends Application {
@Override
public void start(Stage primaryStage) {
ScrollPane root = new ScrollPane();
VBox content = new VBox(25);
content.setPadding(new Insets(25));
Scene scene = new Scene(root, 900, 700);
scene.getStylesheets().add(getClass().getResource("/styles/borders-backgrounds.css").toExternalForm());
// Border Styles Section
VBox borderSection = createBorderStylesSection();
// Border Radius Section
VBox borderRadiusSection = createBorderRadiusSection();
// Background Styles Section
VBox backgroundSection = createBackgroundStylesSection();
// Combined Effects Section
VBox combinedSection = createCombinedEffectsSection();
content.getChildren().addAll(borderSection, borderRadiusSection, backgroundSection, combinedSection);
root.setContent(content);
root.setFitToWidth(true);
primaryStage.setTitle("Borders & Backgrounds");
primaryStage.setScene(scene);
primaryStage.show();
}
private VBox createBorderStylesSection() {
VBox section = new VBox(15);
section.getStyleClass().add("demo-section");
Label sectionTitle = new Label("Border Styles");
sectionTitle.getStyleClass().add("section-title");
HBox borderExamples = new HBox(20);
borderExamples.setAlignment(Pos.CENTER);
String[] borderStyles = {
"border-solid", "border-dashed", "border-dotted",
"border-double", "border-groove", "border-ridge"
};
String[] borderNames = {
"Solid", "Dashed", "Dotted", "Double", "Groove", "Ridge"
};
for (int i = 0; i < borderStyles.length; i++) {
VBox borderExample = createBorderExample(borderNames[i], borderStyles[i]);
borderExamples.getChildren().add(borderExample);
}
section.getChildren().addAll(sectionTitle, borderExamples);
return section;
}
private VBox createBorderExample(String name, String styleClass) {
VBox example = new VBox(10);
example.setAlignment(Pos.CENTER);
Pane borderBox = new Pane();
borderBox.getStyleClass().addAll("border-box", styleClass);
borderBox.setPrefSize(100, 80);
Label nameLabel = new Label(name);
nameLabel.getStyleClass().add("example-name");
example.getChildren().addAll(borderBox, nameLabel);
return example;
}
private VBox createBorderRadiusSection() {
VBox section = new VBox(15);
section.getStyleClass().add("demo-section");
Label sectionTitle = new Label("Border Radius Variations");
sectionTitle.getStyleClass().add("section-title");
HBox radiusExamples = new HBox(20);
radiusExamples.setAlignment(Pos.CENTER);
String[] radiusStyles = {
"radius-small", "radius-medium", "radius-large",
"radius-pill", "radius-circle", "radius-custom"
};
String[] radiusNames = {
"Small (4px)", "Medium (8px)", "Large (16px)",
"Pill (25px)", "Circle", "Custom Shape"
};
for (int i = 0; i < radiusStyles.length; i++) {
VBox radiusExample = createBorderExample(radiusNames[i], radiusStyles[i]);
radiusExamples.getChildren().add(radiusExample);
}
section.getChildren().addAll(sectionTitle, radiusExamples);
return section;
}
private VBox createBackgroundStylesSection() {
VBox section = new VBox(15);
section.getStyleClass().add("demo-section");
Label sectionTitle = new Label("Background Styles");
sectionTitle.getStyleClass().add("section-title");
HBox backgroundExamples = new HBox(20);
backgroundExamples.setAlignment(Pos.CENTER);
String[] backgroundStyles = {
"bg-solid", "bg-gradient-linear", "bg-gradient-radial",
"bg-pattern", "bg-image", "bg-glass"
};
String[] backgroundNames = {
"Solid Color", "Linear Gradient", "Radial Gradient",
"Pattern", "Image", "Glass Effect"
};
for (int i = 0; i < backgroundStyles.length; i++) {
VBox bgExample = createBackgroundExample(backgroundNames[i], backgroundStyles[i]);
backgroundExamples.getChildren().add(bgExample);
}
section.getChildren().addAll(sectionTitle, backgroundExamples);
return section;
}
private VBox createBackgroundExample(String name, String styleClass) {
VBox example = new VBox(10);
example.setAlignment(Pos.CENTER);
Pane bgBox = new Pane();
bgBox.getStyleClass().addAll("background-box", styleClass);
bgBox.setPrefSize(120, 100);
Label nameLabel = new Label(name);
nameLabel.getStyleClass().add("example-name");
example.getChildren().addAll(bgBox, nameLabel);
return example;
}
private VBox createCombinedEffectsSection() {
VBox section = new VBox(15);
section.getStyleClass().add("demo-section");
Label sectionTitle = new Label("Combined Effects");
sectionTitle.getStyleClass().add("section-title");
HBox combinedExamples = new HBox(20);
combinedExamples.setAlignment(Pos.CENTER);
String[] combinedStyles = {
"effect-neomorphic", "effect-floating", "effect-embossed",
"effect-debossed", "effect-glow", "effect-shadow-deep"
};
String[] combinedNames = {
"Neomorphic", "Floating", "Embossed",
"Debossed", "Glow", "Deep Shadow"
};
for (int i = 0; i < combinedStyles.length; i++) {
VBox combinedExample = createCombinedExample(combinedNames[i], combinedStyles[i]);
combinedExamples.getChildren().add(combinedExample);
}
section.getChildren().addAll(sectionTitle, combinedExamples);
return section;
}
private VBox createCombinedExample(String name, String styleClass) {
VBox example = new VBox(10);
example.setAlignment(Pos.CENTER);
Pane effectBox = new Pane();
effectBox.getStyleClass().addAll("effect-box", styleClass);
effectBox.setPrefSize(120, 100);
Label nameLabel = new Label(name);
nameLabel.getStyleClass().add("example-name");
example.getChildren().addAll(effectBox, nameLabel);
return example;
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/borders-backgrounds.css */
.root {
-fx-background-color: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
.demo-section {
-fx-background-color: rgba(255, 255, 255, 0.95);
-fx-padding: 25;
-fx-background-radius: 15px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.1), 15, 0.5, 0, 5);
-fx-border-color: rgba(255, 255, 255, 0.2);
-fx-border-width: 1px;
-fx-border-radius: 15px;
}
.section-title {
-fx-text-fill: #2c3e50;
-fx-font-size: 28px;
-fx-font-weight: bold;
-fx-padding: 0 0 15 0;
-fx-border-color: #3498db;
-fx-border-width: 0 0 3 0;
-fx-border-radius: 0;
}
.example-name {
-fx-text-fill: #2c3e50;
-fx-font-size: 14px;
-fx-font-weight: 500;
}
/* Border Box Base Style */
.border-box {
-fx-background-color: #ecf0f1;
-fx-border-width: 3px;
-fx-border-color: #3498db;
}
/* Border Style Variations */
.border-solid {
-fx-border-style: solid;
}
.border-dashed {
-fx-border-style: dashed;
-fx-border-width: 3px;
}
.border-dotted {
-fx-border-style: dotted;
-fx-border-width: 3px;
}
.border-double {
-fx-border-style: double;
-fx-border-width: 5px;
}
.border-groove {
-fx-border-style: groove;
-fx-border-width: 5px;
-fx-border-color: #3498db #2980b9 #2980b9 #3498db;
}
.border-ridge {
-fx-border-style: ridge;
-fx-border-width: 5px;
-fx-border-color: #2980b9 #3498db #3498db #2980b9;
}
/* Border Radius Variations */
.radius-small {
-fx-background-radius: 4px;
-fx-border-radius: 4px;
}
.radius-medium {
-fx-background-radius: 8px;
-fx-border-radius: 8px;
}
.radius-large {
-fx-background-radius: 16px;
-fx-border-radius: 16px;
}
.radius-pill {
-fx-background-radius: 25px;
-fx-border-radius: 25px;
}
.radius-circle {
-fx-background-radius: 50%;
-fx-border-radius: 50%;
-fx-pref-width: 80px;
-fx-pref-height: 80px;
}
.radius-custom {
-fx-background-radius: 15px 5px 15px 5px;
-fx-border-radius: 15px 5px 15px 5px;
}
/* Background Box Base Style */
.background-box {
-fx-border-color: #bdc3c7;
-fx-border-width: 1px;
-fx-border-radius: 8px;
-fx-background-radius: 8px;
}
/* Background Style Variations */
.bg-solid {
-fx-background-color: #3498db;
}
.bg-gradient-linear {
-fx-background-color: linear-gradient(to right bottom, #667eea, #764ba2);
}
.bg-gradient-radial {
-fx-background-color: radial-gradient(center 50% 50%, radius 70%, #667eea, #764ba2);
}
.bg-pattern {
-fx-background-color: repeating-linear-gradient(
45deg,
#3498db,
#3498db 10px,
#2980b9 10px,
#2980b9 20px
);
}
.bg-image {
-fx-background-color: linear-gradient(rgba(52, 152, 219, 0.8), rgba(41, 128, 185, 0.8)),
url('https://via.placeholder.com/120x100/3498db/ffffff?text=BG+Image');
-fx-background-size: cover;
-fx-background-position: center;
}
.bg-glass {
-fx-background-color: rgba(255, 255, 255, 0.1);
-fx-border-color: rgba(255, 255, 255, 0.2);
-fx-border-width: 1px;
-fx-background-radius: 8px;
-fx-border-radius: 8px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.1), 10, 0.5, 0, 2);
}
/* Effect Box Base Style */
.effect-box {
-fx-background-color: #ecf0f1;
-fx-background-radius: 8px;
}
/* Combined Effect Variations */
.effect-neomorphic {
-fx-background-color: #ecf0f1;
-fx-background-radius: 15px;
-fx-effect: dropshadow(gaussian, #d1d9e6, 10, 0, 5, 5),
dropshadow(gaussian, #ffffff, 10, 0, -5, -5);
}
.effect-floating {
-fx-background-color: white;
-fx-background-radius: 12px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.15), 20, 0.5, 0, 8);
-fx-border-color: rgba(255, 255, 255, 0.5);
-fx-border-width: 1px;
-fx-border-radius: 12px;
}
.effect-embossed {
-fx-background-color: linear-gradient(to bottom right, #ffffff, #e0e0e0);
-fx-background-radius: 10px;
-fx-border-color: #c0c0c0 #e0e0e0 #e0e0e0 #c0c0c0;
-fx-border-width: 2px;
-fx-border-radius: 10px;
-fx-effect: innershadow(gaussian, rgba(0, 0, 0, 0.1), 5, 0.5, 1, 1);
}
.effect-debossed {
-fx-background-color: linear-gradient(to bottom right, #e0e0e0, #ffffff);
-fx-background-radius: 10px;
-fx-border-color: #e0e0e0 #c0c0c0 #c0c0c0 #e0e0e0;
-fx-border-width: 2px;
-fx-border-radius: 10px;
-fx-effect: innershadow(gaussian, rgba(0, 0, 0, 0.2), 5, 0.5, 1, 1);
}
.effect-glow {
-fx-background-color: #3498db;
-fx-background-radius: 10px;
-fx-effect: dropshadow(gaussian, rgba(52, 152, 219, 0.6), 20, 0.7, 0, 0);
-fx-border-color: rgba(255, 255, 255, 0.3);
-fx-border-width: 1px;
-fx-border-radius: 10px;
}
.effect-shadow-deep {
-fx-background-color: white;
-fx-background-radius: 10px;
-fx-effect: dropshadow(three-pass-box, rgba(0, 0, 0, 0.3), 15, 0.5, 0, 5);
-fx-border-color: #f0f0f0;
-fx-border-width: 1px;
-fx-border-radius: 10px;
}
/* Interactive Effects */
.border-box:hover, .background-box:hover, .effect-box:hover {
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
-fx-cursor: hand;
}
/* Border Width Variations */
.border-thin {
-fx-border-width: 1px;
}
.border-medium {
-fx-border-width: 3px;
}
.border-thick {
-fx-border-width: 5px;
}
.border-extra-thick {
-fx-border-width: 8px;
}
/* Border Color Variations */
.border-primary {
-fx-border-color: #3498db;
}
.border-success {
-fx-border-color: #2ecc71;
}
.border-warning {
-fx-border-color: #f39c12;
}
.border-danger {
-fx-border-color: #e74c3c;
}
/* Complex Border Examples */
.border-multi-color {
-fx-border-color: #3498db #2ecc71 #e74c3c #f39c12;
-fx-border-width: 4px;
}
.border-gradient {
-fx-border-color: linear-gradient(to right, #3498db, #2ecc71);
-fx-border-width: 4px;
}
/* Background Size and Position */
.bg-cover {
-fx-background-size: cover;
}
.bg-contain {
-fx-background-size: contain;
}
.bg-center {
-fx-background-position: center;
}
.bg-top-left {
-fx-background-position: top left;
}
/* Multiple Backgrounds */
.bg-multiple {
-fx-background-color: linear-gradient(rgba(52, 152, 219, 0.8), rgba(41, 128, 185, 0.8)),
url('pattern.png');
-fx-background-size: cover, auto;
}
Animations and Transitions
1. CSS Animations and Transitions
// AnimationExample.java
public class AnimationExample extends Application {
@Override
public void start(Stage primaryStage) {
VBox root = new VBox(20);
root.setPadding(new Insets(20));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 800, 600);
scene.getStylesheets().add(getClass().getResource("/styles/animations.css").toExternalForm());
// Title
Label title = new Label("CSS Animations & Transitions");
title.getStyleClass().add("animation-title");
// Transitions Section
VBox transitionsSection = createTransitionsSection();
// Keyframe Animations Section
VBox animationsSection = createAnimationsSection();
// Interactive Animations Section
VBox interactiveSection = createInteractiveSection();
// Loading Animations Section
VBox loadingSection = createLoadingAnimationsSection();
root.getChildren().addAll(title, transitionsSection, animationsSection, interactiveSection, loadingSection);
primaryStage.setTitle("CSS Animations");
primaryStage.setScene(scene);
primaryStage.show();
}
private VBox createTransitionsSection() {
VBox section = new VBox(15);
section.getStyleClass().add("animation-section");
Label sectionTitle = new Label("CSS Transitions");
sectionTitle.getStyleClass().add("section-title");
HBox transitions = new HBox(20);
transitions.setAlignment(Pos.CENTER);
// Color Transition
Button colorTransition = new Button("Color Transition");
colorTransition.getStyleClass().add("transition-color");
// Scale Transition
Button scaleTransition = new Button("Scale Transition");
scaleTransition.getStyleClass().add("transition-scale");
// Rotation Transition
Pane rotateBox = new Pane();
rotateBox.getStyleClass().addAll("transition-box", "transition-rotate");
rotateBox.setPrefSize(80, 80);
VBox rotateExample = new VBox(10, new Label("Rotation"), rotateBox);
rotateExample.setAlignment(Pos.CENTER);
// Opacity Transition
Pane opacityBox = new Pane();
opacityBox.getStyleClass().addAll("transition-box", "transition-opacity");
opacityBox.setPrefSize(80, 80);
VBox opacityExample = new VBox(10, new Label("Opacity"), opacityBox);
opacityExample.setAlignment(Pos.CENTER);
transitions.getChildren().addAll(colorTransition, scaleTransition, rotateExample, opacityExample);
section.getChildren().addAll(sectionTitle, transitions);
return section;
}
private VBox createAnimationsSection() {
VBox section = new VBox(15);
section.getStyleClass().add("animation-section");
Label sectionTitle = new Label("Keyframe Animations");
sectionTitle.getStyleClass().add("section-title");
HBox animations = new HBox(20);
animations.setAlignment(Pos.CENTER);
// Bounce Animation
Pane bounceBox = new Pane();
bounceBox.getStyleClass().addAll("animation-box", "animation-bounce");
bounceBox.setPrefSize(60, 60);
VBox bounceExample = new VBox(10, new Label("Bounce"), bounceBox);
bounceExample.setAlignment(Pos.CENTER);
// Pulse Animation
Pane pulseBox = new Pane();
pulseBox.getStyleClass().addAll("animation-box", "animation-pulse");
pulseBox.setPrefSize(60, 60);
VBox pulseExample = new VBox(10, new Label("Pulse"), pulseBox);
pulseExample.setAlignment(Pos.CENTER);
// Spin Animation
Pane spinBox = new Pane();
spinBox.getStyleClass().addAll("animation-box", "animation-spin");
spinBox.setPrefSize(60, 60);
VBox spinExample = new VBox(10, new Label("Spin"), spinBox);
spinExample.setAlignment(Pos.CENTER);
// Slide Animation
Pane slideBox = new Pane();
slideBox.getStyleClass().addAll("animation-box", "animation-slide");
slideBox.setPrefSize(60, 60);
VBox slideExample = new VBox(10, new Label("Slide"), slideBox);
slideExample.setAlignment(Pos.CENTER);
animations.getChildren().addAll(bounceExample, pulseExample, spinExample, slideExample);
section.getChildren().addAll(sectionTitle, animations);
return section;
}
private VBox createInteractiveSection() {
VBox section = new VBox(15);
section.getStyleClass().add("animation-section");
Label sectionTitle = new Label("Interactive Animations");
sectionTitle.getStyleClass().add("section-title");
HBox interactive = new HBox(20);
interactive.setAlignment(Pos.CENTER);
// Hover Effects
Button hoverButton = new Button("Hover Me");
hoverButton.getStyleClass().add("interactive-hover");
// Click Effects
Button clickButton = new Button("Click Me");
clickButton.getStyleClass().add("interactive-click");
// Focus Effects
TextField focusField = new TextField();
focusField.setPromptText("Focus me");
focusField.getStyleClass().add("interactive-focus");
// Drag Hint
Pane dragBox = new Pane();
dragBox.getStyleClass().addAll("interactive-box", "interactive-drag");
dragBox.setPrefSize(80, 80);
VBox dragExample = new VBox(10, new Label("Drag Hint"), dragBox);
dragExample.setAlignment(Pos.CENTER);
interactive.getChildren().addAll(hoverButton, clickButton, focusField, dragExample);
section.getChildren().addAll(sectionTitle, interactive);
return section;
}
private VBox createLoadingAnimationsSection() {
VBox section = new VBox(15);
section.getStyleClass().add("animation-section");
Label sectionTitle = new Label("Loading Animations");
sectionTitle.getStyleClass().add("section-title");
HBox loading = new HBox(30);
loading.setAlignment(Pos.CENTER);
// Spinner
Pane spinner = new Pane();
spinner.getStyleClass().add("loading-spinner");
spinner.setPrefSize(60, 60);
VBox spinnerExample = new VBox(10, new Label("Spinner"), spinner);
spinnerExample.setAlignment(Pos.CENTER);
// Progress Bar
Pane progressBar = new Pane();
progressBar.getStyleClass().add("loading-progress");
progressBar.setPrefSize(150, 20);
VBox progressExample = new VBox(10, new Label("Progress"), progressBar);
progressExample.setAlignment(Pos.CENTER);
// Pulse Dots
HBox pulseDots = new HBox(5);
pulseDots.setAlignment(Pos.CENTER);
for (int i = 0; i < 3; i++) {
Pane dot = new Pane();
dot.getStyleClass().add("loading-dot");
dot.setPrefSize(15, 15);
pulseDots.getChildren().add(dot);
}
VBox dotsExample = new VBox(10, new Label("Pulse Dots"), pulseDots);
dotsExample.setAlignment(Pos.CENTER);
loading.getChildren().addAll(spinnerExample, progressExample, dotsExample);
section.getChildren().addAll(sectionTitle, loading);
return section;
}
public static void main(String[] args) {
launch(args);
}
}
/* styles/animations.css */
.root {
-fx-background-color: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-fx-font-family: "Segoe UI", Arial, sans-serif;
}
.animation-title {
-fx-text-fill: white;
-fx-font-size: 32px;
-fx-font-weight: bold;
-fx-effect: dropshadow(gaussian, rgba(0,0,0,0.3), 10, 0.5, 0, 2);
}
.animation-section {
-fx-background-color: rgba(255, 255, 255, 0.95);
-fx-padding: 25;
-fx-background-radius: 15px;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.1), 15, 0.5, 0, 5);
-fx-border-color: rgba(255, 255, 255, 0.2);
-fx-border-width: 1px;
-fx-border-radius: 15px;
}
.section-title {
-fx-text-fill: #2c3e50;
-fx-font-size: 24px;
-fx-font-weight: bold;
-fx-padding: 0 0 15 0;
-fx-border-color: #3498db;
-fx-border-width: 0 0 3 0;
}
/* Transition Styles */
.transition-color {
-fx-background-color: #3498db;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 12 24;
-fx-background-radius: 6px;
-fx-border-radius: 6px;
-fx-cursor: hand;
-fx-transition: all 0.3s ease-in-out;
}
.transition-color:hover {
-fx-background-color: #2980b9;
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
}
.transition-scale {
-fx-background-color: #2ecc71;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 12 24;
-fx-background-radius: 6px;
-fx-border-radius: 6px;
-fx-cursor: hand;
-fx-transition: transform 0.2s ease-in-out;
}
.transition-scale:hover {
-fx-scale-x: 1.1;
-fx-scale-y: 1.1;
}
.transition-box {
-fx-background-color: #3498db;
-fx-background-radius: 8px;
}
.transition-rotate {
-fx-transition: rotate 0.5s ease-in-out;
}
.transition-rotate:hover {
-fx-rotate: 45;
}
.transition-opacity {
-fx-opacity: 1;
-fx-transition: opacity 0.5s ease-in-out;
}
.transition-opacity:hover {
-fx-opacity: 0.5;
}
/* Keyframe Animation Styles */
.animation-box {
-fx-background-color: #e74c3c;
-fx-background-radius: 8px;
}
.animation-bounce {
-fx-animation: bounce 2s infinite;
}
@keyframes bounce {
0%, 20%, 50%, 80%, 100% {
-fx-translate-y: 0;
}
40% {
-fx-translate-y: -30px;
}
60% {
-fx-translate-y: -15px;
}
}
.animation-pulse {
-fx-animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
-fx-scale-x: 1;
-fx-scale-y: 1;
-fx-opacity: 1;
}
50% {
-fx-scale-x: 1.1;
-fx-scale-y: 1.1;
-fx-opacity: 0.7;
}
100% {
-fx-scale-x: 1;
-fx-scale-y: 1;
-fx-opacity: 1;
}
}
.animation-spin {
-fx-animation: spin 3s linear infinite;
}
@keyframes spin {
from {
-fx-rotate: 0;
}
to {
-fx-rotate: 360;
}
}
.animation-slide {
-fx-animation: slide 3s ease-in-out infinite;
}
@keyframes slide {
0%, 100% {
-fx-translate-x: 0;
}
50% {
-fx-translate-x: 100px;
}
}
/* Interactive Animation Styles */
.interactive-hover {
-fx-background-color: #9b59b6;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 12 24;
-fx-background-radius: 25px;
-fx-border-radius: 25px;
-fx-cursor: hand;
-fx-transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.interactive-hover:hover {
-fx-background-color: #8e44ad;
-fx-scale-x: 1.05;
-fx-scale-y: 1.05;
-fx-effect: dropshadow(gaussian, rgba(155, 89, 182, 0.4), 15, 0.5, 0, 4);
}
.interactive-click {
-fx-background-color: #f39c12;
-fx-text-fill: white;
-fx-font-size: 14px;
-fx-font-weight: bold;
-fx-padding: 12 24;
-fx-background-radius: 6px;
-fx-border-radius: 6px;
-fx-cursor: hand;
-fx-transition: all 0.1s ease-in-out;
}
.interactive-click:pressed {
-fx-background-color: #e67e22;
-fx-scale-x: 0.95;
-fx-scale-y: 0.95;
-fx-effect: innershadow(gaussian, rgba(0, 0, 0, 0.2), 10, 0.5, 0, 2);
}
.interactive-focus {
-fx-background-color: white;
-fx-background-radius: 6px;
-fx-border-color: #bdc3c7;
-fx-border-radius: 6px;
-fx-padding: 8 12;
-fx-font-size: 14px;
-fx-transition: all 0.3s ease-in-out;
}
.interactive-focus:focused {
-fx-border-color: #3498db;
-fx-border-width: 2px;
-fx-effect: dropshadow(gaussian, rgba(52, 152, 219, 0.3), 10, 0.5, 0, 0);
-fx-scale-x: 1.02;
-fx-scale-y: 1.02;
}
.interactive-box {
-fx-background-color: #3498db;
-fx-background-radius: 8px;
-fx-cursor: hand;
}
.interactive-drag {
-fx-transition: all 0.3s ease-in-out;
}
.interactive-drag:hover {
-fx-background-color: #2980b9;
-fx-effect: dropshadow(gaussian, rgba(0, 0, 0, 0.3), 10, 0.5, 0, 5);
}
/* Loading Animation Styles */
.loading-spinner {
-fx-background-color: transparent;
-fx-border-color: #3498db #e3e3e3 #e3e3e3 #e3e3e7;
-fx-border-width: 4px;
-fx-border-radius: 50%;
-fx-animation: spinner-rotate 1s linear infinite;
}
@keyframes spinner-rotate {
0% {
-fx-rotate: 0;
}
100% {
-fx-rotate: 360;
}
}
.loading-progress {
-fx-background-color: #ecf0f1;
-fx-background-radius: 10px;
-fx-border-radius: 10px;
-fx-effect: innershadow(gaussian, rgba(0, 0, 0, 0.1), 5, 0.5, 0, 1);
}
.loading-progress:before {
-fx-background-color: #3498db;
-fx-background-radius: 10px;
-fx-pref-width: 50%;
-fx-animation: progress-loading 2s ease-in-out infinite;
}
@keyframes progress-loading {
0% {
-fx-pref-width: 0%;
}
50% {
-fx-pref-width: 100%;
}
100% {
-fx-pref-width: 0%;
}
}
.loading-dot {
-fx-background-color: #3498db;
-fx-background-radius: 50%;
-fx-animation: dot-pulse 1.5s ease-in-out infinite;
}
.loading-dot:nth-child(2) {
-fx-animation-delay: 0.2s;
}
.loading-dot:nth-child(3) {
-fx-animation-delay: 0.4s;
}
@keyframes dot-pulse {
0%, 100% {
-fx-scale-x: 1;
-fx-scale-y: 1;
-fx-opacity: 1;
}
50% {
-fx-scale-x: 1.5;
-fx-scale-y: 1.5;
-fx-opacity: 0.5;
}
}
/* Additional Animation Effects */
.fade-in {
-fx-opacity: 0;
-fx-animation: fadeIn 0.5s ease-in-out forwards;
}
@keyframes fadeIn {
from {
-fx-opacity: 0;
-fx-translate-y: 20px;
}
to {
-fx-opacity: 1;
-fx-translate-y: 0;
}
}
.slide-in-left {
-fx-translate-x: -100%;
-fx-animation: slideInLeft 0.5s ease-out forwards;
}
@keyframes slideInLeft {
to {
-fx-translate-x: 0;
}
}
.zoom-in {
-fx-scale-x: 0;
-fx-scale-y: 0;
-fx-animation: zoomIn 0.3s ease-out forwards;
}
@keyframes zoomIn {
to {
-fx-scale-x: 1;
-fx-scale-y: 1;
}
}
/* Staggered animations for multiple elements */
.stagger-item {
-fx-opacity: 0;
-fx-translate-y: 20px;
}
.stagger-item:nth-child(1) {
-fx-animation: fadeInUp 0.5s ease-out 0.1s forwards;
}
.stagger-item:nth-child(2) {
-fx-animation: fadeInUp 0.5s ease-out 0.2s forwards;
}
.stagger-item:nth-child(3) {
-fx-animation: fadeInUp 0.5s ease-out 0.3s forwards;
}
@keyframes fadeInUp {
to {
-fx-opacity: 1;
-fx-translate-y: 0;
}
}
Best Practices and Patterns
1. CSS Architecture and Organization
/* styles/theme.css */
/*
* JavaFX CSS Theme Architecture
* Organized by: Variables, Base Styles, Components, Utilities
*/
/* ===== CSS VARIABLES ===== */
.root {
/* Primary Colors */
-primary-color: #3498db;
-primary-dark: #2980b9;
-primary-light: #5dade2;
/* Secondary Colors */
-secondary-color: #2ecc71;
-secondary-dark: #27ae60;
-secondary-light: #58d68d;
/* Neutral Colors */
-text-primary: #2c3e50;
-text-secondary: #7f8c8d;
-text-muted: #95a5a6;
-bg-primary: #ffffff;
-bg-secondary: #f8f9fa;
-bg-tertiary: #e9ecef;
/* Semantic Colors */
-success-color: #2ecc71;
-warning-color: #f39c12;
-error-color: #e74c3c;
-info-color: #3498db;
/* Border Colors */
-border-color: #dee2e6;
-border-color-light: #e9ecef;
-border-color-dark: #adb5bd;
/* Shadows */
-shadow-sm: dropshadow(gaussian, rgba(0,0,0,0.05), 4, 0.5, 0, 1);
-shadow-md: dropshadow(gaussian, rgba(0,0,0,0.1), 8, 0.5, 0, 2);
-shadow-lg: dropshadow(gaussian, rgba(0,0,0,0.15), 16, 0.5, 0, 4);
-shadow-xl: dropshadow(gaussian, rgba(0,0,0,0.2), 24, 0.5, 0, 8);
/* Border Radius */
-radius-sm: 4px;
-radius-md: 8px;
-radius-lg: 12px;
-radius-xl: 16px;
-radius-pill: 25px;
-radius-circle: 50%;
/* Spacing */
-spacing-xs: 4px;
-spacing-sm: 8px;
-spacing-md: 16px;
-spacing-lg: 24px;
-spacing-xl: 32px;
/* Typography */
-font-family-primary: "Segoe UI", Arial, sans-serif;
-font-family-mono: "Consolas", "Monaco", monospace;
-font-size-xs: 12px;
-font-size-sm: 14px;
-font-size-md: 16px;
-font-size-lg: 18px;
-font-size-xl: 20px;
-font-size-2xl: 24px;
-font-size-3xl: 30px;
-font-weight-light: 300;
-font-weight-normal: 400;
-font-weight-medium: 500;
-font-weight-semibold: 600;
-font-weight-bold: 700;
/* Transitions */
-transition-fast: 0.15s ease-in-out;
-transition-normal: 0.3s ease-in-out;
-transition-slow: 0.5s ease-in-out;
}
/* ===== BASE STYLES ===== */
.root {
-fx-font-family: -font-family-primary;
-fx-background-color: -bg-primary;
-fx-text-fill: -text-primary;
}
/* ===== COMPONENT STYLES ===== */
/* Buttons */
.btn {
-fx-background-color: -bg-primary;
-fx-text-fill: -text-primary;
-fx-font-size: -font-size-sm;
-fx-font-weight: -font-weight-medium;
-fx-padding: -spacing-sm -spacing-md;
-fx-background-radius: -radius-md;
-fx-border-radius: -radius-md;
-fx-border-color: -border-color;
-fx-border-width: 1px;
-fx-cursor: hand;
-fx-transition: all -transition-fast;
}
.btn:hover {
-fx-background-color: -bg-secondary;
-fx-border-color: -border-color-dark;
}
.btn:armed {
-fx-background-color: -bg-tertiary;
-fx-scale-x: 0.98;
-fx-scale-y: 0.98;
}
/* Button Variants */
.btn-primary {
-fx-background-color: -primary-color;
-fx-text-fill: white;
-fx-border-color: -primary-color;
}
.btn-primary:hover {
-fx-background-color: -primary-dark;
-fx-border-color: -primary-dark;
}
.btn-secondary {
-fx-background-color: -secondary-color;
-fx-text-fill: white;
-fx-border-color: -secondary-color;
}
.btn-success {
-fx-background-color: -success-color;
-fx-text-fill: white;
-fx-border-color: -success-color;
}
.btn-warning {
-fx-background-color: -warning-color;
-fx-text-fill: white;
-fx-border-color: -warning-color;
}
.btn-error {
-fx-background-color: -error-color;
-fx-text-fill: white;
-fx-border-color: -error-color;
}
/* Button Sizes */
.btn-sm {
-fx-padding: -spacing-xs -spacing-sm;
-fx-font-size: -font-size-xs;
}
.btn-lg {
-fx-padding: -spacing-md -spacing-lg;
-fx-font-size: -font-size-md;
}
/* Form Controls */
.text-field, .password-field, .text-area {
-fx-background-color: -bg-primary;
-fx-border-color: -border-color;
-fx-border-width: 1px;
-fx-border-radius: -radius-md;
-fx-background-radius: -radius-md;
-fx-padding: -spacing-sm;
-fx-font-size: -font-size-sm;
-fx-transition: all -transition-fast;
}
.text-field:focused, .password-field:focused, .text-area:focused {
-fx-border-color: -primary-color;
-fx-border-width: 2px;
-fx-effect: -shadow-sm;
}
/* Cards */
.card {
-fx-background-color: -bg-primary;
-fx-background-radius: -radius-lg;
-fx-border-radius: -radius-lg;
-fx-effect: -shadow-sm;
-fx-padding: -spacing-lg;
}
.card:hover {
-fx-effect: -shadow-md;
}
/* Alerts */
.alert {
-fx-background-color: -bg-primary;
-fx-background-radius: -radius-md;
-fx-border-radius: -radius-md;
-fx-padding: -spacing-md;
-fx-border-width: 1px;
-fx-border-color: -border-color;
}
.alert-success {
-fx-border-color: -success-color;
-fx-background-color: derive(-success-color, 90%);
}
.alert-warning {
-fx-border-color: -warning-color;
-fx-background-color: derive(-warning-color, 90%);
}
.alert-error {
-fx-border-color: -error-color;
-fx-background-color: derive(-error-color, 90%);
}
.alert-info {
-fx-border-color: -info-color;
-fx-background-color: derive(-info-color, 90%);
}
/* ===== UTILITY CLASSES ===== */
/* Spacing Utilities */
.p-0 { -fx-padding: 0; }
.p-1 { -fx-padding: -spacing-xs; }
.p-2 { -fx-padding: -spacing-sm; }
.p-3 { -fx-padding: -spacing-md; }
.p-4 { -fx-padding: -spacing-lg; }
.p-5 { -fx-padding: -spacing-xl; }
.m-0 { -fx-margin: 0; }
.m-1 { -fx-margin: -spacing-xs; }
.m-2 { -fx-margin: -spacing-sm; }
.m-3 { -fx-margin: -spacing-md; }
.m-4 { -fx-margin: -spacing-lg; }
.m-5 { -fx-margin: -spacing-xl; }
/* Text Utilities */
.text-xs { -fx-font-size: -font-size-xs; }
.text-sm { -fx-font-size: -font-size-sm; }
.text-md { -fx-font-size: -font-size-md; }
.text-lg { -fx-font-size: -font-size-lg; }
.text-xl { -fx-font-size: -font-size-xl; }
.text-light { -fx-font-weight: -font-weight-light; }
.text-normal { -fx-font-weight: -font-weight-normal; }
.text-medium { -fx-font-weight: -font-weight-medium; }
.text-semibold { -fx-font-weight: -font-weight-semibold; }
.text-bold { -fx-font-weight: -font-weight-bold; }
.text-primary { -fx-text-fill: -text-primary; }
.text-secondary { -fx-text-fill: -text-secondary; }
.text-muted { -fx-text-fill: -text-muted; }
.text-left { -fx-text-alignment: left; }
.text-center { -fx-text-alignment: center; }
.text-right { -fx-text-alignment: right; }
/* Background Utilities */
.bg-primary { -fx-background-color: -bg-primary; }
.bg-secondary { -fx-background-color: -bg-secondary; }
.bg-tertiary { -fx-background-color: -bg-tertiary; }
.bg-success { -fx-background-color: -success-color; }
.bg-warning { -fx-background-color: -warning-color; }
.bg-error { -fx-background-color: -error-color; }
.bg-info { -fx-background-color: -info-color; }
/* Border Utilities */
.border { -fx-border-width: 1px; -fx-border-color: -border-color; }
.border-0 { -fx-border-width: 0; }
.border-2 { -fx-border-width: 2px; }
.border-4 { -fx-border-width: 4px; }
.border-primary { -fx-border-color: -primary-color; }
.border-success { -fx-border-color: -success-color; }
.border-warning { -fx-border-color: -warning-color; }
.border-error { -fx-border-color: -error-color; }
.rounded-sm { -fx-background-radius: -radius-sm; -fx-border-radius: -radius-sm; }
.rounded-md { -fx-background-radius: -radius-md; -fx-border-radius: -radius-md; }
.rounded-lg { -fx-background-radius: -radius-lg; -fx-border-radius: -radius-lg; }
.rounded-full { -fx-background-radius: -radius-circle; -fx-border-radius: -radius-circle; }
/* Shadow Utilities */
.shadow-sm { -fx-effect: -shadow-sm; }
.shadow-md { -fx-effect: -shadow-md; }
.shadow-lg { -fx-effect: -shadow-lg; }
.shadow-xl { -fx-effect: -shadow-xl; }
.shadow-none { -fx-effect: null; }
/* Display Utilities */
.d-block { -fx-visibility: visible; }
.d-none { -fx-visibility: hidden; }
.d-inline { /* JavaFX doesn't have inline display */ }
/* Opacity Utilities */
.opacity-0 { -fx-opacity: 0; }
.opacity-25 { -fx-opacity: 0.25; }
.opacity-50 { -fx-opacity: 0.5; }
.opacity-75 { -fx-opacity: 0.75; }
.opacity-100 { -fx-opacity: 1; }
/* ===== RESPONSIVE DESIGN ===== */
/* Note: JavaFX doesn't have media queries like web CSS */
/* Responsive behavior must be handled programmatically */
/* ===== DARK THEME ===== */
.root:dark {
-bg-primary: #1a1a1a;
-bg-secondary: #2d2d2d;
-bg-tertiary: #3d3d3d;
-text-primary: #ffffff;
-text-secondary: #b3b3b3;
-text-muted: #666666;
-border-color: #404040;
-border-color-light: #4d4d4d;
-border-color-dark: #333333;
}
/* ===== ACCESSIBILITY ===== */
/* High contrast support */
.root:high-contrast {
-primary-color: #0000ff;
-text-primary: #000000;
-border-color: #000000;
}
/* Focus indicators for keyboard navigation */
*:focus-visible {
-fx-border-color: -primary-color;
-fx-border-width: 2px;
-fx-border-radius: -radius-sm;
}
/* ===== PRINT STYLES ===== */
/* Note: JavaFX doesn't have print media queries */
/* Print-specific styles would need programmatic handling */
Conclusion
JavaFX CSS provides a powerful and flexible way to style your Java applications. Key takeaways:
- Use CSS variables for maintainable and consistent theming
- Follow a structured approach with base styles, components, and utilities
- Leverage JavaFX-specific properties for advanced styling
- Implement responsive design patterns programmatically
- Use animations and transitions to enhance user experience
- Follow accessibility best practices for inclusive design
- Organize your CSS files logically for better maintainability
- Test across different platforms to ensure consistency
By following these patterns and best practices, you can create beautiful, maintainable, and user-friendly JavaFX applications with professional-grade styling.