Understanding the brasato layout

Florian Gnägi


Table of Contents

1. Fundamental framework concepts
1.1. Programming paradigms
MVC and the composite pattern
Components
Containers and Component positioning
Controllers
1.2. Component lifecycle and rendering
How components are created: layout and control decomposition
Dispatching, event and render phase
Render phase in the AJAX mode
General component rendering
VelocityContainer rendering
2. The brasato layout
2.1. HTML and CSS
The basics
Browser issues
More than the basics
2.2. The YAML framework
Overview
YAML elements
YAML filestructure
Other YAML layout building blocks
How YAML is used in brasato
2.3. Themes
Theme concept
How themes are included
The theme structure
Theme validity
The default theme
A custom theme

Chapter 1. Fundamental framework concepts

1.1. Programming paradigms

MVC and the composite pattern

The brasato webapplication framework has two major implementation concepts:

  1. it implements the Model-View-Controller design pattern. From Wikipedia:

    Model-view-controller (MVC) is an architectural pattern used in software engineering. In complex computer applications that present a large amount of data to the user, a developer often wishes to separate data (model) and user interface (view) concerns, so that changes to the user interface will not affect data handling, and that the data can be reorganized without changing the user interface. The model-view-controller solves this problem by decoupling data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller.

  2. it implements the composite design pattern for a component based architecutre

Components in brasato are very much like components in Java SWING, in fact, the whole GUI layer in brasato has been inspired by the SWING architecture. In such a component based architecture, the controller and the view elements are decomposed into a hierarchical structure of components and composite objects.

If you are not familiar with MVC and the composite design pattern, please bring yourself up-to-date before you continue reading.

Components

Components are visual elements displayed somewhere on the screen. They are generated by a controller that is responsible for this specific part of the view and that reacts to events generated by those components.

Components are reusable and generic GUI elements. Sometimes, components are also called widgets. In brasato, we have GUI components like tables, forms, menu tree, links and many others. Note that all this components are completely business independent. The purpose of a component is to provide a certain functionality to display or manipulate data. What kind of data this is or in what greater context the component is used is irrelevant.

Components are basic elements of the brasato framework, it is most likely that you will never have to create a component by yourself. There is a stable set of elements provided by the framework that is used by developers to create a rich user interface.

Brasato components displayed in the hierarchy browser

Containers and Component positioning

While the purpose of a component is to display a GUI element, the component itself does not know or tell the framework where exactly on the screen it should be displayed. This is where the containers come in place. A container has the functionality to contain several components and to position them within the container's area. The position of the container itself is again unknown since the container is a component as well.

There are three important containers in brasato:

  • Window: the first container in the chain that represents the users browser window.

  • Panel: a placeholder container. A Panel is used when you don't know yet what your view will be, but you know that there will be something you have to display later

  • VelocityContainer: a HTML based container. Pure HTML is used to position components contained by this container, thus it is very flexible

We can summarize, that a brasato webapplication GUI is a hierarchical structure of containers and components. In the brasato GUI debug mode this hierarchical structure can be observed well. Each container has a thin dotted line that symbolizes the border of the container area.

To enable the brasato debug mode, the property brasato.debug=true must be set in the olat.properties file. The GUI debug mode is then started in the debug window that you can find at the top left corner of the browser window.

Start the brasato GUI debugger
A link component in a container in a container in a container ... in a window

Controllers

While the MVC pattern separates the view part of your code from the workflow part, it does not necessary make code component based. In simpler web applications it is very common to have one fat controller that dispatches all the requests and does more or less everything. This is normally the case when you use the servlet development model: for each workflow a dedicated servlet.

What is special about the brasato framework is that it takes care of the whole dispatching process for you and offers a way to break down a whole business process workflow in manageable and reusable controller and view parts. In brasato, developers don't write servlets, they write controllers.

