JavaFX

JavaFX CSS Tutorial

This is a JavaFX CSS tutorial. In this article we will discuss how you can define the style for a Node. You will also learn, how you can add and use StyleSheets (CSS) in JavaFX.

JavaFX allows you to define the look (or the style) of JavaFX applications using CSS. You can define UI elements using JavaFX class libraries or FXML and use CSS to define their look.
 
 
 
 
 
 

 
The following table shows an overview of the whole tutorial:

The following examples uses Java SE 8.

1. Introduction

CSS provides the syntax to write rules to set the visual properties. A CSS rule is also known as a style. A collection of CSS rules is known as a style sheet. Styles, skins, and themes are three related, and highly confused, concepts.

A rule consists of a selector and a set of property-value pairs. A selector is a string that identifies the UI elements to which the rules will be applied. A property-value pair consists of a property name and its corresponding value separated by a colon (:). Two property-value pairs are separated by a semicolon (;). The set of property-value pairs is enclosed within curly braces ({ }) preceded by the selector. An example of a rule in CSS is as follows:

.button 
{
	-fx-background-color: red;
	-fx-text-fill: white;
}

In the above example, .button is a selector, which specifies that the rule will apply to all buttons. -fx-background-color and -fx-text-fill are property names with their values set to red and white, respectively. When the above rule is applied, all buttons will have the red background color and white text color.

Styles provide a mechanism to separate the presentation and content of UI elements. They also facilitate grouping of visual properties and their values, so they can be shared by multiple UI elements. JavaFX lets you create styles using JavaFX CSS.

Skins are collections of application-specific styles, which define the appearance of an application. Skinning is the process of changing the appearance of an application (or the skin) on the fly. JavaFX does not provide a specific mechanism for skinning.

Themes are visual characteristics of an operating system that are reflected in the appearance of UI elements of all applications. To contrast skins and themes, skins are application specific, whereas themes are operating system specific. It is typical to base skins on themes. That is, when the current theme is changed, you would change the skin of an application to match the theme. JavaFX has no direct support for themes.

2. Naming Conventions in JavaFX CSS

JavaFX uses slightly different naming conventions for the CSS style classes and properties. CSS style class names are based on the simple names of the JavaFX classes representing the node in a Scene Graph. All style class names are lowercased. If the class name for the JavaFX node consists of multiple words, for example, TextField, a hyphen is inserted between two words to get the style class name. For example, the style classes for the TextField and CheckBox classes are text-field and check-box, respectively.

Property names in JavaFX styles start with -fx-. For example, the property name font-size in normal CSS styles becomes -fx-font-size in JavaFX CSS style. JavaFX uses a convention to map the style property names to the instance variables. It takes an instance variable; it inserts a hyphen between two words; if the instance variable consists of multiple words, it converts the name to the lowercase and prefixes it with -fx-.

For example, for an instance variable named textAlignment, the style property name would be -fx-text-alignment.

.label
{
	-fx-background-color: red;
	-fx-text-fill: white;
	-fx-text-alignment: center;
}

4. Adding Inline Styles

4.1 The Java Class

FxCSSExample1.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class FxCSSExample1 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a simple Inline Style Example");
		Label message = new Label();
		
		// Set the Style of the Labels
		label.setStyle
		(
				"-fx-font-family: \"arial\";"
				+ "-fx-font-size: 16px;"
				+ "-fx-font-style: normal;"
				+ "-fx-font-weight: normal;"
		);
		message.setStyle
		(
				"-fx-font-family: \"arial\";"
				+ "-fx-font-size: 20px;"
				+ "-fx-font-style: italic;"
				+ "-fx-font-weight: bolder;"
		);
		
		// Create The Button
		Button button = new Button("OK");

		// Set the Style of the Button
		button.setStyle
		(
				"-fx-font-size: 24px;"
				+ "-fx-font-weight: bold;"
				+ "-fx-background-color: lightgreen;"
				+ "-fx-border-style: solid inside;"
				+ "-fx-border-width: 2;"
				+ "-fx-border-insets: 5;"
				+ "-fx-border-radius: 5;"
				+ "-fx-border-color: blue;"
		);
		
		// Add an EventHandler to the OK-Button
		button.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the Button to the VBox
		root.getChildren().addAll(label,button,message);
		// Create the Scene
		Scene scene = new Scene(root,350,200);
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("An Inline Style Example");
		// Display the Stage
		stage.show();		
	}

}

