CSS Styling

JavaFX supports CSS (Cascading Style Sheets) for styling UI components. This allows you to separate the visual appearance from the structure and behavior of your application. In the Jukebox project, CSS is used extensively to create a retro 80s-inspired theme. This cookbook section explains how CSS styling works in JavaFX, using the Jukebox project as reference.

What You'll Learn:
  • How JavaFX CSS works
  • Applying CSS to JavaFX components
  • CSS selectors in JavaFX
  • Common JavaFX CSS properties
  • Jukebox's styling approach and structure
  • Creating and applying your own styles

JavaFX CSS Overview

JavaFX uses a subset of CSS with JavaFX-specific properties. The syntax is similar to web CSS, but the properties are different (they start with -fx- instead of just the property name).

Benefits of Using CSS in JavaFX:
  • Separation of Concerns: UI structure (FXML) is separate from appearance (CSS)
  • Consistent Look: Apply the same styles to multiple components
  • Easy Maintenance: Change appearance in one place rather than in code
  • Theming: Easily switch between different visual themes
  • Reusability: Style classes can be reused across the application
JavaFX CSS vs Web CSS:
Aspect JavaFX CSS Web CSS
Property Prefix -fx-background-color background-color
Selector Syntax Similar but different selectors Standard CSS selectors
Property Names JavaFX-specific (-fx-font, -fx-padding) Standard CSS properties
Color Format Hex (#ff8c00), RGB, RGBA Same
Units Pixels, percentages, em Pixels, percentages, em, rem, etc.

Applying CSS in Jukebox

In the Jukebox project, CSS is applied in two ways:

1. Inline Stylesheet Reference in FXML

The main application window references a CSS file in its FXML:

<!-- In application-window.fxml -->

<VBox alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity"
     minHeight="-Infinity" minWidth="-Infinity" prefHeight="778.0"
     prefWidth="621.0"
     stylesheets="@/styles/application-window.css"  <!-- CSS file reference -->
     xmlns="http://javafx.com/javafx/25"
     xmlns:fx="http://javafx.com/fxml/1"
     fx:controller="jukebox.controller.ApplicationWindowController">
    <!-- ... rest of FXML ... -->
</VBox>
Inline Stylesheet Path:
  • @/styles/application-window.css - The @ symbol means classpath-relative
  • Files are stored in src/resources/styles/ which is on the classpath
  • This CSS applies to all child nodes of the VBox

2. Programmatic Stylesheet Application

You can also apply stylesheets programmatically in code:

// In Java code
Scene scene = new Scene(root, 800, 600);

// Add CSS file
scene.getStylesheets().add(
    getClass().getResource("/styles/application-window.css").toExternalForm()
);

Jukebox's CSS Structure

The Jukebox project has one main CSS file: application-window.css. Let's examine its structure:

/*
 * =============================================================================
 * 80s Jukebox Theme - Application CSS Stylesheet
 * =============================================================================
 *
 * This stylesheet defines the complete visual theme for the Jukebox application,
 * inspired by 1980s retro aesthetics with improved readability.
 *
 * Design Philosophy:
 * - Dark background with bright, vibrant accent colors (amber/orange and cyan)
 * - High contrast between text and backgrounds for readability
 * - Consistent spacing and padding throughout
 * - Glowing effects on text and borders for that classic 80s neon look
 * - Sharp, angular button designs with gradient fills
 * - Monospace (Courier New) font family to evoke vintage computer displays
 */

Color Palette in Jukebox:

CSS Selectors in JavaFX

JavaFX supports several types of CSS selectors:

JavaFX CSS Selector Types:
Selector Example Description
Type Selector .button Selects all elements of this type (all Button instances)
ID Selector #albumTitleLabel Selects the element with the specified fx:id
Style Class Selector .my-style-class Selects elements with the specified style class
Parent-Child Selector .vbox > .button Selects all buttons that are direct children of VBox
Descendant Selector .vbox .button Selects all buttons that are descendants of VBox (any level)
Pseudo-Class Selector .button:hover Selects buttons in hover state

Examples from Jukebox:

/* Type selector - applies to all buttons */
.button {
    -fx-background-color: linear-gradient(to bottom, #ff8c00, #e67e22);
    -fx-text-fill: #121212;
    /* ... */
}

/* ID selector - applies to specific element */
#albumTitleLabel {
    -fx-font-size: 28;
    -fx-font-weight: bold;
    -fx-text-fill: #00ffff;
    /* ... */
}

/* Parent-child selector */
.split-pane > *.split-pane-divider {
    -fx-background-color: #ff8c00;
    -fx-padding: 1;
}

/* Pseudo-class selector */
.button:hover {
    -fx-background-color: linear-gradient(to bottom, #ffa726, #f57c00);
    -fx-scale-x: 1.05;
    -fx-scale-y: 1.05;
}
JavaFX fx:id vs HTML id:
  • In FXML, elements have fx:id attributes
  • In CSS, you reference these using #fxIdValue syntax
  • Example: fx:id="albumTitleLabel" in FXML becomes #albumTitleLabel in CSS

Common JavaFX CSS Properties

JavaFX supports many CSS properties. Here are the most commonly used ones:

Styling Specific Components in Jukebox

Let's look at how specific components are styled in Jukebox:

Root and Container Styles

.root {
    -fx-background-color: #0a0a0a;
    -fx-border-color: #444;
    -fx-border-width: 8;
    -fx-border-style: solid;
    -fx-background-insets: 0, 1, 2;
    -fx-background-radius: 10;
}

.vbox {
    -fx-background-color: #121212;
    -fx-border-color: #555, #666;
    -fx-border-width: 2;
    -fx-border-style: solid;
    -fx-border-radius: 5;
    -fx-padding: 15;
    -fx-effect: dropshadow(gaussian, rgba(255,140,0,0.6), 20, 0, 0, 0);
}

.hbox {
    -fx-padding: 10 0 0 0;
}

Label Styles

.label {
    -fx-text-fill: #e0e0e0;
    -fx-font-family: 'Courier New';
    -fx-font-size: 16;
    -fx-font-weight: bold;
    -fx-effect: dropshadow(gaussian, rgba(0,255,255,0.5), 3, 0, 0, 0);
    -fx-background-color: #121212;
    -fx-padding: 5;
}

#albumTitleLabel {
    -fx-font-size: 28;
    -fx-font-weight: bold;
    -fx-text-fill: #00ffff;
    -fx-effect: dropshadow(gaussian, rgba(255,140,0,0.6), 8, 0, 0, 0);
    -fx-underline: true;
}

Button Styles

.button {
    -fx-background-color: linear-gradient(to bottom, #ff8c00, #e67e22);
    -fx-background-radius: 8;
    -fx-border-color: #fff, #ccc, #fff, #ccc;
    -fx-border-width: 2;
    -fx-border-radius: 8;
    -fx-border-insets: 0, 1, 2, 3;
    -fx-text-fill: #121212;
    -fx-font-family: 'Courier New';
    -fx-font-size: 14;
    -fx-font-weight: bold;
    -fx-padding: 8 16 8 16;
    -fx-effect: dropshadow(gaussian, rgba(255,255,255,0.6), 2, 0, 0, 0);
    -fx-cursor: hand;
}

.button:hover {
    -fx-background-color: linear-gradient(to bottom, #ffa726, #f57c00);
    -fx-border-color: #fff, #eee, #fff, #ddd;
    -fx-scale-x: 1.05;
    -fx-scale-y: 1.05;
    -fx-effect: dropshadow(gaussian, rgba(255,255,255,0.8), 4, 0, 0, 0);
}

.button:pressed {
    -fx-background-color: linear-gradient(to bottom, #e67e22, #d35400);
    -fx-border-color: #ccc, #aaa, #ccc, #888;
    -fx-border-insets: 1, 0, 2, 1;
    -fx-scale-x: 0.98;
    -fx-scale-y: 0.98;
    -fx-translate-y: 2;
}

TableView and ListView Styles

.table-view {
    -fx-background-color: #1e1e1e;
    -fx-border-color: #ff8c00;
    -fx-border-width: 2;
    -fx-border-radius: 5;
    -fx-background-radius: 5;
}

.table-view:focused {
    -fx-border-color: #00ffff;
    -fx-border-width: 2;
}

.table-view .column-header-background {
    -fx-background-color: #ff8c00;
}

.table-view .column-header {
    -fx-background-color: transparent;
    -fx-text-fill: #121212;
    -fx-font-family: 'Courier New';
    -fx-font-size: 14;
    -fx-font-weight: bold;
    -fx-alignment: CENTER_LEFT;
    -fx-padding: 5;
}

.table-view .table-cell {
    -fx-background-color: #1e1e1e;
    -fx-text-fill: #e0e0e0;
    -fx-font-family: 'Courier New';
    -fx-font-size: 14;
    -fx-padding: 5;
    -fx-cell-size: 25;
}

.table-view .table-row-cell:selected {
    -fx-background-color: #00ffff;
    -fx-background-insets: 0;
    -fx-text-fill: #121212;
}

.table-view .table-row-cell:hover {
    -fx-background-color: rgba(0,255,255,0.15);
}

TextField Styles

.text-field {
    -fx-background-color: #1e1e1e;
    -fx-background-radius: 3;
    -fx-border-color: #ff8c00;
    -fx-border-width: 2;
    -fx-border-radius: 3;
    -fx-text-fill: #e0e0e0;
    -fx-font-family: 'Courier New';
    -fx-font-size: 14;
    -fx-highlight-fill: rgba(0,255,255,0.2);
    -fx-highlight-text-fill: #121212;
    -fx-prompt-text-fill: rgba(255,140,0,0.5);
}

.text-field:focused {
    -fx-border-color: #00ffff;
    -fx-border-width: 2;
}

Creating Your Own Styles

Let's create a simple CSS stylesheet for your JavaFX application:

  • Step 1: Create CSS File

    Create a file at src/resources/styles/my-styles.css:

    /* My Custom Stylesheet */
    
    /* Define color scheme */
    /* Primary: #3498db (blue) */
    /* Secondary: #2ecc71 (green) */
    /* Background: #ecf0f1 (light gray) */
    /* Text: #2c3e50 (dark blue-gray) */
    
    /* Root container */
    .root {
        -fx-background-color: #ecf0f1;
    }
    
    /* Buttons */
    .button {
        -fx-background-color: #3498db;
        -fx-text-fill: white;
        -fx-font-family: 'Arial';
        -fx-font-size: 14;
        -fx-padding: 8 16 8 16;
        -fx-border-radius: 5;
        -fx-cursor: hand;
    }
    
    .button:hover {
        -fx-background-color: #2980b9;
    }
    
    .button:pressed {
        -fx-background-color: #1a5276;
    }
    
    /* Primary button (save, add) */
    .button.primary {
        -fx-background-color: #2ecc71;
    }
    
    .button.primary:hover {
        -fx-background-color: #27ae60;
    }
    
    /* Danger button (delete) */
    .button.danger {
        -fx-background-color: #e74c3c;
    }
    
    .button.danger:hover {
        -fx-background-color: #c0392b;
    }
    
    /* Labels */
    .label {
        -fx-text-fill: #2c3e50;
        -fx-font-family: 'Arial';
        -fx-font-size: 14;
    }
    
    /* Title labels */
    .label.title {
        -fx-font-size: 24;
        -fx-font-weight: bold;
        -fx-text-fill: #3498db;
    }
    
    /* Text fields */
    .text-field {
        -fx-background-color: white;
        -fx-border-color: #bdc3c7;
        -fx-border-width: 1;
        -fx-border-radius: 3;
        -fx-padding: 5;
        -fx-font-family: 'Arial';
        -fx-font-size: 14;
    }
    
    .text-field:focused {
        -fx-border-color: #3498db;
        -fx-border-width: 2;
    }
    
    /* ListView */
    .list-view {
        -fx-background-color: white;
        -fx-border-color: #bdc3c7;
        -fx-border-width: 1;
        -fx-border-radius: 3;
    }
    
    .list-cell {
        -fx-padding: 8;
        -fx-text-fill: #2c3e50;
    }
    
    .list-cell:selected {
        -fx-background-color: #3498db;
        -fx-text-fill: white;
    }
    
    .list-cell:hover {
        -fx-background-color: #d6eaf8;
    }
  • Step 2: Apply CSS to FXML

    Reference your CSS file in your FXML:

    <VBox alignment="TOP_CENTER" 
         stylesheets="@/styles/my-styles.css"
         xmlns="http://javafx.com/javafx/25"
         xmlns:fx="http://javafx.com/fxml/1">
        <!-- ... rest of FXML ... -->
    </VBox>
  • Step 3: Add Style Classes to Elements

    Add style classes to your elements:

    <Button text="Save" styleClass="primary" onAction="#handleSave" />
    <Button text="Delete" styleClass="danger" onAction="#handleDelete" />
    <Label text="Welcome" styleClass="title" />
  • Step 4: Apply Inline Styles (if needed)

    You can also apply styles directly to elements:

    <Button text="Custom" 
            style="-fx-background-color: #9b59b6; -fx-text-fill: white;" />
    
    <Label text="Important" 
           style="-fx-font-size: 18; -fx-font-weight: bold; -fx-text-fill: #e74c3c;" />
  • Style Class vs ID:
    • styleClass="my-class" - Allows multiple elements to share the same style. Multiple classes can be separated by spaces.
    • fx:id="myId" - Unique identifier for an element. Used in CSS with #myId selector.
    • Use styleClass when multiple elements should share styling
    • Use fx:id when you need to style a specific unique element

    CSS Tips and Tricks

    Best Practices for JavaFX CSS:
    1. Use Type Selectors for Consistency: Style all buttons, labels, etc. consistently with type selectors
    2. Use ID Selectors for Specific Elements: When a specific element needs unique styling
    3. Use Style Classes for Reusability: Create reusable style classes for common patterns
    4. Organize Your CSS: Group related styles together with comments
    5. Use Hover and Pressed States: Provide visual feedback for interactive elements
    6. Test Different States: Make sure your styles look good in all states (normal, hover, pressed, disabled)
    CSS Organization Example:
    /* =========================================================================
     * COLOR PALETTE
     * ========================================================================= */
    /* Primary: #3498db */
    /* Secondary: #2ecc71 */
    /* Background: #ecf0f1 */
    
    /* =========================================================================
     * ROOT AND CONTAINERS
     * ========================================================================= */
    .root { ... }
    .vbox { ... }
    .hbox { ... }
    
    /* =========================================================================
     * BUTTONS
     * ========================================================================= */
    .button { ... }
    .button:hover { ... }
    .button:pressed { ... }
    .button.primary { ... }
    .button.danger { ... }
    
    /* =========================================================================
     * LABELS
     * ========================================================================= */
    .label { ... }
    .label.title { ... }
    .label.subtitle { ... }
    
    /* =========================================================================
     * TEXT FIELDS
     * ========================================================================= */
    .text-field { ... }
    .text-field:focused { ... }

    Debugging CSS Issues

    Common CSS Problems and Solutions:
    • Styles Not Applied: Check the CSS file path in stylesheets attribute. Make sure the file is on the classpath.
    • Selector Not Matching: Use Scene Builder or check your selector syntax. Remember JavaFX uses -fx- prefix.
    • Priority Issues: More specific selectors override less specific ones. ID selectors have higher priority than class selectors.
    • Inheritance: Some properties inherit, others don't. Check the JavaFX CSS documentation.
    • Not Seeing Changes: Make sure you're running the updated version. Clean and rebuild your project.

    Try This:

    1. Run the Jukebox application and notice the retro 80s theme
    2. Look at the color scheme: dark backgrounds, orange/amber accents, cyan highlights
    3. Open application-window.css and read through the comments at the top
    4. Find the button styling section and see how hover/pressed states are styled
    5. Find the #albumTitleLabel style and see how it's different from regular labels
    6. Find where the CSS is referenced in application-window.fxml
    7. Try changing the primary color from #ff8c00 to #3498db and see the theme change
    8. Try adding your own style for #adminTitleLabel and see the change in Admin Panel

    Common Pitfalls

    Pitfall 1: Wrong CSS Path

    If your CSS file isn't loading, check the path. Use @/path/from/classpath syntax for classpath-relative paths. The file must be in a directory that's on the classpath (typically src/resources).

    Pitfall 2: Missing -fx- Prefix

    JavaFX CSS properties must start with -fx-. Using background-color instead of -fx-background-color won't work.

    Pitfall 3: Over-Specific Selectors

    Very specific selectors (like .vbox > .hbox > .button:hover) can make your CSS hard to maintain and override. Start with simpler selectors.

    Pitfall 4: Not Testing All States

    When styling interactive elements (buttons, text fields), make sure to test normal, hover, focused, and disabled states.

    Pitfall 5: Using Web CSS Properties

    Not all web CSS properties work in JavaFX. Stick to JavaFX-specific properties (-fx-*).

    Pitfall 6: Not Handling Selection States

    For ListView, TableView, and other selectable controls, always style the selected state for good user experience.

    Key Takeaways

    Related Cookbook Sections