So what is a controller? A controller has the following features:

  • Implementation of workflow logic: controllers react to events that occure due to user interaction. e.g. a user clicks on a link, the responsible controller decides what the meaning of this action is and what business logic is triggered by this event. A sidenote: the controller should not implement the business logic itself, this should be done in a so called manager class. The controller is only responsible in controlling the users GUI workflow, the workflow logic.

  • Creation of a view. Each controller must have a view, a component that represents the viewable thing that this controller is about. This is done by executing the setInitialComponent() method in the controllers constructor. In most cases the controllers view part is either

    • a Panel: in this case the controller can swap its entire view. Remember, the panel is only a placeholder for a component that is generated later!

    • a VelocityContainer: in this case the controller can use many components and position them together with text elements using plain HTML and CSS code

  • Implementation of the composite pattern. There we have it again: a controller can have many child controllers. We come to this in the next chapter.

  • Managing of the data model: The first element in the MVC is the datamodel. It is initialized by the controller and handed over to the components that use the datamodel to display the data. Important to understand is the fact that whenever something happens, e.g. a user clicks the remove link in a table entry, the remove operation is not performed by the table component. Remember, the component has no business meaning, it is only a GUI element! The table component fires an event to the controller that created this table component, the controller does execute some business logic and removes the table entry from the table data model. When the table component displays itself, it just takes the updated data model and renders the data from the model.

  • Controller can be reusable: The higher up in the controller hierarchy, the less reusable is a controller. E.g. the MainHomeController can really just generate the home area as in the OLAT web application. There is little hope that this is reusable anywhere else. On the other hand the GroupController is used almost anywhere. It is a business context free controller that is very reusable.

Sometimes it is difficult to distinguish between components and controllers: why is something implemented as a controller and why some other things as a component? You will see that there are some components like the table component that have a wrapper controller. Whenever you use a table in the brasato framework you actually use the TableController and not the Table component. The reason is that the table component got too many features and is to complex to handle all the configuration options that we wanted like pageing, excel download, table configuration and more. The controller has much more possibilities to deal with all this functionality. E.g. the table configuration feature needs a little data model to know which columns are enabled by this user. The controller can read this information from the database and implement a workflow to change the settings. This can't be done in a component. Remember, a component is only a view element, it does not implement a workflow!

So, sometimes the border between controllers and components is thin. Business context free controllers with a high reusability factor like the GroupController, UserSearchController or TableController behave very much like components.

For your convenience the brasato framework offers a feature rich BasicController implementation. The BasicController has methods to easily initialize VelocityContainer objects, to show info, warn or error messages, it creates a package translator for you and auto-disposes child controllers when used properly. You should always start by subclassing from the BasicController when you build your own controller!

1.2. Component lifecycle and rendering

How components are created: layout and control decomposition

It is important to understand how all those components and containers are created at runtime to get a deeper understanding about the final layout. The following picture shows the most relevant controllers and components. To reduce complexity unimportant elements have been removed.

Decomposition of the framework controllers and components that span up the layout

In this diagramm we focus only on layout relevant parts of the framework and ignore the brasato main servlet and dispatching process. It is enough to know that at some point the BaseChiefControllerCreator.createChiefController method is called for a certain user request to create a new user window. First, a new BaseChiefController is created. This is the top of the controller hierarchy. The BaseChiefController creates an instance of the Window component and adds the HTML elements html, head and body in a VelocityContainer to that window. Therefore, the BaseChiefController is mainly responsible to provide framework related HTML fragments such as the debug tools, the AJAX back channel and covers the whole issues of JavaScript and CSS inclusion.

Then, a SimpleBaseController is created that has a simple VelocityContainer view to add the GUI messages, modal dialog and a GUI stack feature. The SimpleBaseController wrapps the application specific base controller that handles the applications basic behaviour. In most cases this will be the BaseFullWebappController.

You might wonder how the framework knows which controller it should use as the application specific base controller: the BaseChiefController and the SimpleBaseController are both parts of the framework, but the BaseFullWebappController can be replaced with whatever super controller you like. We talked above about the BaseChiefControllerCreator that factored all this controllers - for this purpose the BaseChiefControllerCreator has a Spring injected ContentCreator that has the ability to create the base controller for the current web app. In this example the AutoCreator with the configuration className=BaseFullWebappController is used to create a BaseFullWebappController at run time.

Base controller factory: configured via Spring