CSS styles for a Node in a Scene Graph may come from style sheets or an inline style. In the above example, you have seen how to specify an inline style for a Node.

The Node class has a style property that is of StringProperty type. The style property holds the inline style for a node. You can use the setStyle(String inlineStyle) and getStyle() methods to set and get the inline style of a node.

There is a difference between a style in a style sheet and an inline style. A style in a style sheet consists of a selector and a set of property-value pairs, and it may affect zero or more nodes in a Scene Graph. The number of nodes affected by a style in a style sheet depends on the number of nodes that match the selector of the style. An inline style does not contain a selector. It consists of only set property-value pairs. An inline style affects the Node on which it is set.

The following example sets the style for a Label:

// Set the Style of the Labels
label.setStyle
(
		"-fx-font-family: \"arial\";"
		+ "-fx-font-size: 16px;"
		+ "-fx-font-style: normal;"
		+ "-fx-font-weight: normal;"
);

The following snippet of code uses an inline style for a Button to display its text in bold, sets the background color to lightgreen and the border color to blue, etc.:

// Set the Style of the Button
button.setStyle
(
		"-fx-font-size: 24px;"
		+ "-fx-font-weight: bold;"
		+ "-fx-background-color: lightgreen;"
		+ "-fx-border-style: solid inside;"
		+ "-fx-border-width: 2;"
		+ "-fx-border-insets: 5;"
		+ "-fx-border-radius: 5;"
		+ "-fx-border-color: blue;"
);

4.2 The GUI

The following image shows the result of the above example:

A JavaFX CSS Inline Style Example
A JavaFX CSS Inline Style Example

5. Adding Style Sheets

5.1 The Java Class

FxCSSExample2.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;

public class FxCSSExample2 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a simple Stylesheet Example");
		Label message = new Label();
		
		// Create The Button
		Button button = new Button("OK");
		
		// Add an EventHandler to the OK-Button
		button.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the Button to the VBox
		root.getChildren().addAll(label,button,message);
		// Create the Scene
		Scene scene = new Scene(root,350,200);
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample2.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("A simple StyleSheet Example");
		// Display the Stage
		stage.show();		
	}

}

5.2 The Style Sheet

fxcssexample1.css

/* JavaFX CSS - Leave this comment until you have at least create one rule which uses -fx-Property */
.button 
{
	-fx-font-size: 24px;
	-fx-font-weight: bold;
	-fx-background-color: lightgreen;
	-fx-border-style: solid inside;
	-fx-border-width: 2;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
	-fx-border-color: blue;	
}

.label
{
	-fx-font-family: "arial";
	-fx-font-size: 16px;
	-fx-font-style: normal;
	-fx-font-weight: bolder;
}

You can add multiple style sheets to a JavaFX application. Style sheets are added to a Scene or parents. Scene and Parent classes maintain an observable list of string URLs linking to style sheets. Use the getStylesheets() method in the Scene and Parent classes to get the reference of the observable list and add additional URLs to the list. The following code would accomplish this:

// Add the StyleSheet to the Scene
scene.getStylesheets().add(getClass().getResource("fxcssexample2.css").toExternalForm());

5.3 The GUI

The result of this example is the same like in the previous one. But in this example, all styles are defined in an external style sheet.

A JavaFX CSS StyleSheet Example
A JavaFX CSS StyleSheet Example

6. Priorities of Styles for a Node

6.1 The Java Class

