For theme authors
How a theme works with Formulize UI: giving the tokens its values, loading the stylesheet, keeping its own rules from getting in the way of the classes, and framing the page that everything is on.
- Giving the tokens values
- Loading the stylesheet
- Keeping theme rules out of the way
- Framing the page
- Printing
Giving the tokens values
Formulize UI sets a neutral default for every token. A theme gives them its own values in a :root rule, and the colours and font set on the Appearance page then override the theme's.
- Set the tokens, rather than restyling the classes: every class is built on them, so the theme's look reaches all of them at once, and the Appearance page keeps working.
- The sizes are in rem, so the browser's font size scales them. Keep a theme's own sizes in rem too.
In the theme's stylesheet
:root {
--fz-color-accent: #0f5e9c;
--fz-color-accent-hover: #0b4a7a;
--fz-color-accent-soft: #e7f0f8;
--fz-font-sans: "Source Sans 3", system-ui, sans-serif;
--fz-radius-lg: 0.25rem;
}Loading the stylesheet
Formulize adds formulize-ui.css to its own pages. A theme adds it to every other page by calling formulize_uiStylesheetLink() in its theme.html, before the theme's own stylesheet.
- The function returns nothing on a page that already has the stylesheet, so it is never loaded twice.
- The order matters:
formulize-ui.cssfirst, then Formulize's own stylesheet, then the theme's. Where a theme rule and a class have the same weight, the theme wins.
In theme.html, in the head
<{php}>
require_once XOOPS_ROOT_PATH . '/modules/formulize/include/functions.php';
echo formulize_uiStylesheetLink();
<{/php}>
<link rel="stylesheet" type="text/css" media="all" href="<{$icms_imageurl}>css/style.css" />Keeping theme rules out of the way
Every public class is a single class selector, with no !important, so a utility or a modifier can always adjust it. A theme keeps that working by not outweighing the classes.
- Give the theme's own classes the theme's prefix, such as
lyris-, neverfz-. - When styling Formulize's own markup, wrap the selector in
:where(), which gives it no weight, so a class added to that markup still wins. - A rule that styles every element of a kind, such as every
buttonor every checkbox, would also restyle the Formulize UI components. Add:where(:not([class*="fz-"]))to it: it skips any element with a Formulize UI class, and adds no weight, so the rule otherwise works as before.
In the theme's stylesheet
/* Formulize's own markup: no weight, so classes added to it still win */
:where(#formulize-list-of-entries) td {
padding: 0.5rem 0.75rem;
}
/* Every button, except the Formulize UI ones */
button:where(:not([class*="fz-"])),
input[type="submit"]:where(:not([class*="fz-"])) {
min-width: 8rem;
border-radius: 0;
}Framing the page
The space at the edges of a page, and how wide a page can get, are the theme's to supply, in one place, for every page. No type of screen brings its own, and what people write for a screen starts at the edge of what the theme gives it.
- Put one wrapper around all of a page's content in
theme.html, and give itpadding: var(--fz-page-padding), the Appearance page's Page padding. Every type of screen then has the same space, including the types added later, and a screen inside another is not inset twice. - To offer the Page width setting, keep the same wrapper to
--formulize-content-max-width. A screen set to the full width has that property at100%on its own page. - Make the wrapper its own element, inside the part of the page that scrolls, and leave the scrolling part without padding.
- Don't put the page's space on the parts of a screen, in screen templates: a screen drawn with other templates would have none.
- On a phone the space can be smaller, and a screen made of bars and cards can run to the edges of the screen, as long as nothing in it touches them.
- The whole of this, with what Lyris does, is in What Formulize expects from a theme, in the documentation.
In theme.html
<main class="mytheme-content">
<div class="mytheme-page">
<{$icms_contents}>
</div>
</main>In the theme's stylesheet
.mytheme-page {
box-sizing: border-box;
max-width: var(--formulize-content-max-width);
margin-inline: auto;
padding: var(--fz-page-padding);
}Printing
A page can be made for printing with the Print classes, which decide what of the page's own content is on paper. The theme does the rest: on paper it leaves out its own header and menus, and lets the content run on over as many sheets as it needs.
- In an
@media printrule, hide the parts of the theme that are for getting around the site: the header, the menus, the footer. - Anything the theme makes scroll on screen stops at its own bottom edge on paper. Give it
height: autoandoverflow: visiblethere, so it is as tall as what is in it. - Take the space at the edges of the page off as well: the sheet's own margin does that on paper.
- These rules have to win over the theme's own layout whatever it is, so
!importantis at home in them.
In the theme's stylesheet
@media print {
.mytheme-header,
.mytheme-menu,
.mytheme-footer {
display: none !important;
}
.mytheme-content {
height: auto !important;
overflow: visible !important;
padding: 0 !important;
}
}