Theme & Scheme

In the Style Guide, we differentiate between the terms theme and scheme (short for color scheme).

A theme is a domain specific design scheme. Each domain can have its own theme.

A scheme is a color scheme for a theme. Usually there is a light and a dark color scheme, which can be displayed user-specifically.

Theme

The components of the Style Guide are (mainly) implemented for general use and according to best practice methods.

Font sizes are an example of best practice values. It is generally recommended that the root font size is 1rem. See the implementation in _variable.scss and _root.scss.

Based on these basic implementations, the design of a component can be adapted to the needs of a domain. The sum of these adjustments for a domain are referred to as a theme.

For example, the root font size in the finanzen.net theme is defined as 14px. See the implementation in the theme files _variable.scss and _root.scss.

Base Theme

Almost all components are implemented according to best practice values.

Exceptions are highly specific components that only appear in one theme, for example Details Navigation.

By implementing the components as generally as possible, their reuse in the themes is improved.

Same scripting on all themes

Each component is implemented in such a way that its behavior is always the same. That means we don’t differentiate between different themes in scripting.

That means all themes use the implementation of the base theme scripting.

An example of this is the Accordion component. It doesn’t matter whether the accordions should be open/close in the toggle mode on one domain and open/close normally on another domain. The scripting on both domains is the same, see accordion.ts.

private toggle(item: AccordionItem): void {
  const { isClosing, isOpening } = this.items.get(item);
  const isOpen = this.isOpen(item);
  const isClose = !isOpen;

  if (isClose || isClosing) {
    this.expand(item);

    const accordion = this.getAccordion(item);
    // -------------------------------------------------------
    // The open/close behavior of the accordion is not checked
    // during a build of the scripts or during the initialization
    // phase of the component, but during runtime.
    // -------------------------------------------------------
    if (this.isToggler(accordion)) {
      this.shrinkAccordion(accordion, [item]);
    }
  } else if (isOpen || isOpening) {
    this.shrink(item);
  }
}

Override design in SCSS

Unlike scripting, the components in the styles are implemented in advance in such a way that they can be easily overwritten. Certain unchangeable properties can be set directly and the modifiable properties are defined via custom properties.

An example of this implementation is the Accordion component. The items of an accordion are basically implemented as a flex column. However, the spacing between items is variable, see _accordion-styles.scss. In the default theme the distance between the individual items is defined with a distance of 0, see _accordion-custom-properties.scss. In the finanzen.net theme, on the other hand, the distance is overwritten with a value of 0.75rem, see theme file _accordion.de.scss.

  .accordion {
    /// flex & column are fixed properties
    display: flex;
    flex-direction: column;
    /// gap has the value "var(--sg-accordion-item-gap, 0)" and can be override
    gap: cp.access($component-name, item-gap, $default-light-scheme);

    /// ...
  }

Build themes and component in-/excluding

Different bundle files can be built during the build process of the Style Guide. In general, a CSS and JS file is built for each theme. In these bundles, it can be precisely defined which components should be integrated and which should not be integrated.

ATTENTION currently there is still an error in the exclusion of components in the JS bundle files.

You can even split a theme into different bundle files.

Here is an example from one of three bundle files from the finanzen.net theme:

/// style-net-core.scss
@charset "UTF-8";

@use "./5.theme/finanzen-net/finanzen-net" as finanzen-net;
@use "./5.theme/components" as components;

@include finanzen-net.theme(
  $theme-selector: "",
  $components: components.set(
    // base
    $fundamental-styles: true,
    $root: true,
    $typography: true,
    // component
    $ad: true,
    $button: true,
    $image: true,
    $menu: true,
    $side-panel: true,
    // layout
    $page-content: true,
    $page-header: true,
    $page-layout: true
  )
);

A detailed listing of the themes and their bundle files can be found in the themes chapter.

(Color) Scheme

In a color scheme, a distinction is generally made between a light and a dark mode.

Each component has a light color scheme implementation in the base theme. In addition, each component can have a base theme dark color scheme implementation. The overwritten themes can also overwrite these basic implementations in light and dark.

prefers-color-scheme and scheme toggler

There are basically two ways of distinguishing whether a component can be displayed in dark or light mode.

The first method uses the browser’s settings and changes a component based on its settings. The following example shows how to customize a component’s background color based on the prefers-color-scheme media query.

:root {
  --sg-button-color: white;
  --sg-button-background: darkgray;
}