FxCSSExample3.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample3 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a Styles Priorities Example");
		Label message = new Label();

		// Set the Style of the Label
		message.setStyle
		(
			"-fx-font-family: \"arial\";" +
			"-fx-font-size: 16px;" +
			"-fx-font-style: italic;"
		);
		
		// Create The Buttons
		Button ok = new Button("OK");
		Button cancel = new Button("Cancel");

		// Set the Style of the Button
		cancel.setStyle
		(
			"-fx-background-color: red;" +
			"-fx-border-style: solid inside;" +
			"-fx-border-width: 2;" +
			"-fx-border-insets: 5;" +
			"-fx-border-radius: 5;" +
			"-fx-border-color: blue;"
		);
		
		// Add an EventHandler to the OK-Button
		ok.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(ok,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,350,200);
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample3.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("A Style Priorities Example");
		// Display the Stage
		stage.show();		
	}

}

6.2 The Style Sheet

fxcssexample3.css

.button 
{
	-fx-font-size: 24px;
	-fx-font-weight: bold;
}

.label
{
	-fx-font-family: "arial";
	-fx-font-size: 20px;
	-fx-font-weight: bolder;
}

In a JavaFX application, it is possible, and very common, for the visual properties of nodes to come from multiple sources. For example, the font size of a button can be set by the JavaFX runtime, style sheets can be added to the Parent and the Scene of the Button, an inline style can be set for the Button, and programmatically can be added using the setFont(Font f) method. If the value for the font size of a button is available from multiple sources, JavaFX uses a rule to decide the source whose value is to be used.

In the above example, the font style definitions for the cancel button comes from the stylesheet:

.button 
{
	-fx-font-size: 24px;
	-fx-font-weight: bold;
}

On the other hand, the properties for the border and the background color are defined in the java source code:

cancel.setStyle
(
	"-fx-background-color: red;" +
	"-fx-border-style: solid inside;" +
	"-fx-border-width: 2;" +
	"-fx-border-insets: 5;" +
	"-fx-border-radius: 5;" +
	"-fx-border-color: blue;"
);

The JavaFX runtime uses the following priority rules to set the visual properties of a node. The source with a higher priority that has a value for a property is used:

  • Inline style (the highest priority)
  • Parent style sheets
  • Scene style sheets
  • Values set in the code using JavaFX API
  • User agent style sheets (the lowest priority)

The style sheet added to the parent of a node is given higher priority than the style sheets added to the Scene. This enables developers to have custom styles for different branches of the Scene Graph. For example, you can use two style sheets that set properties of buttons differently: one for buttons in the Scene and one for buttons in any HBox. Buttons in a HBox will use styles from its Parent, whereas all other buttons will use styles from the Scene.

The values set using the JavaFX API, for example, the setFont() method, have the second lowest priority.

The lowest priority is given to style sheets used by the user agent. What is a user agent? A user agent, in general, is a program that interprets a document and applies style sheets to the document to format, print, or read. For example, a web browser is a user agent that applies default formatting to HTML documents. In our case, the user agent is the JavaFX runtime, which uses the caspian.css style sheet for providing the default look for all UI nodes.

6.3 The GUI

The following GUI show the result of the above example:

A JavaFX CSS Styles Priorities Example
A JavaFX CSS Styles Priorities Example

7. Inheriting CSS Properties

7.1 The Java Class

FxCSSExample4.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample4 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a simple Inherit Example");
		Label message = new Label();

		// Set the Style of the Label
		message.setStyle("-fx-font-family: \"arial\";-fx-font-size: 16px;-fx-font-style: italic;");
		
		// Create The Buttons
		Button ok = new Button("OK");
		Button cancel = new Button("Cancel");

		// Set the Style of the Button
		ok.setStyle
		(
				"-fx-border-color: red;"
				+ "-fx-border-width: inherit;"
		);
		
		// Add an EventHandler to the OK-Button
		ok.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(ok,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,400,200);
		
		// Set the Style for the Root Element
		root.setStyle
		(
				"-fx-cursor: hand;"
				+ "-fx-border-color: blue;"
				+ "-fx-border-width: 5px;"
		);
		
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample4.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("An Inheritance Example");
		// Display the Stage
		stage.show();		
	}

}

7.2 The Style Sheet

fxcssexample4.css

.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
	-fx-border-width: 10;
}


