Theming Guide
A practical reference for the CSS conventions, load order, and system variables that apply to every SynaptikCMS theme.
CSS load order
The CMS injects stylesheets in this exact order, via render_header_scripts() in header.php:
css/synaptikCSS.php— combined system styles:gallery-layout.css,lightbox.css,search.css,shortcodes.csstheme/{active}/css/style.css— your theme stylesheet (with?v=mtimecache busting)
Consequence: your style.css always loads last. Any rule with equal or greater specificity overrides a system rule. You do not need !important for standard overrides — fix specificity at the selector level instead.
Consequence for shortcodes: shortcodes.css loads before your style.css. Shortcode classes (.sc-callout, .sc-button, .sc-quote, etc.) can be freely overridden in your theme.
System CSS custom properties
The CMS injects one custom property into :root at runtime:
| Property | When set | Value |
|---|---|---|
--snk-adminbar-height | Admin is logged in | 36px |
When no admin session is active, the property is not declared. Use the var() fallback syntax:
.site-header {
top: var(--snk-adminbar-height, 0px);
}
Do not declare --snk-adminbar-height in your theme — the fallback handles the default case automatically.
Admin bar offset
The CMS injects a 36 px admin toolbar at the top of the viewport when an administrator is logged in. Two things to handle:
1. Offset fixed navigation
Any position: fixed element with a top offset must account for the bar:
.site-header {
position: fixed;
top: var(--snk-adminbar-height, 0px);
}
For elements below the header, use calc():
.sidebar {
position: fixed;
top: calc(var(--snk-adminbar-height, 0px) + var(--header-h));
}
position: sticky elements do not need this — they follow the normal document flow.
2. Render the bar before your navigation
If your header uses backdrop-filter, it creates a CSS stacking context that can push the admin bar behind it regardless of z-index. Call render_adminbar() as the first child of <body>:
</head>
<body>
<?php render_adminbar(); ?>
<header class="site-header">
...
This is a no-op for non-admin visitors. Calling it explicitly is recommended for all themes as a best practice, even without backdrop-filter.
Search overlay variables
The search overlay (css/search.css) is fully themeable via CSS custom properties. All of the following are required in your theme's :root:
:root {
--search-overlay-bg: #1a1a18;
--search-card-bg: #2a2a25;
--search-card-bg-hover: #111009;
--search-accent: #3ea34e;
--search-accent-dark: #2d8a3d;
--search-accent-light: #52c463;
--search-text: rgba(255,255,255,.85);
--search-section-heading: rgba(255,255,255,.35);
--search-radius: 4px;
}
See Search Overlay Theming for the full reference, light/dark examples, and how to map these to your existing theme tokens.
Required CSS classes
The CMS core and default card renderers emit these classes. Your theme must style them (or accept the unstyled output):
| Class | Rendered by |
|---|---|
.articles-grid | render_home_articles() |
.article-card | render_article_card() |
.projects-grid | render_home_projects() |
.project-card | render_project_card() |
.related-items | render_related_items() |
.custom-fields-block | render_item_custom_fields() |
.featured-image | render_featured_image() |
.content-title | render_content_title() |
.content-date | render_content_date() |
.content-category | render_content_category() |
.content-tags | render_content_tags() |
Card classes (.article-card, .project-card) can be fully replaced by providing card partials.
Other classes that must be sylized in CSS, or at least not broken:
/* Search overlay (generated by `render_search_ui()`) */
.search-overlay { }
.search-input { }
.search-results { }
/* Shortcodes (in rich editor) */
.sc-callout { }
.sc-quote { }
.sc-btn { }
.sc-toc { }
.sc-grid { }
/* Galleries */
.gallery-grid { }
.gallery-masonry { }
.lightbox-trigger { }
/* Breadcrumbs */
.breadcrumbs { }
/* Contact form */
.contact-form { }
.contact-field { }
.contact-status { }
Shortcode CSS classes
Shortcode output uses sc- prefixed classes defined in shortcodes.css. Override them freely in your style.css:
| Shortcode | Wrapper class |
|---|---|
[callout] | .sc-callout, .sc-callout--info, .sc-callout--warning, etc. |
[quote] | .sc-quote |
[button] | .sc-button, .sc-button--primary, .sc-button--secondary, .sc-button--outline |
[columns] / [column] | .sc-columns, .sc-column |
theme/functions.php load order
Your theme's functions.php is loaded after all CMS core files but before any template variables exist. You can use it to:
- Register hooks and filters via
add_theme_action()/add_theme_filter() - Enqueue additional stylesheets with
add_theme_stylesheet() - Enqueue additional scripts with
add_theme_script() - Pre-fetch and cache data in
$GLOBALS
You cannot redefine CMS functions (PHP fatal) or access template variables like $item (not yet defined).
Use sl_load_index('article') for data access in functions.php, never $GLOBALS['data']['article'] — the data array is not yet populated at that point.
Additional stylesheets and scripts
style.css and script.js are injected automatically. For additional files:
// In theme/functions.php
add_theme_stylesheet('css/print.css'); // Injected in <head>
add_theme_script('js/animations.js'); // Injected before </body>
add_theme_script('js/polyfill.js', false); // Injected in <head>
Paths are relative to your theme directory (theme/{name}/).