@media (prefers-color-scheme:dark) {
  --sg-button-color: black;
  --sg-button-background: lightgray;
}

.button {
  color: var(--sg-button-color);
  background: var(--sg-button-background);
}

The second method uses a toggle button on the web page that allows the user to change the settings at will.

:root, .sg-light-scheme {
  --sg-button-color: white;
  --sg-button-background: darkgray;
}

.sg-dark-scheme {
  --sg-button-color: black;
  --sg-button-background: lightgray;
}

.button {
  color: var(--sg-button-color);
  background: var(--sg-button-background);
}

The Style Guide uses both methods. These are also seen as best practice. Accordingly, the source code looks like this:

:root {
  --sg-button-color: white;
  --sg-button-background: darkgray;
}

.sg-dark-scheme {
  --sg-button-color: black;
  --sg-button-background: lightgray;
}

@media (prefers-color-scheme:dark) {
  --sg-button-color: black;
  --sg-button-background: lightgray;

  .sg-light-scheme {
  --sg-button-color: white;
  --sg-button-background: darkgray;
  }
}

.button {
  color: var(--sg-button-color);
  background: var(--sg-button-background);
}

For less file size, we set the default theme light scheme values in the custom property fallback values.

.sg-dark-scheme {
  --sg-button-color: black;
  --sg-button-background: lightgray;
}

@media (prefers-color-scheme:dark) {
  --sg-button-color: black;
  --sg-button-background: lightgray;

  .sg-light-scheme {
  --sg-button-color: white;
  --sg-button-background: darkgray;
  }
}

.button {
  color: var(--sg-button-color, white);
  background: var(--sg-button-background, darkgray);
}

For more information, see the implementation in _color-scheme.scss.

Scheme Toggler Button & Key Shortcuts

The user-specific switch between dark and light mode can be implemented using native Style Guide methods. There is either the always active key shortcut and the optional color scheme toggler.

With the key combination CTRL+ALT+s you can switch between the light and dark mode.

In addition, if required, you can select a clickable element on your website to which you can add the data attribute [data-sg-scheme-toggle]. If the style guide finds this attribute while page load, it adds a click event to the element, which also toggles the dark and light mode. If dark mode is active, the attribute [data-sg-scheme-toggle-active] is automatically added to the element, or removed if you switch to light mode.

In addition, the ColorScheme class uses the Observer Pattern, which allows you to listen to the current state of the selected color scheme via scripting.

In the following example we show you an implementation of how to implement a scheme toggle button:

<button class="button button--icon button--pill button--flat" data-sg-scheme-toggle>
  <span class="icon icon--sun display-none"></span>
  <span class="icon icon--moon display-none"></span>
</button>
<style>
  window.styleGuideCallbacks = window.styleGuideCallbacks ?? [];
  window.styleGuideCallbacks.push(() => {
    const Observer = window.styleGuide.Observer;

    class SchemeToggleButton extends Observer {
      constructor() {
        super();

        this.toggler = document.querySelector('[data-sg-scheme-toggle]');
        this.sun = this.toggler?.querySelector('.icon--sun');
        this.moon = this.toggler?.querySelector('.icon--moon');
        this.toggler?.addEventListener('click', () => this.toggle());
        this.toggle();

        window.styleGuide?.colorScheme?.addObserver(this);
      }

      get darkModeActive() {
        return this.toggler?.hasAttribute('data-sg-scheme-toggle-active') ?? false;
      }

      toggle() {
        const darkModeActive = this.darkModeActive;

        this.sun?.classList.toggle('display-none', !darkModeActive);
        this.moon?.classList.toggle('display-none', darkModeActive);
      }

      update() {
        this.toggle();
      }
    }
    const schemeToggleButton = new SchemeToggleButton();
    window.styleGuide.colorScheme.addObserver(schemeToggleButton);
  });
</style>

Store Selection

The color scheme selection will store in the local storage.

Fast JS DarkMode Snipped

If you add the following code snipped in top of the <head>, the switch between dark/light mode while page load is extremely fast.

<script>
  document.documentElement.classList.toggle('sg-light-scheme', localStorage.getItem('sg-dark-scheme') === '0');
  document.documentElement.classList.toggle('sg-dark-scheme', localStorage.getItem('sg-dark-scheme') === '1');
</script>

Build Infos

A component’s color scheme is component specific and theme specific. This means that if add a component of a theme in a bundle file, both schemes of the component are always included in the bundle.