.label
{
	-fx-font-family: "arial";
	-fx-font-size: 20px;
	-fx-font-weight: bolder;
}

JavaFX offers two types of inheritance for CSS properties:

  • Inheritance of CSS property types
  • Inheritance of CSS property values

In the first type of inheritance, all CSS properties declared in a JavaFX class are inherited by all its subclasses. For example, the Node class declares a cursor property and its corresponding CSS property is -fx-cursor. Because the Node class is the superclass of all JavaFX nodes, the -fx-cursor CSS property is available for all node types.

// Set the Style for the Root Element
root.setStyle
(
		"-fx-cursor: hand;"
		+ "-fx-border-color: blue;"
		+ "-fx-border-width: 5px;"
);

In the second type of inheritance, a CSS property for a node may inherit its value from its parent. The parent of a node is the container of the Node in the Scene Graph, not its JavaFX superclass. The values of some properties of a Node are inherited from its parent by default, and for some, the node needs to specify explicitly that it wants to inherit the values of the properties from its parent. In our example the CSS properties -fx-border-color and -fx-border-width will be inherited to all children.

You can specify inherit as the value for a CSS property of a Node if you want the value to be inherited from its parent. If a Node inherits a CSS property from its parent by default, you do not need to do anything, that is, you do not even need to specify the property value as inherit. If you want to override the inherited value, you need to specify the value explicitly (overriding the parent’s value).

.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
	-fx-border-width: 10;
}

In this case, the property -fx-border-width will be overrided.

7.3 The GUI

The following image shows the effect of the inheritance:

A JavaFX CSS Inheritance Example
A JavaFX CSS Inheritance Example

8. Understanding Style Selectors

Each style in a style sheet has an associated selector that identifies the nodes in the Scene Graph to which the associated JavaFX CSS property values are applied. JavaFX CSS supports several types of selectors: class selectors, pseudo-class selectors, ID selectors, among others.

8.1 Using Class Selectors

8.1.1 The Java Class

FxCSSExample5.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample5 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a simple Class Selector Example");
		Label message = new Label();
		
		// Create The Buttons
		Button ok = new Button("OK");
		Button cancel = new Button("Cancel");
		
		// Add an EventHandler to the OK-Button
		ok.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(ok,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,400,200);
		
		// Set the StyleClass for the Root Element
		root.getStyleClass().add("hbox");
		
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample5.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("A Class Selector Example");
		// Display the Stage
		stage.show();		
	}

}

8.1.2 The Style Sheet

fxcssexample5.css

.hbox 
{
	-fx-border-color: blue;
	-fx-border-width: 2px;
	-fx-border-radius: 5px;
	-fx-border-insets: 5px;
	-fx-padding: 10px;
	-fx-spacing: 5px;
	-fx-background-color: lightgray;
	-fx-background-insets: 5px;
}
.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
}


.label
{
	-fx-font-family: "arial";
	-fx-font-size: 14px;
	-fx-font-weight: bolder;
}

The Node class defines a styleClass variable that is an ObservableList. Its purpose is to maintain a list of JavaFX style class names for a Node. Note that the JavaFX class name and the style class name of a node are two different things. A JavaFX class name of a node is a Java class name, for example VBox, which is used to create objects of that class. A style class name of a Node is a string name that is used in CSS styling.

You can assign multiple CSS class names to a Node. The following snippet of code assigns the style class “hbox” to an HBox:

// Set the StyleClass for the Root Element
root.getStyleClass().add("hbox");

A style class selector applies the associated style to all nodes, which have the same style class name as the name of the selector. A style class selector starts with a period followed by the style class name. Note that the style class names of nodes do not start with a period.

8.1.3 The GUI

The following image shows an example using the class name as selector:

A JavaFX CSS Class Selector Example
A JavaFX CSS Class Selector Example

8.2 Class Selector for the root Node

8.2.1 The Java Class

FxCSSExample6.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample6 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a simple Root Selector Example");
		Label message = new Label();
		
		// Create The Buttons
		Button ok = new Button("OK");
		Button cancel = new Button("Cancel");
		
		// Add an EventHandler to the OK-Button
		ok.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(ok,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,400,200);
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample6.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("A Root Selector Example");
		// Display the Stage
		stage.show();		
	}

}

