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.
- 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).
- 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
| 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>
@/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:
| 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;
}
- In FXML, elements have
fx:idattributes - In CSS, you reference these using
#fxIdValuesyntax - Example:
fx:id="albumTitleLabel"in FXML becomes#albumTitleLabelin 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;" />
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#myIdselector.- Use styleClass when multiple elements should share styling
- Use fx:id when you need to style a specific unique element
CSS Tips and Tricks
- Use Type Selectors for Consistency: Style all buttons, labels, etc. consistently with type selectors
- Use ID Selectors for Specific Elements: When a specific element needs unique styling
- Use Style Classes for Reusability: Create reusable style classes for common patterns
- Organize Your CSS: Group related styles together with comments
- Use Hover and Pressed States: Provide visual feedback for interactive elements
- Test Different States: Make sure your styles look good in all states (normal, hover, pressed, disabled)
/* =========================================================================
* 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
- Styles Not Applied: Check the CSS file path in
stylesheetsattribute. 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:
- Run the Jukebox application and notice the retro 80s theme
- Look at the color scheme: dark backgrounds, orange/amber accents, cyan highlights
- Open
application-window.cssand read through the comments at the top - Find the button styling section and see how hover/pressed states are styled
- Find the
#albumTitleLabelstyle and see how it's different from regular labels - Find where the CSS is referenced in
application-window.fxml - Try changing the primary color from
#ff8c00to#3498dband see the theme change - Try adding your own style for
#adminTitleLabeland see the change in Admin Panel
Common Pitfalls
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).
JavaFX CSS properties must start with -fx-. Using background-color instead of -fx-background-color won't work.
Very specific selectors (like .vbox > .hbox > .button:hover) can make your CSS hard to maintain and override. Start with simpler selectors.
When styling interactive elements (buttons, text fields), make sure to test normal, hover, focused, and disabled states.
Not all web CSS properties work in JavaFX. Stick to JavaFX-specific properties (-fx-*).
For ListView, TableView, and other selectable controls, always style the selected state for good user experience.
Key Takeaways
- JavaFX uses CSS with
-fx-prefixed properties - CSS files are referenced in FXML using
stylesheetsattribute - JavaFX supports type selectors (
.button), ID selectors (#myId), and style class selectors (.my-class) - Pseudo-classes (
:hover,:pressed,:focused) provide state-specific styling - Jukebox uses a retro 80s theme with dark backgrounds and vibrant accent colors
- Common JavaFX CSS properties include background-color, text-fill, font-family, padding, border
- Gradients can be used for rich button backgrounds:
linear-gradient(to bottom, #ff8c00, #e67e22) - Drop shadow effects create depth:
dropshadow(gaussian, rgba(...), distance, ...) - Always style interactive states (hover, pressed, focused, selected)
- Organize your CSS with comments and logical grouping