The earlier update to the DocRaptor pipeline used by DoX CMS allows you to use CSS variables and calculations with it when you compile PDF publications. The other publication formats which are compatible with these functions are PDF files made with the default compiler, and online publications in the form of HTML and WebHelp. This update is a good reason to get familiar with these features of CSS.
CSS variables are reusable standardized values defined inside style sheets. You can add situational values for them if needed. These variables have nothing to do with the variables in DoX CMS which remain non-functional in style sheets. Basic examples of how you can use CSS variables include standardized color codes and mutually coordinated measurements such as indentations that involve different implementations.
Calculations, on the other hand, are a method to determine numerical values. You can relate values used elsewhere to each other or use other mathematical functions. They can be used to, for example, combine values in different units into one value or to reference the values of multiple CSS variables.
This lets you avoid repeating related values. When you update such values, you need not track them separately in each related position. You can also derive such values from other values which makes the derivative values automatically update according to changes in the directly controlled values.
I will discuss the related syntax and examples of how to aid your documentation with it in relation to both features.
CSS variables
Each CSS variable consists of a name and a value which you can adjust for different contexts. You must define such variables in relation to a selector that includes every position where you will use them. You should thus set their default values in relation to a root element such as the body element. You can add exceptions to this value for selectors that match where you need them to apply.
You thus deploy CSS variables in the way I show below. It requires two hyphens before a name. You add values for them in the same way as for other rules in CSS. The selector defines where this value applies to that variable. Here is an example of such notation:
body {
--example_variable: 20px;
}
.dita-table {
--example_variable: 5px;
}
At this time, the color codes in the CSS editor that DoX CMS includes do not register variables as rules. Because of this, they can break the colors for the rest of the style sheet in the editor even though this does not affect whether those rules work. I thus recommend that you use a separate style sheet to define the values for variables. You can also add them at the end of a style sheet. The effect does not occur when you add variables as values elsewhere.
To use these variables as values elsewhere, you must add the frame ‘var()’ around their names. This lets you set the variables as the values or parts thereof for other rules. When the value of the variable changes, so do the values for such rules. Here is an example of such notation:
p, .topicBodyWrapper > div {
margin-left: var(--example_variable);
}
td > p {
padding: var(--example_variable);
}
You can also use variables inside other other variables. For example, the values of several variables can be combined into one variable which you can use when all those values are needed. The value of a variable can also be derived from that of another variable with a calculation.
More information about CSS variables is available at W3C.
Example implementations: CSS variables
These are examples of different ways to utilize CSS variables. I will not include methods which involve calculations. I will discuss how to use variables with calculations separately as part of how calculations work.
Standardized values
This is the simplest way to use CSS variables. If you must use the same value in multiple positions, you can make it into a variable. This is especially helpful when those values are complex or otherwise hard ot remember. The example that I provide below shows how to make brand colors into variables. This lets you refer to them by name rather than with unintuitive color codes.
body {
--brand_green: #485f48;
--brand_black: #171717;
--brand_yellow: #fffdd0;
}
.topicTitleWrapper {
color: var(--brand_black)
border: 2px solid var(--brand_black);
border-left: 5px solid var(--brand_green);
}
Changed values
You can change variables’ values for different contexts. At first, the benefit of this may seem minimal because you could instead just apply values other than the variable to related rules there. It does prevent repeating the related rules, however. Also, if you use the same values for different rules such as the color of both title text and borders, you only need to update the value once this way.
Element classes
Just as with any situational change, you can use element classes to set different values for variables. The example below does this with the column widths of simpletables. This lets you specify multiple templates for table layouts without a need to repeat any of the complex selectors and sets of rules involved. My example only includes rules for the first two columns in two different element classes.
body {
--column1: auto;
--column2: auto;
}
table {
width: 100%;
table-layout: fixed;
}
table:not(.dita-table table) td:nth-child(1) {
width: var(--column1);
}
table:not(.dita-table table) td:nth-child(2) {
width: var(--column2);
}
[doxelementclass~="IconTable"] {
--column1: 20%;
--column2: 5%;
}
[doxelementclass~="CommandTable"] {
--column1: 40%;
--column2: 60%;
}
Device-specific values
Similar solutions are also available to adjust online publications for different devices. In this case, you specify the new values for the variables in relation to different devices. The example included below does so for title sizes. Of course, for such purposes, it would be easier to use calculations for derivative values.
body {
--level1title: 24px;
--level2title: 20px;
}
.titleWrapper_Level1 {
font-size: var(--level1title);
}
.titleWrapper_Level2 {
font-size: var(--level2title);
}
@media only screen and (max-width: 800px) {
--level1title: 18px;
--level2title: 16px;
}
Adaptable single-sourced content
I have previously showed how you can change the values of variables based on where they are used within the same publication here. A solution like this lets you insert parts that change depending on where they are used to otherwise standardized sentence templates. The structure of the sentence remains single-sourced but these changes apply in the different positions where it gets used. An alternative method to achieve this involves CSS variables. Please note how the parts added like this cannot be subject to grammatical changes.
This implementation involves expressions that you add through the style sheet to otherwise empty phrase (ph) elements with matching identifiers. I recommend that you use element classes for such identifiers. For this section to remain single-sourced, you cannot add the element classes which control its value directly to it. You must add them to wrappers outside it such as section elements. You must then also add an identifier for the correct parts within that wrapper, though. The rules in the style sheet used for this add content to these elements as ::before pseudoelements. When a CSS variable is used for these values, you must also specify language-specific values for it. There is an example implementation below.
[doxelementclass~="Menu_Editor"] span[doxelementclass~="InsertContent"]::before {
content: var(--menu_editor);
}
[doxelementclass~="Menu_Tags"] span[doxelementclass~="InsertContent"]::before {
content: var(--menu_tags);
}
span[doxelementclass~="InsertContent"]::before {
text-transform: capitalize;
}
[lang="fi"] [doxelementclass~="Menu_Editor"] {--menu_editor: "editori";}
[lang="fi"] [doxelementclass~="Menu_Tags"] {--menu_editor: "editori";}
[lang="en"] [doxelementclass~="Menu_Editor"] {--menu_editor: "editor";}
[lang="en"] [doxelementclass~="Menu_Tags"] {--menu_editor: "editor";}
Just in case, I will also include a demonstration of what kind of content these rules will require. This demonstration includes both the source version used for the content reference (conref) that keeps the content single-sourced, and one example of a target version with an appropriately marked wrapper. The mention of ‘#333’ simply refers to the ID value of the topic that I used for the source version.
<p id="system_toolbar_open_menu">Click on the related icon in the system toolbar to open the <ph doxelementclass="InsertContent"/> menu.</p>
<section doxelementclass="Menu_Editor">
<p conref="#333/system_toolbar_open_menu"/>
</section>
Coordinated layouts
When some values use variables, you can also apply the same variables elsewhere in ways which must match their original usage. If you keep the values of involved variables the same between such applications, you can coordinate the layouts of different pieces of content with their help. For example, you can use the same variable for both the width of note elements’ non-repeating background images and the indentation of their content. This makes the content always be indented past the width of its icon and the two will never overlap. A calculation lets you increase the indentation by a standardized amount.
This method keeps the relationship between specified elements constant regardless of the involved values. Such mutual coordination makes it easier to change these values to, for example, adjust the content layout based on the used viewport. It also makes updates to such values easier because the other values coordinated in this way update accordingly simultaneously.
The example I present below makes the indentation of titles relative to their number values the same as where other content starts. I also added the variable used to do this inside a different variable to show how that functionality works. This implementation uses no calculations, but they are helpful as part of similar solutions.
body {
--BaseIndent: 25mm;
--ContentPadding: 2mm 10mm 2mm var(--BaseIndent);
}
.titleWrapper .titleNumberWrapper {
width: var(--BaseIndent);
}
.topicBodyWrapper > *:not(.dita-section), .dita-section > * {
padding: var(--ContentPadding);
}
Calculations
Calculations let you form numerical values with or without units according to mathematical functions. You can include sums, deductions, multiplication, and division. The allowed values for use inside them are numbers, which may include units, and CSS variables with values in that format. Calculations also allow you to combines values with different units. You can, for example, add extra width in millimeters on top of a hundred percent when you need an element to stretch past the borders of its wrapper.
You add calculations to style sheets in the same way as values for rules in general. Their format involves a calculation inside the frame ‘calc()’. You must separate the values and special characters that constitute such calculations from each other with empty spaces. If you add a different calculation inside the main calculation, or you must change the order of operations, you can add additional parentheses around the related portions. Negative values are allowed. You can also add additional empty spaces and line breaks inside calculations.
These are the special characters used for different operations:
- X + Y: the sum of X and Y
- X – Y: Y deducted from X
- X * Y: X multiplied by Y
- X / Y: X divided by Y
As such, calculations in CSS may look like this, for example:
h2 {
font-size: calc(var(--TitleBaseSize) * 0.8)
}
More information about these calculations is available at W3C.
Example implementations: Calculations
These are some examples of different ways to utilize calculations in style sheets.
Clearer expressions
How much is one seventh of hundred percent? You can calculate the result in advance and write it as is in the style sheet. If anyone who reads the style sheet is not thinking of the answer, though, they might have issues inferring what the value ‘14.3%’ refers to. An explicit calculation for this value, on the other hand, expresses the intent directly. This also applies to values derived from several other values, such as their combined length. I will discuss such examples in more detail later.
This example is the same as the previous one, except that I replaced the variable with its value. I strongly recommend the use of variables. The used notation also demonstrates to the reader of the style sheet how the final value is derived from another one. It is not an arbitrary smaller value.
h2 {
font-size: calc(24px * 0.8)
}
Combine units
The values for calculations can involve more than one unit. The final value can combine values that use different units. These values can also mix both relative and absolute units such as percentages and millimeters. This lets you combine CSS variables that have values in different units. The benefit of this is how mutually coordinated values can be expressed in more than one unit. In the same vein, these values themselves can include different units, such as specific relative and absolute units, whenever there is reason to do so.
The example below shows a value which extends large images past the limits of text container around it. Do note how you should also center such images horizontally. My example does not include the rules for that.
.dita-fig img {
width: calc(100% + 20mm);
}
Relative dimensions
When a calculation includes variables, you can calculate the new value relative to their values. Values derived in this way scale properly when the used baseline values from involved variables change.
This lets you, for example, move the position of an element in relation to the width of another element. A planned update to our own manual involves such portions. They are especially helpful in online publications in which some elements can be positioned outside the standard text wrap. The example that I present below moves note elements with the fastpath type next to other content. This makes them into always available containers for links to different parts of long topics.
body {
--FastpathPosition: calc(var(--TopicWidth) + var(--TopicRightMargin));
--TopicRightMargin: 5vw;
--TopicWidth: 55vw;
}
.topicWrapper {
width: var(--TopicWidth);
margin-right: var(--TopicRightMargin);
}
[data-ditaatribute-type="fastpath"] {
position: fixed;
right: var(--FastpathPosition);
}
Animations
Animations done in CSS usually require you to define values for different phases. The values for the transitions between them get calculated based on the specified time and these keyframe values. Calculations let you determine the target values relative to the initial value. In this case, these values need not be calculated or estimated beforehand, and the underlying intent is expressed more clearly like I showed above.
This simple example shows how you can make an image grow at a specified rate when the cursor moves over it. I limit this functionality to images inside figure elements. This implementation does show the animation for reducing image size when these images are first loaded in, though. There are ways around this. However, I am just using this implementation for demonstration purposes.
body {
--FigImageWidth: 20vw;
--FigImageWidthHover: calc(var(--FigImageWidth) * 3);
}
@keyframes FigImageHover {
from {width: var(--FigImageWidth);}
to {width: var(--FigImageWidthHover);}
}
@keyframes FigImageHoverLeave {
from {width: var(--FigImageWidthHover);}
to {width: var(--FigImageWidth);}
}
.dita-fig > p img {
animation: FigImageHoverLeave 1s forwards;
width: var(--FigImageWidth);
height: auto;
}
.dita-fig > p img:hover {
animation: FigImageHover 1s forwards;
}
Summary
CSS variables and calculations are available for various PDF and HTML publications. The updated DocRaptor pipeline in DoX CMS also lets you use them. They let you specify standardized and mutually coordinated values as well as derivatives of them in style sheets.
In addition to standardized values, CSS variables support include situational changes to these values without the need to repeat related complex selectors or rules. You can link such adaptations to element classes or differences in viewports in particular. They also allow you to add expressions that change based on the context within a document to otherwise single-sourced parts, as well as values which are coordinated between different rules and for different elements.
Calculations let you add mathematical functions to style sheets. These calculations can also contain CSS variables. This makes their results change when the values of included variables change. Calculations let you present calculated values more clearly than just those results, to combine values with different units, relate values to each other, and to provide keyframe values for CSS animations as modifications of related baseline value.