8.2.2 The Style Sheet

fxcssexample6.css

.root 
{
	-fx-border-color: blue;
	-fx-border-width: 2px;
	-fx-border-radius: 5px;
	-fx-border-insets: 5px;
	-fx-padding: 10px;
	-fx-spacing: 5px;
	-fx-background-color: lightgray;
	-fx-background-insets: 5px;
}

.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
}


.label
{
	-fx-font-family: "arial";
	-fx-font-size: 14px;
	-fx-font-weight: bolder;
}

The root node of a Scene is assigned a style class named “root”. You can use the root style class selector for CSS properties that are inherited by other nodes. The root node is the parent of all nodes in a Scene Graph. Storing CSS properties in the root node is preferred because they can be looked up from any node in the Scene Graph.

The style of the root node comes from the style sheet:

.root 
{
	-fx-border-color: blue;
	-fx-border-width: 2px;
	-fx-border-radius: 5px;
	-fx-border-insets: 5px;
	-fx-padding: 10px;
	-fx-spacing: 5px;
	-fx-background-color: lightgray;
	-fx-background-insets: 5px;
}

8.2.3 The GUI

The GUI of an example using the root selector:

A JavaFX CSS Root Selector Example
A JavaFX CSS Root Selector Example

8.3 Using ID Selectors

8.3.1 The Java Class

FxCSSExample7.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample7 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a simple ID Selector Example");
		Label message = new Label();
		
		// Create The Buttons
		Button ok = new Button("OK");
		Button cancel = new Button("Cancel");
		cancel.setId("cancelButton");
		
		// Add an EventHandler to the OK-Button
		ok.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the OK Button");
			}
		});

		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(ok,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,400,200);
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample7.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("An ID Selector Example");
		// Display the Stage
		stage.show();		
	}

}

8.3.2 The Style Sheet

fxcssexample7.css

.root 
{
	-fx-border-color: blue;
	-fx-border-width: 2px;
	-fx-border-radius: 5px;
	-fx-border-insets: 5px;
	-fx-padding: 10px;
	-fx-spacing: 5px;
	-fx-background-color: lightgray;
	-fx-background-insets: 5px;
}

.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
}

#cancelButton 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
	-fx-background-color: lightgreen;
	-fx-text-fill: red;
}

.label
{
	-fx-font-family: "arial";
	-fx-font-size: 14px;
	-fx-font-weight: bolder;
}

The Node class has an id property of the StringProperty type, which can be used to assign a unique id to each node in a Scene Graph. Maintaining the uniqueness of an id in a Scene Graph is the responsibility of the developer. It is not an error to set a duplicate id for a Node. You do not use the id property of a node directly in your code, except when you are setting it. It is mainly used for styling nodes using ID selectors. An ID selector in a style sheet is preceded by the pound (#) sign. Note that the ID value set for a node does not include the # sign.

The following snippet of code sets the id property of the cancel Button to “cancelButton”:

// Create The Buttons
Button cancel = new Button("Cancel");
cancel.setId("cancelButton");

8.3.3 The GUI

The following GUI shows the effect of using an ID selector:

A JavaFX CSS ID Selector Example
A JavaFX CSS ID Selector Example

8.4 Combining ID and Class Selectors

A selector can use the combination of a style class and an ID. In this case, the selector matches all nodes with the specified style class and ID. Consider the following style:

#cancelButton.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
	-fx-background-color: lightgreen;
	-fx-text-fill: red;
}

The selector #cancelButton.button matches all nodes with a cancelButton ID and a button style class. You can also reverse the order:

.button#cancelButton
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-radius: 5;
	-fx-background-color: lightgreen;
	-fx-text-fill: red;
}

Now it matches all nodes with a button style class and a cancelButton ID.

9. Specifying Background Colors

9.1 The Java Class

