Styling Widgets With CSS

CSS is the presentation language of the web, allowing to change colors, spacing, fonts, borders, shadows of elements and so much more. And we can use it with GTK too!

However, not all properties are supported. You can find a list of the supported properties in the official documentation.

# Loading a Stylesheet

We start by creating a style.css file in data/css/:

1window {
2	background-color: orchid;
3}

For the moment we only put a dummy rule inside, to check when our stylesheet is loaded.

We add it to our data resources:

4<file>css/style.css</file>

Now, we need to load it when our application starts, so we will run code in the startup virtual method. Styling information in GTK is managed by a Gtk.StyleContext object, so we will create one for the default display, and then add as a provider a Gtk.CssProvider object loaded with our stylesheet.

Which gives, translated in code, in src/Application.js:

1import Gdk from 'gi://Gdk';
10class extends Gtk.Application {
11	vfunc_startup() {
12		super.vfunc_startup();
13		this.#loadStylesheet();
14	}
15
16	/* ... */
17
18	#loadStylesheet() {
19		// Load the stylesheet in a CssProvider
20		const provider = new Gtk.CssProvider();
21		provider.load_from_resource('/org/example/filebrowser/css/style.css');
22
23		// Add the provider to the StyleContext of the default display
24		Gtk.StyleContext.add_provider_for_display(
25			Gdk.Display.get_default(),
26			provider,
27			Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
28		);
29	}
30}

Now, when we run the application, its background should be purple-y.

# Styling Our Welcome Widget

Let’s use CSS to replace the styling information we put in our UI files.

First, we have to give our Welcome widget a CSS name, so that we can target it in our stylesheet. By default, it gets the widget name, which is not very helpful. To change it, we set the CssName property of the configuration object of the GObject.registerClass() function:

4export const WelcomeWidget = GObject.registerClass({
5	GTypeName: 'FbrWelcomeWidget',
6	CssName: 'welcome',
7	Template: 'resource:///org/example/filebrowser/ui/WelcomeWidget.ui',
8	/* ... */
9}, class extends Gtk.Widget {});

We then remove the spacing property of the layout manager in data/ui/WelcomeWidget.ui:

5<object class="GtkBoxLayout">
6	<property name="orientation">vertical</property>
7</object>

And all the margin-* properties of the widget in data/ui/Window.ui:

5<object class="FbrWelcomeWidget">
6	<property name="welcome-text">Welcome to our new file browser!</property>
7	<property name="valign">center</property>
8</object>

The spacing property can be replaced by the border-spacing CSS property. The different margin-* properties can be replaced by the shorthand margin CSS property. Remove the rules in the style.css file and add these ones for the Welcome widget:

1welcome {
2	border-spacing: 18px;
3	margin: 36px;
4}

We can go further, and for instance change the font size and weight of the label inside. The CSS name of each widget can be found in the “CSS Nodes” section of its documentation page. So, for a Gtk.Label, we can see that the CSS name is label.

To only change the appearance of the label directly inside our widget (in order to not change other labels such as the one in the button), we use the child combinator selector:

6welcome > label {
7	font-size: 1.4em;
8	font-weight: bold;
9}

# CSS Classes

To give widgets different appearances depending on the context (for example, allowing different font sizes for our Welcome widget), we can use CSS classes.

To give a widget a class in the UI file, we use the style element, and add a class element with the name attribute set to the class we want. A widget can have multiple classes

Let’s add the big class to the Welcome widget instance of the main window in data/ui/Window.ui (removing the margins in the meantime):

 5<object class="FbrWelcomeWidget">
 6	<!-- ... -->
 7	<style>
 8		<class name="big"/>
 9	</style>
10</object>

And update the selector for the label inside our widget in data/css/style.css:

6welcome.big > label {
7	/* ... */
8}

Now, the text of our widget will only be bigger when it has the big class.

# Built-In Classes

Some widgets have built-in classes that you can use. They are mentioned in the “CSS Nodes” section of their documentation page.

For instance, we can read that the Gtk.Button object can have the suggested-action class. We can use it on the button of our widget to give it more impact.

Let’s add this class to the button in data/ui/WelcomeWidget.ui:

24<object class="GtkButton">
25	<!-- ... -->
26	<style>
27		<class name="suggested-action"/>
28	</style>
29</object>

The button now has a blue background, inviting the user to click on it.


CSS in GTK is very powerful, it also has some advanced features such as color definitions and expressions and some custom properties, you can read about these in the official documentation. Use it to make your application stand out!