Skip to main content

Create Appearance-compatible custom CSS and Themes

caution

This page is a work-in-progress for Bloom 6.0. Information subject to change.

note

Please see this page for a more introductory explanation of the Bloom Appearance system: The Appearance System

caution

This is a very technical note, intended only for Publishers with technical staff.

How the Appearance System works

Each Theme is a CSS file that sets the value of one or more Appearance properties.

Each book has an appearance.json file that can contain the same set of properties in JSON form. It also includes a property to indicate the currently selected theme.

As you customize settings in the “Book Settings” dialog, Bloom updates that appearance.json. Note that the user interface only shows a small number of available Appearance settings. Instead, most settings are controlled by the theme that you choose.

When Bloom displays a book, it converts that appearance.json and the chosen theme into a CSS file named appearance.css.

The HTML page then applies these stylesheets in this order (last wins, all other things being equal):

  1. basePage.css or basePage-legacy.css
  2. appearance.css
  3. customBookStyles.css, customBookStyles2.css

Precedence

A challenge in modern Bloom is that there are a number of things that each influence the final display of a page. These things may even be wanting opposite things to happen. What happens if the Book Settings Dialog is used to turn something on, but a custom css is used to turn it off? Who wins?

Since ultimately CSS is involved, the answer is complicated by CSS specificity rules. But given the same specificity, here is the order of precedence for the various sources ( >> here means “has precedence over”):

note

xmatter HTML >> customBookStyles.css >> xmatter.json >> branding.json (.appearance) >> Book Settings (appearance.json) >> Theme (foobar.css)

Why is xMatter pug the ultimate winner? This is because, if an xMatter doesn’t have an HTML element for something, it can’t be CSS’ed or JSON’ed into existence.

Notice that Theme’s position in the list. Not only is it last, but actually any property that appears in Book Settings will win over that described in the Theme, unless CSS specificity rules cause it to overcome the Book Settings.

note

Avoid putting things in a theme that are also part of Book Settings. Be aware that in a future version, a given property may become available in Book Settings and therefore will override that setting in an older theme, unless we create a value for the Book Settings control that means “I don’t care”. Such a value is likely for things like page-background-color.

Creating a new Theme

note

If you cannot get what you need using the Book Settings UI or by choosing a theme, first, talk to us. We may advise a different solution, or we may direct you to use the following directions.

If it doesn’t already exist, create a customBookStyles.css in the root of the book folder. Use an editor that understands CSS will show you any errors. We highly recommend Visual Studio Code (it is free). The basic template is:

.bloom-page {
/* set properties here*/
}

For example, imagine that we want to draw a dashed red box around the “Margin Box”

.bloom-page {
--marginBox-border-style: dashed;
--marginBox-border-color: red;
}

What if we need something special in Device16x9Portrait versions of the book? For this, we add a rule group that selects for that:

/* default */
.bloom-page {
--marginBox-border-style: dashed;
--marginBox-border-color: red;
}
.Device16x9Portrait {
--marginBox-border-style: solid;
}

If you set a variable that is a dimension, like --page-margin or --page-gutter, it must have some unit, such as px or em or mm or in. Contrary to usual CSS advice, you must give a unit even if setting the variable to zero. Although it seems redundant (0px = 0em = 0mm = 0in), the browser fails when doing any arithmetic with variables that are supposed to be dimensions but lack a unit, so setting such a variable to zero can have unexpected results that are difficult to diagnose, such as rules that appear to apply but don’t do anything.

We are trying to standardize on mm as the unit for measurements that should not related to font size, and em for ones that should. Following this convention may help with future compatibility if we add a UI control for the variable you are using.

As before, it is still possible to write arbitrary CSS rules based on what you find in Bloom HTML. However, we really need to move away from that practice. Instead:

caution

Before writing CSS rules that use anything other than the official Appearance properties, please consider asking us to add an Appearance property for what you are trying to do. This will lead to a more sustainable Bloom ecosystem.

caution

