Styling (and Layout) with CSS

There are different techniques and technologies available to determine the size (width and height) of a rendered widget.

CSS
The browser uses CSS (Cascading Style Sheets) as a technology for defining visual aspects, such as fonts, colors, border styles, but also for geometry.
Layout Managers
Whereas CSS (and browsers) were originally designed for the markup of documents, the requirements for web applications are in many ways different. Layout Managers are a common technique in desktop applications to lay out a UI, and this is also available in Wt.
CSS Grids
A practical alternative to plain CSS, and to overcome some of its deficiencies which, are CSS frameworks which allow one to place widgets using a generic tag system. These typically divide the page in a virtual grid. When using Wt with the Bootstrap theme, such a CSS grid framework is included.

Introduction to CSS

Cascading Style Sheets (CSS) group rules that specify both markup and layout properties of widgets. These rules are linked to certain widgets (or more correctly, DOM nodes in the browser that render these widgets) using selectors. Selectors may match widgets based on the style class or widget id of the widget or one of its ancestors, or even more advanced combinations.

Primer + reference here.

Three ways to use CSS in Wt.

Inline CSS
A single widget's style properties can be modified directly using C++ API
Internal StyleSheet
The internal stylesheet allows to use a C++ API to create, modify and remove CSS style rules that typically impact multiple widgets.
External StyleSheets
By far the most practical approach is to use external CSS stylesheets that define styling rules, and apply them to Wt widgets using style classes.

API for inline CSS style

A subset of CSS properties are available in the Wt API, and thus allow to influence the layout or visual appearance of a widget directly, from C++. This is useful if you want programmatic control over these properties; for other situations we recommend to use an external CSS stylesheet.

CSS properties that impact layout aspects are made available directly in the WWidget API, whereas decorative aspects are available from WWidget::cssDecorationStyle(), which returns a reference to a WCssDecorationStyle class.

The following table gives an overview of properties that can be directly modified from C++.

Class Property Description
WWidget setPositionScheme() CSS position property.
WWidget setOffsets() CSS top, right, bottom, left properties.
WWidget resize() CSS width, height properties.
WWidget setMinimumSize() CSS min-width, min-height properties.
WWidget setMaximumSize() CSS max-width, max-height properties.
WWidget setLineHeight() CSS line-height property.
WWidget setFloatSide() CSS float property.
WWidget setClearSides() CSS clear property.
WWidget setMargin() CSS margin property.
WWidget setVerticalAlignment() CSS vertical-align property.
WWidget setInline(), setHidden() CSS display property.
WCssDecorationStyle setCursor() CSS cursor property.
WCssDecorationStyle setBackgroundColor(), setBackgroundImage() CSS background property.
WCssDecorationStyle setForegroundColor() CSS color property.
WCssDecorationStyle setBorder() CSS border property.
WCssDecorationStyle setFont() CSS font property.
WCssDecorationStyle setTextDecoration() CSS text-decoration property.

The Internal Style Sheet

The method WApplication::styleSheet() returns a reference to the embedded stylesheet (an instance of WCssStyleSheet), which can be manipulated dynamically to add, modify or removing rules. This is used primarily in some advanced composite widgets within Wt (such as WTableView, WTreeView) since it allows to modify certain properties of a group of widgets using a minimum of DOM manipulations.

Using External Style Sheets

Widgets may allow configuration of their look and feel through style classes. These may be defined in an embedded stylesheet or in external style sheets. Preferably use external stylesheets because of the strict separation between style and widget. It provides the broadest application of style as it allows you to manage the presentational aspects of all widgets from a handful of style sheets.

These are API classes and methods for working with CSS external stylesheets:

Class Method Description
WApplication useStyleSheet() Adds an external style sheet
WWidget setStyleClass() Sets (one or more) CSS style classes
WWidget styleClass() Returns the CSS style class
WWidget addStyleClass() Adds a CSS style class
WWidget removeStyleClass Removes a CSS style class
WWidget toggleStyleClass Toggles a CSS style class

