CSS styles
The look of JavaFX controls is set with cascading style sheets: the same CSS as on the web, but with its own property names, all starting with -fx-. The standard theme is called Modena; your stylesheet is applied on top of it and changes only what it mentions. This keeps the styling separate from both the markup and the code.
The stylesheet
Create a file next to the FXML:
/* src/main/resources/com/example/notes/styles.css */
.root {
-fx-font-family: "Segoe UI", sans-serif;
-fx-font-size: 14px;
-fx-background-color: #f7f7fb;
}
.header {
-fx-font-size: 22px;
-fx-font-weight: bold;
-fx-text-fill: #2d3a8c;
}
.button {
-fx-background-color: #4f6bed;
-fx-text-fill: white;
-fx-background-radius: 6;
-fx-padding: 6 14;
}
.button:hover {
-fx-background-color: #3b55d1;
}
.button:disabled {
-fx-opacity: 0.5;
}
.danger {
-fx-background-color: #d9534f;
}
.danger:hover {
-fx-background-color: #c9302c;
}
#countLabel {
-fx-text-fill: #777777;
}.root is the root of the scene: the font and background set here are inherited by every control. Each standard control has its own class: .button, .label, .text-field, .table-view. #countLabel selects a node by its fx:id.
Attaching it to the scene
The file is added to the scene's list of stylesheets in App:
// src/main/java/com/example/notes/App.java — part of start()
Scene scene = new Scene(loader.load(), 800, 480);
scene.getStylesheets().add(App.class.getResource("styles.css").toExternalForm());toExternalForm() turns the resource address into a string JavaFX understands. Another way is an attribute on the FXML root tag: stylesheets="@styles.css", where @ means a path relative to the FXML file.
Your own classes
Let's add classes to the header and the delete button in the markup:
<!-- src/main/resources/com/example/notes/main-view.fxml — changed lines -->
<Label text="My notes" styleClass="header">
<Button fx:id="deleteButton" text="Delete" onAction="#deleteNote"
styleClass="danger"/>The styleClass attribute adds a class to the standard one: the button gets both, button and danger. The .danger rule comes after .button in the file, so its background color wins. In code, deleteButton.getStyleClass().add("danger") does the same.
Common properties
| Property | What it sets |
|---|---|
-fx-background-color | The background color |
-fx-text-fill | The text color of a Label or Button |
-fx-font-size, -fx-font-weight | Font size and weight |
-fx-padding | Inner spacing |
-fx-background-radius | Rounded background corners |
-fx-border-color, -fx-border-width | A border |
-fx-opacity | Transparency |
Pseudo-classes: :hover under the cursor, :pressed being pressed, :focused in focus, :disabled unavailable, :selected a selected row or a ticked check box.
Trying it out
Run the application. The window background is now a light grey with a blue tint, and "My notes" is a large bold blue header. "Add" is a blue button with rounded corners and white text, and "Delete" is red. While nothing is selected, "Delete" is semi-transparent. "Notes: 2" is grey.
Common mistake
If the file name in getResource is wrong, for example style.css instead of styles.css, the window does not open: java.lang.NullPointerException: Cannot invoke "java.net.URL.toExternalForm()" because the return value of "java.lang.Class.getResource(String)" is null. And a property without the prefix, for example background-color: red;, is silently skipped by JavaFX; if a style does not apply, check the -fx- first.