Problems with unconstrained “custom CSS” For a long time, highly technical Bloom users have been able to go “under the hood” to make tweaks to page layout and styling using the Web’s “Cascading Style Sheets” (CSS) language. This system is useful as a last resort, but it has several problems, including:

  • We find that many of the custom CSS files in books uploaded to BloomLibrary.org are actually riddled with errors, indicating that this feature is being used by organizations that lack the tools or expertise to do it properly.

  • It is difficult for us to add friendly UI controls over settings that compete with settings that may be in the custom CSS files.

  • CSS rules often depend on how we implemented lower-level Bloom CSS and page HTML. This reliance prevents us from improving Bloom with simpler or more modern approaches.

Appearance Properties

Variable NameTODO: Changes to names
nouns camelCase
dimensions separated by dashes
mostGeneral-moreSpecfic-even-moreSpecific-property

We decided to use natural property names, so “horizontal-gap” instead of “gap-horizontal”
Use RestrictionsDescriptionIn Themes and Custom CSSIn Book Settings UI
--cover-margin-bottom⚠️Themes should not try to change cover pages— else users may have a confusing clash with xmatter, branding, and book settings customizations.padding-bottom value for outside front and back cover pages. [default is 12mm]6.0
--cover-margin-toppadding-top value for outside front and back cover pages. [default is 12mm]6.0
--coverShowLanguageName--cover-languageName-show⚠️Themes should not try to change cover pages— else users may have a confusing clash with xmatter, branding, and book settings customizations.display value for the language name on the front cover (none to hide or inline-block to display in a default manner). [default is inline-block, a keyword]6.0
--coverShowTitleL2--cover-title-L2-show⚠️Themes should not try to change cover pages— else users may have a confusing clash with xmatter, branding, and book settings customizations.display value for the Language 2 title on the front cover (none to hide or block to display in a default manner). [default is block, a keyword]6.0
--coverShowTitleL3--cover-title-L3-show⚠️Themes should not try to change cover pages— else users may have a confusing clash with xmatter, branding, and book settings customizations.display value for the Language 3 title on the front cover (none to hide or block to display in a default manner). [default is none, a keyword]6.0
--coverShowTopic--cover-topic-show⚠️Themes should not try to change cover pages— else users may have a confusing clash with xmatter, branding, and book settings customizations.display value for the topic on the front cover (none to hide or inline-block to display in a default manner) [default is inline-block, a keyword]6.0
--cover-creditsRow-show⚠️Themes should not try to change cover pages— else users may have a confusing clash with xmatter, branding, and book settings customizations.display value for the credits on the front cover (none, a keyword, to hide) [default is to show]
--image-border-radiusborder-radius for images added by the user to the front cover or to a content page [default is 0px, for square corners]6.0
--marginBox-background-colorbackground-color for content on numbered pages, including behind text boxes, between text boxes, behind partially transparent pictures, and between text boxes and pictures. [default is transparent]6.0
--marginBox-border-colorborder-color for borders around text boxes on numbered pages. [default is black]6.0
--marginBox-border-radiusborder-radius for borders around text boxes on numbered pages. [default is 0px, for square corner]6.0
--marginBox-border-styleborder-style for borders around text boxes on numbered pages (typical values include solid, dashed, dotted, and none). [default is none, a keyword, to hide the border]6.0
--marginBox-border-widthborder-width for user text boxes on numbered pages (typical values include 3px, 1mm, thin, medium, or thick). [default is medium]6.0
--marginBox-paddingpadding for text boxes on numbered pages. [default is 0px]6.0
--multilingual-editable-vertical-gapThe space between the different language sections of each block when Bloom is configured to show each block of text in more than one language. [default is 10px]6.0
--page-background-colorbackground-color for the full content of all pages. [default is _white]_6.0
--page-gutteradditional inner margin for pages of a book. [default is 0mm since most Bloom books are too small to need a gutter, or are published as e-books that inherently don’t need a gutter]6.0
--page-marginmargin for all pages. Aspects can be overriden by the more specific --page-margin- and —cover-margin- properties.6.0
--page-margin-bottompadding-bottom for inner pages, i.e., not outside cover pages, but including inside cover pages. [default is 12mm]6.0
--page-margin-leftbasic padding-left for all pages. It is added to --page-gutter for left-side pages. Also used for padding-right for pages which are inherently symmetrical left vs right. These include outside cover pages, calendar pages, Device16x9… sized pages, etc. [default is 12mm]6.0
--page-margin-rightbasic padding-right for all pages. It is added to --page-gutter for right-side pages. [default is 12mm]6.0
--page-margin-toppadding-top for inner pages, i.e., not outside cover pages, but including inside cover pages. [default is 12mm]6.0
--page-horizontalSplit-heightpadding-top for the lower section when a page is split horizontally into upper and lower sections. [default is 3px, chosen conservatively to match what 5.6 had… could easily argue for 0] Normally it’s better to use --text-padding instead.6.0
--page-verticalSplit-widthpadding-left for the right-hand section when a page is split vertically into left and right sections. [default is 3px]6.0
--pageNumber-always-left-marginleft value for displaying page numbers on right side pages. This is the distance between the left edge of the page and the page number. This allows page number to always be on the left, regardless of page side. The auto keyword works for this value, but nothing works unless --pageNumber-right-margin is set to the unset keyword. If this is used, --pageNumber-right-margin must be set to unset, a keyword. [default is unset, a keyword]6.0
--pageNumber-background-colorbackground-color for displaying the page number. [default is transparent]6.0
--pageNumber-background-widthused for both height and width in displaying the page number. This setting usually doesn’t matter unless --pageNumber-background-color is set to something other than transparent. [default is unset, a keyword]6.0
--pageNumber-border-radiusborder-radius for displaying the page number. This usually doesn’t matter unless --pageNumber-background-color is set to something other than transparent. [default is 0px, producing square corners]6.0
--pageNumber-bottombottom value for displaying the page number. This is the distance between the bottom of the number and the bottom of the page. Either --pageNumber-bottom or --pageNumber-top should be set to a length value, and the other set to unset, a keyword. [default is 10px]6.0
--pageNumber-font-sizefont-size for displaying the page number. This can be expressed exactly as in the default value, or using units of em for sizes relative to the parent element or rem for sizes relative to the body element. If not set, the body element defaults to a font size of 16px. In this case, 1.1666667rem would roughly equal 14pt for the standard 96dpi screen. If the body font-size is 10pt, then 1.4rem would equal 14pt. [default is 14pt]6.0
--pageNumber-left-marginleft value for displaying page numbers on left side pages. This is the distance between the left edge of the page and the page number. The auto keyword works for this value. [default is auto, a keyword]6.0
--pageNumber-right-marginright value for displaying page numbers on right side pages. This is the distance between the right edge of the page and the page number. If this is used, --pageNumber-always-left-margin should be set to unset, a keyword. The auto keyword does not work for this value. [default is var(--page-margin-right), which makes it the same as the current value of --page-margin-right]6.0
--pageNumber-showCSS display value for the page number. The default is to show the page number on numbered pages. Set to none (a keyword) to hide the page numbers.
--pageNumber-toptop for displaying the page number. This is the distance between the top of the number and the top of the page. Either --pageNumber-bottom or --pageNumber-top should be set to a length value, and the other set to unset, a keyword. [default is unset, a keyword]6.0
-pageNumber-extra-heightHow much should the marginBox shrink to leave room for the page number?
TODO: Add this
-textOverPicture-padding
See BL-12948
--topLevel-text-paddingOnly applies to boxes boxes that aren’t nested inside other boxes. (This is so that it doesn’t interfered will little grid boxes, orgami-based dictionaries, etc.) [default is 1em. Therefore it grows with the size of the font.] See example screenshot below. Can override with the next 4 as needed.6.0
--topLevel-text-padding-topSpace added at the top of a text when there is another box above it. [default is --text-padding-default]6.0
--topLevel-text-padding-bottomSpace added at the bottom of a text when there is another box below it. [default is --text-padding-default]6.0
--topLevel-text-padding-leftSpace added at the left of a text when there is another box to the left of it. [default is --text-padding-default]6.0
--topLevel-text-padding-rightSpace added at the right of a text when there is another box to its right. [default is --text-padding-default]6.0