FxCSSExample8.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample8 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a Background Color Example");
		Label message = new Label();
		
		// Create The Buttons
		Button yes = new Button("Yes");
		yes.getStyleClass().add("button-style-yes");
		
		Button no = new Button("No");
		no.getStyleClass().add("button-style-no");
		
		Button cancel = new Button("Cancel");
		cancel.getStyleClass().add("button-style-cancel");
		
		// Add an EventHandler to the YES-Button
		yes.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Yes Button");
			}
		});

		// Add an EventHandler to the NO-Button
		no.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the No Button");
			}
		});
		
		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler<ActionEvent>()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(yes,no,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,400,200);
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample8.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("A Background Color Example");
		// Display the Stage
		stage.show();		
	}

}

9.2 The Style Sheet

fxcssexample8.css

.root 
{
	-fx-border-color: blue;
	-fx-border-width: 2px;
	-fx-border-radius: 5px;
	-fx-border-insets: 5px;
	-fx-padding: 10px;
	-fx-spacing: 5px;
	-fx-background-color: lightgray;
	-fx-background-insets: 5px;
}

.button-style-yes
{
	-fx-background-color: green;
	-fx-background-insets: 5;
	-fx-background-radius: 10;
}
.button-style-no
{
	-fx-background-color: red;
	-fx-background-insets: 0;
	-fx-background-radius: 0;
}

.button-style-cancel
{
	-fx-background-color: yellow;
	-fx-background-insets: 5 10 15 20;
	-fx-background-radius: 0 20 10 10;
}

.button 
{
	-fx-font-size: 20px;
	-fx-border-insets: 5;
	-fx-border-width: 2;
	-fx-border-color: blue;
	-fx-border-radius: 5;
}

.label
{
	-fx-font-family: "arial";
	-fx-font-size: 14px;
	-fx-font-weight: bolder;
}

A Node can have multiple background fills, which are specified using three properties:

  • -fx-background-color
  • -fx-background-radius
  • -fx-background-insets

The -fx-background-color property is a list of comma-separated color values. The number of colors in the list determines the number of rectangles that will be painted. You need to specify the radius values for four corners and insets for four sides, for each rectangle, using the other two properties. The number of color values must match the number of radius values and inset values.

The -fx-background-radius property is a list of a comma-separated set of four radius values for the rectangles to be filled. A set of radius values in the list may specify only one value, for example, 10, or four values separated by whitespaces, for example, 10 5 15 20. The radius values are specified for the top-left, top-right, bottom-right, and bottom-left corners in order. If only one radius value is specified, the same radius value is used for all corners.

The -fx-background-insets property is a list of a comma-separated set of four inset values for the rectangles to be filled. A set of inset values in the list may specify only one value, for example, 10, or four values separated by whitespaces, for example, 10 5 15 20. The inset values are specified for the top, right, bottom, and left sides in order. If only one inset value is specified, the same inset value is used for all sides.

In our example, we have defined three different style for the buttons in the style sheet:

.button-style-yes
{
	-fx-background-color: green;
	-fx-background-insets: 5;
	-fx-background-radius: 10;
}
.button-style-no
{
	-fx-background-color: red;
	-fx-background-insets: 0;
	-fx-background-radius: 0;
}

.button-style-cancel
{
	-fx-background-color: yellow;
	-fx-background-insets: 5 10 15 20;
	-fx-background-radius: 0 20 10 10;
}

In the Java class, the style will be supplied to the buttons:

// Create The Buttons
Button yes = new Button("Yes");
yes.getStyleClass().add("button-style-yes");

Button no = new Button("No");
no.getStyleClass().add("button-style-no");

Button cancel = new Button("Cancel");
cancel.getStyleClass().add("button-style-cancel");

9.3 The GUI

The following GUI shows an example with three buttons, where each button has an own background style:

A JavaFX CSS Background Color Example
A JavaFX CSS Background Color Example

10. Specifying Borders

10.1 The Java Class

FxCSSExample9.java

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

public class FxCSSExample9 extends Application
{
	public static void main(String[] args) 
	{
		Application.launch(args);
	}
	
