Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
dsch
Product and Topic Expert
Product and Topic Expert
762

Using the open-source npm module @sap-theming/theming-base-content makes it surprisingly easy to use all SAP Fiori theming parameters in your own applications. Especially you can simply import the css_variables.css file of the theme you want and start using the custom CSS properties.

Depending on your build setup, this may have unintended side-effects. One side-effect has been raised in CSS variable files should differentiate between variables and variables that load assets: with a default bundler configuration that inlines assets into the bundled CSS file, all assets referenced by the css_variables.css file are inlined as well. As many fonts (all versions of the 72 font, and the SAP-icons) are referenced, this results in unnecessary large bundle sizes.

In this post I show how to configure postcss, the de-facto CSS bundler standard, to inline imports and assets, but ignore the assets referenced in css_variables.css.

Repository setup

Let's start from scratch.

mkdir my-project && cd my-project
npm init -y
npm i -S @sap-theming/theming-base-content

With that we get a new directory my-project in which we'll be working, that contains an empty package.json which then gets @sap-theming/theming-base-content as a regular dependency.

We will create a src/main.css which we'll be editing, and which should be bundled to target/main.css. For demonstration purposes we'll import the css_variables.css of Morning Horizon from @sap-theming/theming-base-content (which will contain asset URLs we don't want to inline) and add a url to our own code (which we do want to inline).

/* file: src/main.css */
@import url("@sap-theming/theming-base-content/content/Base/baseLib/sap_horizon/css_variables.css");
.checkers {
  background-image: url("./checkers.svg");
}

For the sake of completion, src/checkers.svg just creates black and white tiles:

<!-- file: src/checkers.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
  <rect x="0" y="0" width="50" height="50" fill="#000"/>
  <rect x="0" y="50" width="50" height="50" fill="#fff"/>
  <rect x="50" y="0" width="50" height="50" fill="#fff"/>
  <rect x="50" y="50" width="50" height="50" fill="#000"/>
</svg>

Adding postcss

To bundle src/main.css we'll be using postcss-cli with the plugins postcss-import (to inline the @import) and postcss-url (to inline the url()).

npm i -D postcss-cli postcss-import postcss-url

We want to bundle src/main.css to target/main.css, so we'll be calling

npx postcss src/main.css -o target/main.css

To add plugins to that we need a postcss.config.js in the project root. The magic part is that postcss-url is applied only to urls inside the src/ folder.

// file: postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import')(),
    require('postcss-url')({filter: 'src/**/*', url: 'inline'})
  ]
}

Now if we run postcss, css_variables.css is inlined, checkers.svg is inlined, but the assets referenced in css_variables.css are not. Just as we intended:

/* file: target/main.css */
/**
 * Copyright (c) 2012-2020 SAP SE or an SAP affiliate company. All rights reserved.
 *
 * Theming Engine 1.69.2
 * data:{"Path": "Base.baseLib.sap_horizon.css_variables", "PathPattern": "/%frameworkId%/%libId%/%themeId%/%fileId%.css", "Extends": ["baseTheme"], "Tags": ["Fiori_3","LightColorScheme"], "FallbackThemeId": "sap_fiori_3", "Engine": {"Name": "theming-engine", "Version": "1.69.2"}, "Version": { "Build": "11.1.38.20220405122918", "Source": "11.1.38"}}
 */
.sapThemeMetaData-Base-baseLib{background-image: url('data&colon;text/plain;utf-8,{"Path": "Base.baseLib.sap_horizon.css_variables", "PathPattern": "/%frameworkId%/%libId%/%themeId%/%fileId%.css", "Extends": ["baseTheme"], "Tags": ["Fiori_3","LightColorScheme"], "FallbackThemeId": "sap_fiori_3", "Engine": {"Name": "theming-engine", "Version": "1.69.2"}, "Version": { "Build": "11.1.38.20220405122918", "Source": "11.1.38"}}');}
:root{--sapThemeMetaData-Base-baseLib:{"Path": "Base.baseLib.sap_horizon.css_variables", "PathPattern": "/%frameworkId%/%libId%/%themeId%/%fileId%.css", "Extends": ["baseTheme"], "Tags": ["Fiori_3","LightColorScheme"], "FallbackThemeId": "sap_fiori_3", "Engine": {"Name": "theming-engine", "Version": "1.69.2"}, "Version": { "Build": "11.1.38.20220405122918", "Source": "11.1.38"}};}
:root {
  --sapBrandColor: #0070f2;
  --sapHighlightColor: #0070f2;
  --sapBaseColor: #fff;
  /* […] */
  --sapFontUrl_72Mono_Bold_woff: url('../../../Base/baseLib/baseTheme/fonts/72Mono-Bold.woff');
  --sapFontUrl_72Mono_Bold_full_woff2: url('../../../Base/baseLib/baseTheme/fonts/72Mono-Bold-full.woff2');
  --sapFontUrl_72Mono_Bold_full_woff: url('../../../Base/baseLib/baseTheme/fonts/72Mono-Bold-full.woff');
}
.background-image--sapCompanyLogo {
  background-image: var(--sapCompanyLogo);
}
.background-image--sapBackgroundImage {
  background-image: var(--sapBackgroundImage);
}
.background-image--sapShell_BackgroundImage {
  background-image: var(--sapShell_BackgroundImage);
}
.checkers {
  background-image: url("data&colon;image/svg+xml,%3Csvg xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22 viewBox%3D%220 0 100 100%22%3E  %3Crect x%3D%220%22 y%3D%220%22 width%3D%2250%22 height%3D%2250%22 fill%3D%22black%22%2F%3E  %3Crect x%3D%2250%22 y%3D%220%22 width%3D%2250%22 height%3D%2250%22 fill%3D%22white%22%2F%3E  %3Crect x%3D%2250%22 y%3D%2250%22 width%3D%2250%22 height%3D%2250%22 fill%3D%22black%22%2F%3E  %3Crect x%3D%220%22 y%3D%2250%22 width%3D%2250%22 height%3D%2250%22 fill%3D%22white%22%2F%3E%3C%2Fsvg%3E");
}

Recap

This shows that it is possible with proper bundler configuration to inline everything but the assets from css_variables.css.

As a little exercise we can add a second filter to postcss-url, that rewrites all URL references from css_variables.css to absolute URLs against the unpkg.com CDN:

// file: postcss.config.js
module.exports = {
  plugins: [
    require('postcss-import')(),
    require('postcss-url')([
      {filter: 'src/**/*', url: 'inline'},
      {filter: '**/content/Base/baseLib/**/*', url: ({url}) => `https://unpkg.com/@sap-theming/theming-base-content/content/Base/baseLib/${
        url.replace(/^.*\/content\/Base\/baseLib\//, '')
      }`}
    ])
  ]
}