Examples

Selectors

Root Selector

.bloom-pageThis is the root that applies to every page. Use this instead of ::root which is normally recommended in CSS documentation. ::root will appear to work, but may fail Bloom Reader.

Special Page Selectors

.outsideFrontCover
.insideFrontCover
.titlePage
.credits
.insideBackCover
.outsideBackCover

Page Size / Layout Selectors

.A5Portrait
.A5Landscape
A4Portrait
A4Landscape
A3Portrait
A3Landscape
B5Portrait
LetterLandscape
LetterPortrait
HalfLetterPortrait
HalfLetterLandscape
QuarterLetterLandscape
QuarterLetterPortrait
Device16x9Portrait
Device16x9Landscape
A6Portrait
A6Landscape
Cm13Landscape
USComicPortrait
Size6x9Portrait
Size6x9Portrait
.bloom-page[class*="Device"]Apply only to Device layouts
.bloom-page:not([class*="Device"])Apply only to non-Device layouts
.bloom-page[class*="Landscape"]Apply only to Landscape layouts
.bloom-page[class*="Portrait"]Apply only to Portrait layouts

Migrating old custom CSS

If you have existing customBookStyles.css files, here are some of the main considerations for moving to the Appearance system. First, just try opening your book in Bloom 6.0 (or later). Go to the book settings dialog and see whether the page theme is Default, Legacy (Bloom 5.6), or something else. If it’s something other than Legacy (Bloom 5.6), you’re lucky… we already did the migration for you. It would be good to check that you like the results and see if there’s anything you want to tweak, but you shouldn’t need to do any more, unless you want to clean up padding, as described in the release notes.