	@Override
	public void start(Stage stage) 
	{
		// Create the Labels
		Label label = new Label("This is a Border Example");
		Label message = new Label();
		
		// Create The Buttons
		Button yes = new Button("Yes");
		yes.getStyleClass().add("button-style-yes");
		
		Button no = new Button("No");
		no.getStyleClass().add("button-style-no");
		
		Button cancel = new Button("Cancel");
		cancel.getStyleClass().add("button-style-cancel");
		
		// Add an EventHandler to the YES-Button
		yes.setOnAction(new EventHandler()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Yes Button");
			}
		});

		// Add an EventHandler to the NO-Button
		no.setOnAction(new EventHandler()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the No Button");
			}
		});
		
		// Add an EventHandler to the OK-Button
		cancel.setOnAction(new EventHandler()
		{
			@Override
			public void handle(ActionEvent event)
			{
				message.setText("You have pressed the Cancel Button");
			}
		});
		
		// Create the HBox
		HBox hbox = new HBox();
		// Set the vertical spacing between children to 20px
		hbox.setSpacing(20);
		// Add the Buttons to the HBox
		hbox.getChildren().addAll(yes,no,cancel);
		
		// Create the VBox
		VBox root = new VBox();
		// Set the vertical spacing between children to 20px
		root.setSpacing(20);
		// Set the padding of the VBox
		root.setPadding(new Insets(10, 10, 10, 10));
		// Add the Labels and the HBox to the VBox
		root.getChildren().addAll(label,hbox,message);
		// Create the Scene
		Scene scene = new Scene(root,400,200);
		// Add the StyleSheet to the Scene
		scene.getStylesheets().add(getClass().getResource("fxcssexample9.css").toExternalForm());
		// Add the scene to the Stage
		stage.setScene(scene);
		// Set the title of the Stage
		stage.setTitle("A Border Example");
		// Display the Stage
		stage.show();		
	}

}

10.2 The Style Sheet

fxcssexample9.css

.root 
{
	-fx-border-color: blue;
	-fx-border-width: 2px;
	-fx-border-radius: 5px;
	-fx-border-insets: 5px;
	-fx-padding: 10px;
	-fx-spacing: 5px;
	-fx-background-color: lightgray;
	-fx-background-insets: 5px;
}

.button-style-yes
{
	-fx-border-color: black;
	-fx-border-width: 5;
	-fx-border-radius: 0;
	-fx-border-insets: 0;
	-fx-border-style: solid line-join bevel line-cap square;
}
.button-style-no
{
	-fx-border-color: red, black;
	-fx-border-width: 5, 5;
	-fx-border-radius: 0, 0;
	-fx-border-insets: 0, 5;
	-fx-border-style: solid inside, dotted outside;
}

.button-style-cancel
{
	-fx-border-color: red black red black;
	-fx-border-width: 5;
	-fx-border-radius: 0;
	-fx-border-insets: 0;
	-fx-border-style: solid line-join bevel line-cap round;
}

.button 
{
	-fx-font-size: 20px;
	-fx-font-weight: bold;
	-fx-background-color: gray;
	-fx-background-insets: 5;
	-fx-background-radius: 10;
}

.label
{
	-fx-font-family: "arial";
	-fx-font-size: 14px;
	-fx-font-weight: bolder;
}

A Node can have multiple borders through CSS. A border is specified using five properties:

  • -fx-border-color
  • -fx-border-width
  • -fx-border-radius
  • -fx-border-insets
  • -fx-border-style

Each property consists of a comma-separated list of items. Each item may consist of a set of values, which are separated by whitespaces.

10.3 Border Colors

The number of items in the list for the -fx-border-color property determines the number of borders that are painted. The following style will paint one border with the black color:

-fx-border-color: black;

10.4 Border Widths

You can specify the width for borders using the -fx-border-width property. You have an option to specify different widths for all four sides of a border. Different border widths are specified for top, right, bottom, and left sides in order. If the unit for the width value is not specified, pixel is used.

The following style specifies one border with all sides painted in black in 2px width:

-fx-border-color: black;
-fx-border-width: 5;

10.5 Border Radii

