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.