The BaseFullWebappController deals with the main navigation and layout of the web app. We think the approach of a main navigation at the top - we call it Site - is universal and can be used for almost every web application out there. The BaseFullWebappController has a VelocityContainer as the main view part which is devided into several sections:

  • layout wrapper (#b_page and #b_page_margins) for pure layouting purposes

  • web app header (#b_header): you could place a link or logo there. The area is controlled by a Spring configured HeaderController

  • the Site navigation (#b_nav): navigation for static sites and dynamic tabs, controlled entirely by the BaseFullWebappController

  • a static top navigation element (#b_topnav): for static links like the logout button, the search field, an imprint. This is controlled by the Spring configured TopNavController

  • the main area (#b_main): The main application area for the currently active site. The controller that is used in this area must implement the MainController interface. In most cases the Main3ColsController is used which features a 1, 2 or 3 column view.

  • the footer (#b_footer): Use it to display some footer information like logged in users or a link to the project homepage. This is controlled by a Spring configured FooterController

Note that the nomenclatura for this elements strictly follows the YAML web layout framework. The BaseFullWebappController layout is based on YAML.

The next level of layout relevant parts are generated by the controller that is responsible for the #b_main area. As I said, usually this is the Main3ColsController delivered by the brasato framework. More about this later. Within the Main3ColsController the three columns can be filled with whatever the application needs.

Dispatching, event and render phase

When implementing the MVC approach, another fundamental paradigm is executed: the separation of the dispatching, event handling and rendering.

When a user request enters the brasato framework it gets automatically dispatched by the DispatcherAction. The framework computes then which component is responsible for dealing with the request and calls the Component.dispatchRequest() method on this component.

There are two types of requests a component can dispatch:

  1. a component internal action: some user action that does only modify a view option of the component. E.g. in the Table component the user could click the table header which then sorts the table ascending or descending in this column. This action does not modify the data model nor does it modify anything in the system at all. It is entirely GUI related and component internal only.

  2. a component provided action: some functionality the component offers to the controller that created the component. E.g. in the Table component, when one actually clicks on a link in one of the rows this is not a table internal GUI issue. This is the selection functionality of the table, one of the main features the Table component offers.

When component internal actions occure, the component will handle it and the dispatching phase is finished.

But when the user action was a functionality that the component offers to its Listeners in the component specification, it is a whole different story. The Listener is the Controller who created the Component and attached itself as Listener. The listener gets informed whenever some of those functions are executed by the user, we call them Event. So, when the user presses this link in the table row, the Table component will fire an Event to the Controller by calling the Controller.event() method.

Now we entered the event handling phase. Actually, this is still part of the dispatching phase since it happens during the execution of the dispatchRequest() method of the Component, but from a logical point of view this is not dispatching anymore. Sending events from a component to a controller, from controllers to parent controllers or even from controllers to global event buses implement the Observer design pattern, another fundamental design concept. But I'm not going into details here, it is enough to know that the components will signal to its listening controlles that a specific event happend.

In the Controller.event() method the Controller catches those events and executes some business logic. For example, the controller could call the UserManager and delete the user associated with the selected row from the database and refresh the data model of the table component. That's it: the controller catches the event from the component and manipulates the datamodel. (In other cases, the controller could fire events to its parent controller to signal that a certain workflow is now finished, and the parent controller could then remove the entire view of the current controller and replace it with another view. But at some point in the hierarchy, a controller will do some business logic and not fire an event anymore since everything has been done that needs to be done.)

Now, when the last event is handeld, the dispatching and event handling phase is finished and the framework continues with the rendering phase. At this point all the business logic has been finished, all database transactions have been submitted, all states are set and we could call it a day for this request. Everythig that follows now is just rendering the data and the new state of the application. After this point, no business logic should be executed anymore and no data manipulation be made.

The render phase is easy: the framework takes the current Window with the whole hierarchy of Components and Containers and traverses it with the Renderer. You can think of the Renderer as a transformer, it transforms the internal object structure into a HTML page. The Renderer has special implementations for each Component and uses those while traversing the component tree recursively. For example, the MenuRenderer will be used to render a MenuTree, the TableRenderer is used to display a Table component. Each of those Renderer produces a string that represents the rendered component as an HTML fragment.

The sum of all those component HTML fragments is the page as an HTML document. Thats it. In the end, the brasato framework delivers this page to the users browser.

Render phase in the AJAX mode

A very powerfull feature of the brasato framework is the automated AJAX mode. When the AJAX mode is enabled, the dispatching and event phase remain the same, but an importand difference happens during rendering phase.

Instead of applying the rendering to the whole Component tree starting from the Window object, the framework checks for each component in the tree if it actually has a dirty view. Dirty means, that the view of the Component changed since the last call. Only those components that are marked as dirty are rendered (including the components child components) and sent to the browser via a background AJAX channel.

In the browser, some JavaScript code detects the corresponding element in the HTML DOM tree and replaces it with the newly rendered component view it got from the server. In fact, this new view is nothing else than a small HTML snipplet.

The effect of the AJAX mode is that the basic layout does not need to be redrawn by the browser, only parts in the DOM tree will change. This results in a more vivid user experience due to lower network traffic and less computer power needed to draw the HTML page in the browser.

From a programmers perspective nothing special has to be done to support this AJAX mode unless a programmer does some custom dispatching or a component wants to implement component-internal AJAX features (e.g. dynamic loading of a menu tree).

General component rendering

Components are rendered programmatically in Java code. The Component.render() method is executed. To understand how a component is mapped to HTML one must read the Java sourcecode for the specific renderer. To modify the rendering, the class must be patched and recompiled. Component Renderers are in the same package as the components in org.olat.core.gui.components.* .

Generally it is not recommended to modify a renderer just to change the layout. After each update of the OLAT application all changes must be carefully reviewed and the patches reapplied. If you can't style a component with the HTML markup that is generated by a renderer, please let me know so that we can modify it for a future release.

VelocityContainer rendering

A special case is the VelocityContainer component. The main feature of this Container is to position contained child components using HTML markup and to add other elements like internationalized text fragments. This is implemented using the Apache Velocity templating engine. When constructing a VelocityContainer instance in a Controller, the path to a velocity template file is one of the main elements of the constructor. The templates are normally stored in a special directory _content on the same level as the controller that constructs the element. During the render phase, the VelocityContainer will use this template to create the HTML fragment.

To create a velocity container instance you can use the BasicController.createVelocityContainer() helper method. As an argument it takes the name of your HTML template. E.g. when giving the name "test", the velocity container will search for a file _content/test.html.

The advantage of this approach is that it is very simple to write Velocity templates and to position other objects like child components, translated strings or objects that represent parts of the data model. A so called VelocityRenderDecorator offers many helpfull methods in the template like translating, URL generation, child component rendering and much more. The render decorator can be accessed using the $r variable in the templates.

Most elements in a brasato web application are implemented in velocity containers, almost every controllers view is constructed using a VelocityContainer. Therefore, most of the HTML code generated in the render phase is defined in the velocity templates. In most cases you can forget about how other components are rendered, most likely you will never need to modify anything there. But for customizing the brasato web application layout, it might be necessary to modify some of the velocity templates.

When you write your own velocity templates, make sure you write valid XHTML 1.0 transitional code. Best is to test your page using an XHTML online validator.

See the Velocity User Guide for more information about the possibilities in the velocity engine.

Chapter 2. The brasato layout

2.1. HTML and CSS

The basics

HTML (Hyper Text Markup Language) is used to describe the structure and the content for each webpage that is displayed in your webbrowser. As described in the previous chapters, a brasato application like OLAT generates on the server a hierarchy of components. Each component generates a view using either a renderer or a velocity template. Each renderer or template will generate HTML code that combined alltogether form a proper HTML page. The compiled page is then sent to the client for displaying.

In an ideal world, the HTML code does not say anything about how the content should be represented on the Screen, it's only about structure and content. The formatting and layouting is done by CSS (Cascading Style Sheet) rules that are applied to the HTML structure. This is done on the browser and not on the server.

The coupling of HTML and CSS is very loose: first, the HTML document tells the browser which CSS files should be considered for this document, second, the browser analyses the HTML structure and the CSS rules and applies each matching rule from the CSS file to the elements from the HTML document.

A CSS rule is defined by so called selectors. There are different type of selectors with different precedence. When it comes to rendering, the browser looks at all the rules in the CSS files and builds up a cascade of rules that can be applied to each element. As a rule of thumb one can say that the more specific a CSS rule is, the higher is the relevance of the rule in the CSS cascade.

To understand how the browser layout is created, use the Firefox extension Firebug. Firebug offers great debugging tools and allows you to inspect and even real-time modify the CSS rules that apply to a HTML element.

The FireBug extension in action

Browser issues

Viewing a HTML page in your browser involves the following steps:

  • Parsing of the HTML document and building a browser internal representation, the so called DOM (Document Object Model)

  • Parsing of the CSS document and building a browser internal representation

  • Detection of matching CSS rules for each element in the DOM

  • Detection of conflicting CSS rules that match for the same element and solving the conflicts by using the CSS cascade rules

  • Rendering of the elements using the resolved CSS rules

The problem a web developer faces is the fact that each of these steps can be implemented slightly different in the various browsers. This is due to bugs (faulty implementation) and different interpretation of the specification (weak specification or engineers that can't read a spec).

Thus, it is not enough to read the HTML and CSS specs, writing web applications involves a lot of expertise, permanent research and testing, testing, testing.

More than the basics

If you want to fully understand or modify the brasato layout or build a custom template you must have HTML and CSS expertise, there is no way around that. To proceed you should first bring yourself up to date with these technologies. There are many, many free resources around in the web that you can use.

The following topics are crucial and must be understood:

  • Different HTML versions, difference between HTML and XHTML

  • Various CSS selectors

  • The CSS cascade (precedence of selectors and the combinations)

  • The CSS box model including the different interpretation between Internet Explorer and Firefox (Box model bug)

  • Box display types (inline, block, list-item, none etc) and default values for HTML elements

  • Element positioning (static, relative, absolute etc)

  • Concept of a floating element and how the clearing mechanism works

  • Browser render modes (Standards mode, Quirks mode)

  • Most relevant browser bugs and how to deal with them

2.2. The YAML framework

Overview

YAML stands for "Yet Another Multicolumn Layout". It is a HTML/CSS layout framework developed by Dirk Jesse that helps developers and designers to solve common layout problems in web pages. These problems can be classified in two sections:

  • Layout blue-prints: recipes for implementing a CSS based layout without (miss)using HTML-table elements

  • Bugs: fixes and workarounds for common browser bugs, both for dealing with CSS parse bugs and with display and render bugs

I won't go into details here and explain the YAML framework. Please read the online documentation or better buy the YAML book written by the YAML author and support his work.

YAML elements

The YAML layout is composed of a set of HTML DIV elements:

  • page margins: a wrapper container to define outer page margins

  • page: a wrapper container to style the inner page style: writing direction, page background

  • header: an optional container for a page header

  • topnav: an optional container for a tool or a top navigation element

  • nav: an optional container that holds the main site navigation

  • main: the main content container

  • col1: an optional container for the first column, usually the left column

  • col2: an optional container for the second column, usually the right column

  • col3: an optional container for the third column, usually the middle column

  • footer: an optional footer container

In the HTML code they appear in the described order. With this setup a variety of layouts can be created.

HTML markup structure in the YAML framework. Image property of www.yaml.de

In most scenarios a 1-3-2 layout is used. Yes, this is not a typo: the center column is column three and not column two. This is because the column one and the column two float on the left and the right side of the content and therefore must be declared in the HTML code before the third column. This is just one of the akward behaviours of CSS.

Just by using CSS rules it is possible to layout the said columns in many different ways. Below you see an example of a 1-3-2 and a 2-3-1 layout. Those are the most commonly used layouts, the 1-3-2 for left-to-right and the 2-3-1 for right-to-left languages.

CSS rendering of the YAML elements in OLAT. . Image property of www.yaml.de

YAML filestructure

The YAML framework splits up all the CSS rules into several separate files, one for each media type. In addition, all hacks and tweaks for the Internet Explorer browser family are separated into different files and included with the Microsoft proprietary conditional comment tag. The benefit is that the file structure is very clean and the standard CSS does validate since the custom IE hacks are not loaded by standards compliants browsers like FireFox or Safari. The drawback is that the browser has to load many files and it might look complicated at first sight.

Here's how how the files are organized:

The YAML project file structure

Other YAML layout building blocks

Besides the solutions for the basic layout problems YAML does also address other common issues like subcolumns and navigation. For example, using the subcolumn container it is easy to create a 25%-75% column layout that is contained within the first column of a 33%-33%-33% column layout.

Please have a look at the YAML homepage to learn more about YAML.

How YAML is used in brasato

In the brasato frame the developer doesn't have to deal with those basic layout issues. They are already implemented using the YAML components:

  • BaseChiefController loads all necessary CSS files

  • BaseFullWebappController provides the YAML container page, page_margins, header, topnav, nav and the footer. In the nav container, the sliding door concept is implemented to display the sites navigation

  • Main3ColsController provides the YAML container main, col1, col2 and col3

First, the YAML CSS files are loaded. To not get conflicts with content that also uses YAML, in brasato all YAML classes and DOM element ID's contain a prepended b_. Example: the element page_margins in YAML is renamed to b_page_margins in brasato. Besides this modification we use the standard YAML distribution with some minor additions.

In brasato, the YAML package is located under webapp/static/yaml/

YAML is used to build the basic layout structure of the application. It is included in the default templated in the first line. Some styles are then overriden by the theme.

2.3. Themes

Theme concept

All CSS rules and the referenced media elements (icons, sounds) that are used to layout a brasato application build a so called theme. A theme must offer layouting rules for every component. Since a theme is completely separated from the code it is possible to have many themes on the same server, instantly change the look of an application and to share themes independent from the application code. In the Admin site in the OLAT application the installed themes can be selected and tested from a drop down list.

In brasato a default theme is delivered that includes rendering instructions for every component. An additional example theme demonstrates how one can build a derived theme without redefineing every single element but just overrideing some elements.

Themes are located under webapp/static/themes/

Please see also the theme documentation that you find under webapp/static/themes/themes.README

How themes are included

In the constructor of the BaseChiefController the current theme is detected and added into the HTML head section. There are several files that are loaded from a theme:

  • layout.css: The main CSS file that includes all other CSS files

  • patches.css: The patch CSS file for IE browsers that include IE specific fixes

  • favicon.ico: The site icon displayed in the browser location bar

The CSS files that are included here do not contain actual CSS selectors and rules but rather do they serve as an entry point to load the necessary CSS files.

The theme structure

The theme structure is very close to the YAML structure. The rules are splitt into four different type of files:

  • yaml_basemod.css: rules for the classes from the YAML framework

  • brasato.css: rules for the classes from the brasato framework

  • olat.css: rules for the classes from the application, in this example the OLAT e-learning system

  • content.css: rules for content formatting

These files are available in different directories, each symbolizes the usage of the rules:

  • all: rules for all media types (screen, print, etc)

  • aural: rules only for aural media types

  • print: rules that override the rules from all to optimize the view for printing

  • patches: special rules only for the IE browser family

In the images directory you will find all the images that are referenced in the CSS rules. The images are addressed relative to the location of the CSS file.

The main entry points for a theme are the layout.css and the patches.css file on the root level of the theme. Those are the files that are included in the HTML head element. All other files must be included in the correct order from those files.

An example from the default theme:

@charset "UTF-8";

/* basic layout definitions for all media */

@import url(../../yaml/core/slim_base.css);

@import url(all/yaml_basemod.css);

@import url(all/brasato.css);

@import url(all/olat.css);

@import url(all/content.css);

/* print specific adjustments */

@import url(../../yaml/core/slim_print_base.css);

@import url(print/yaml_basemod_print.css);

@import url(print/brasato_print.css);

@import url(print/olat_print.css);

/* aural styles */

@import url(aural/brasato.css);

@import url(aural/content.css);

Theme validity

A valid theme must provide the following files:

  • layout.css: The main CSS file that includes all other CSS files

  • patches.css: The patch CSS file for IE browsers that include the IE specific fixes

  • all/content.css: The definition for content formatting. This file must exist under this path to make it available to the TinyMCE HTML editor

  • favicon.ico: The site icon displayed in the browser location bar

The default theme

The default theme is located under webapp/static/themes/default/. It contains rules for every component of the brasato framework and the OLAT application.

In the first line of the theme, the YAML framework is included followed by rules for overriding the default YAML rules. Then, the brasator framework component rules are added and after that the OLAT application rules. The content rules are included last.

The default layout serves you as a case study how to write your own theme, however in most cases it does not make sense to redefine everything. Instead, in the first line of your theme you include the default theme and only override the styles that you want to change.

A custom theme

For your convenience we provide an example custom theme. The example theme is located under webapp/static/themes/example/.

Instead of redefineing everything, the example theme overrides CSS classes from the default theme to modify the look of the application. In the first line of the layout.css you will find a rule to include the default theme. Then, some rules are overriden in the theme. Typical rules you want to override are:

  • Font face

  • Page, header and footer backgrounds

  • Site navigation tabs

  • Link color

Since every image in OLAT is defined using CSS rules it is possible to change the entire icon set by the theme.