The following example shows how to refer to add an external style sheet to the application and how to add/remove classes to a widget like WTable.

Example

These are the most import API classes and methods for working with CSS:

MethodDescription
WApplication::useStyleSheet()Adds an external style sheet
WWidget::setStyleClass()Sets (one or more) CSS style classes
WWidget::removeStyleClass()Removes a CSS style class
WWidget::toggleStyleClass()Toggles a CSS style class
source
#include <Wt/WApplication.h>
#include <Wt/WContainerWidget.h>
#include <Wt/WPushButton.h>
#include <Wt/WText.h>
#include <Wt/WTable.h>

using namespace Wt;

// Add an external style sheet to the application.
Wt::WApplication::instance()->useStyleSheet("style/CSSexample.css");

auto container = std::make_unique<Wt::WContainerWidget>();
// The style sheet should be applied to this container only.
// The class .CSS-example is used as selector.
container->setStyleClass("CSS-example");

Wt::WPushButton *allB = container->addNew<Wt::WPushButton>("Set all classes");

Wt::WPushButton *removeB = container->addNew<Wt::WPushButton>("Remove info class");
removeB->setMargin(10, Wt::Side::Left | Wt::Side::Right);
removeB->disable();

Wt::WPushButton *toggleB = container->addNew<Wt::WPushButton>("Toggle compact");
toggleB->disable();

Wt::WText *text = container->addNew<Wt::WText>();
text->setText("<p>These are the most import API classes and methods for"
              " working with CSS:</p>");

Wt::WTable *table = container->addNew<Wt::WTable>();
table->setHeaderCount(1);
table->elementAt(0, 0)->addNew<Wt::WText>("Method");
table->elementAt(0, 1)->addNew<Wt::WText>("Description");
table->elementAt(1, 0)->addNew<Wt::WText>("WApplication::useStyleSheet()");
table->elementAt(1, 1)->addNew<Wt::WText>("Adds an external style sheet");
table->elementAt(2, 0)->addNew<Wt::WText>("WWidget::setStyleClass()");
table->elementAt(2, 1)->addNew<Wt::WText>("Sets (one or more) CSS style classes");
table->elementAt(3, 0)->addNew<Wt::WText>("WWidget::removeStyleClass()");
table->elementAt(3, 1)->addNew<Wt::WText>("Removes a CSS style class");
table->elementAt(4, 0)->addNew<Wt::WText>("WWidget::toggleStyleClass()");
table->elementAt(4, 1)->addNew<Wt::WText>("Toggles a CSS style class");

allB->clicked().connect([=] {
    // Set style classes for the complete table.
    table->setStyleClass("table table-bordered");
    // Set the info style class for the first row after the header.
    table->rowAt(1)->setStyleClass("info");
    // Set a style class for the methods (first column, the header excluded).
    for (int i=1; i<table->rowCount(); i++)
        table->elementAt(i,0)->setStyleClass("code");
    removeB->enable();
    toggleB->enable();
});

removeB->clicked().connect([=] {
    table->rowAt(1)->removeStyleClass("info");
    removeB->disable();
});

toggleB->clicked().connect([=] {
    if (toggleB->text() == "Toggle compact") {
        table->toggleStyleClass("table-sm", true);
        toggleB->setText("Toggle expanded");
    } else {
        table->toggleStyleClass("table-sm", false);
        toggleB->setText("Toggle compact");
    }
});

Here is the corresponding style sheet (CSSexample.css).

source
.CSS-example table {
  width: 0%;
  margin-top: 20px;
  margin-bottom: 20px;
}

.CSS-example .table-bordered {
  border: 1px solid #DDD;
  border-left: 0;
  border-radius: 4px;
}

.CSS-example .table-sm th,
.CSS-example .table-sm td {
  padding: 4px 5px;
}

.CSS-example .code {
  font-family: andale mono;
  color: #570;
  font-size: 97%;
}

.CSS-example .info {
  background-color: #D9EDF7;
}

Top