You can specify the radius values for four corners of a border using the -fx-border-radius property. You can specify the same radius value for all corners. Different radius values are specified for top-left, top-right, bottom-right, and bottom-left corners in order. If the unit for the radius value is not specified, pixel is used.

You can specify the inset values for four sides of a border using the -fx-border-insets property. You can specify the same inset value for all sides. Different inset values are specified for top, right, bottom, and left sides in order. If the unit for the inset value is not specified, pixel is used.

The following style specifies a border with a radius value of 0px for all corners:

-fx-border-radius: 0;

10.6 Border Insets

You can specify the inset values for four sides of a border using the -fx-border-insets property. You can specify the same inset value for all sides. Different inset values are specified for top, right, bottom, and left sides in order. If the unit for the inset value is not specified, pixel is used.

The following style specifies three borders with insets 0px and 5px on all sides:

-fx-border-insets: 0, 5;

10.7 Border Styles

The -fx-border-style property defines the style of a border. Its value may contain several parts as follows:

-fx-border-style: <dash-style> [phase <number>] [<stroke-type>] [line-join <line-join-value>] [line-cap <line-cap-value>]

The value for <dash-style> can be none, solid, dotted, dashed, or segments(<number>, <number>...). The value for <stroke-type> can be centered, inside, or outside. The value for <line-join-value> can be miter <number>, bevel, or round. The value for <line-cap-value> can be square, butt, or round. The segments() function is used to have a border with a pattern using alternate dashes and gaps:

-fx-border-style: segments(dash-length, gap-length, dash-length, ...);

The first argument to the function is the length of the dash; the second argument is the length of the gap, and so on. After the last argument, the pattern repeats itself from the beginning. The following style will paint a border with a pattern of a 10px dash, a 5px gap, a 10px dash, and so on:

-fx-border-style: segments(10px, 5px);

You can pass as many dashes and gap segments to the function as you want. The function expects you to pass an even number of values. If you pass an odd number of values, this will result in values that are concatenated to make them even in number. For example, if you use segments(20px, 10px, 5px), it is the same as if you passed segments(20px, 10px, 5px, 20px, 10px, 5px).

In our example the styles are defined as follows:

.button-style-yes
{
	-fx-border-color: black;
	-fx-border-width: 5;
	-fx-border-radius: 0;
	-fx-border-insets: 0;
	-fx-border-style: solid line-join bevel line-cap square;
}
.button-style-no
{
	-fx-border-color: red, black;
	-fx-border-width: 5, 5;
	-fx-border-radius: 0, 0;
	-fx-border-insets: 0, 5;
	-fx-border-style: solid inside, dotted outside;
}

.button-style-cancel
{
	-fx-border-color: red black red black;
	-fx-border-width: 5;
	-fx-border-radius: 0;
	-fx-border-insets: 0;
	-fx-border-style: solid line-join bevel line-cap round;
}

Notice that the second style achieves overlapping of two borders, one in solid red and one in dotted black, by specifying the appropriate insets and stroke type (inside and outside). Borders are drawn in the order they are specified. It is important that you draw the solid border first in this case; otherwise, you would not see the dotted border.

The following snippet of code sets the id property of all buttons:

// Create The Buttons
Button yes = new Button("Yes");
yes.getStyleClass().add("button-style-yes");

Button no = new Button("No");
no.getStyleClass().add("button-style-no");

Button cancel = new Button("Cancel");
cancel.getStyleClass().add("button-style-cancel");

10.8 The GUI

The following GUI shows an example with three buttons, where each button has an own unique border style:

A JavaFX CSS Border Example
A JavaFX CSS Border Example

11. Download Java Source Code

This was an JavaFX CSS Tutorial

Download
You can download the full source code of this example here: JavaFxCSSExample.zip

Andreas Pomarolli

Andreas has graduated from Computer Science and Bioinformatics at the University of Linz. During his studies he has been involved with a large number of research projects ranging from software engineering to data engineering and at least web engineering. His scientific focus includes the areas of software engineering, data engineering, web engineering and project management. He currently works as a software engineer in the IT sector where he is mainly involved with projects based on Java, Databases and Web Technologies.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button