If you see “Legacy (Bloom 5.6)” then your book is, for the moment, stuck in the old days. It is using custom CSS that’s not compatible with the Appearance system. Some things in the Book Settings dialog are already disabled, and it’s likely that more new capabilities won’t work over time. We would encourage you to switch over.

The first thing to try is just to change the theme to Default. (You could also try some of the others.) This will disable your custom CSS and give you one of the new layouts. One of them might be close enough, especially if you make use of the new Book Settings! Then you can just discard your custom CSS. (Or if you or colleagues are still using 5.6 to work on this book, you may want to keep it until 6.0 moves from Beta to Release.)

If you still want custom CSS, we encourage you to see what you can do by setting the variables described above. If you want to do something that can’t be done with them, we’d like to know about it… maybe we can add some more variables.

In particular, books get locked into the legacy theme mainly if their customBookStyles.css sets the position and size of the margin box. You can replace such rules using the Appearance system… usually much more easily. For example, if you want just 2mm of margin around your page, and 5mm more on the bottom to show page numbers, in the old system you’d need something like

.Device16x9Portrait .marginBox {
top: 2mm;
left: 2mm;
width: ?mm; /* width of a Device16x9 portrait page minus 4mm */
height: ?mm; /* height of a Device16x9 portrait page minus 9mm */
}
/* and maybe */
.Device16x9Portrait.titlePage,
.Device16x9Portrait.creditgsPage {
height: ?mm; /* height of a Device16x9 portrait page minus 4mm, not leaving room for page number */
}
.A5Portrait .marginBox {
/* ...needs different width and height for a different page size */
}

/* And similarly for any other page sizes you care about */

In the Appearance system, you can just do

.bloom-page {
--page-margin: 2mm;
--pageNumber-extra-height: 5mm;
}

/* if you want a bigger margin on A4 you can do it, but the above will work for all sizes where you want 2mm. */

You could also set --page-margin-bottom to 7mm, but the above is better: it will do the right thing on pages that don’t have numbers and if you use book settings to turn off page numbers.

Other things like padding don’t have to be changed; but see Bloom 6.0 Beta Release Notes for how padding has been improved and may make awkward ways of doing things unnecessary. The more you can do with the documented variables, the better your chances for compatibility with future Bloom versions and features.