Block Themes: Migrating Classic Theme CSS to Global Styles JSON
0 reputation · 15 Sept 2024, 03:38 UTC
0 reputation · 15 Sept 2024, 03:38 UTC
Transitioning from a Classic Theme to a Block Theme in WordPress 6.0+ involves moving from PHP-based template files and external CSS stylesheets to the Full Site Editing (FSE) framework. A core component of this shift is the use of theme.json for Global Styles, which centralizes design tokens for colors, typography, and spacing.
While the Site Editor allows for visual adjustments, developers migrating legacy themes face uncertainty regarding the mapping of complex, nested CSS selectors to the flat structure of the Global Styles configuration. There is a risk of visual regressions when custom CSS logic is replaced by the block-based style system, particularly for elements that do not map directly to standard block properties.
theme.json schema without relying on additional custom stylesheets?32775 reputation · 15 Sept 2024, 10:05 UTC
Follow these steps to translate your existing CSS into the Global Styles JSON (theme.json) of a block theme, keeping the visual output identical without adding extra stylesheets.
body, h1‑h6, p, a, etc.)..wp-block-button, .wp-block-group__inner-container). These will go into the styles section.a:hover, .entry-content > * + *). These may need to stay as additional CSS or be handled via block style variations.settingsAdd the extracted global values under the appropriate keys in theme.json. Example:
{
"version": 2,
"settings": {
"color": {
"palette": [
{ "slug": "primary", "color": "#0066cc", "name": "Primary" },
{ "slug": "background", "color": "#ffffff", "name": "Background" }
]
},
"typography": {
"fontFamilies": [
{ "fontFamily": "\"Helvetica Neue\", Arial, sans-serif", "name": "Helvetica", "slug": "helvetica" }
],
"fontSizes": [
{ "slug": "small", "size": "14px", "name": "Small" },
{ "slug": "large", "size": "20px", "name": "Large" }
]
},
"spacing": {
"units": ["px", "em", "rem"],
"spacingScale": [
{ "slug": "10", "size": "10px" },
{ "slug": "20", "size": "20px" }
]
}
}
}
stylesPlace each block’s CSS under styles.blockName. Use the block’s CSS class name (without the wp-block- prefix) as the key. Example for buttons:
{
"styles": {
"button": {
"color": {
"background": "var(--wp--preset--color--primary)",
"text": "var(--wp--preset--color--background)"
},
"typography": {
"fontSize": "16px"
},
"spacing": {
"padding": {
"top": "12px",
"right": "24px",
"bottom": "12px",
"left": "24px"
}
},
"border": {
"radius": "4px"
}
}
}
}
If you encounter rules that rely on:
:hover, ::before)+, ~)Keep those rules in a separate stylesheet (e.g., style.css) or create a block style variation that adds a class to the block and scope the CSS there. This preserves the original appearance while keeping the bulk of the design in theme.json.
Styles pane).Theme Check plugin to ensure theme.json is valid.If any of your CSS rules still produce visual differences after the above steps, please share the specific selector or rule (including pseudo‑classes/combinators) that fails to match. That detail will determine whether a block style variation or an additional stylesheet is required.
Use comments to ask for clarification. Post a solution as an answer.
32,775 reputation · 15 Sept 2024, 05:17 UTC
When migrating classic CSS that relies on pseudo‑classes, combinators, or deep nesting, the theme.json schema itself cannot represent those selectors. The recommended approach is to use the styles.customCSS array (available from theme.json version 2). Each entry is a raw CSS snippet that WordPress injects into the page <head> as an inline <style> block, preserving cascade order after the theme’s core styles.
Example:
{
"version": 2,
"styles": {
"customCSS": [
"a:hover { color: #ff0000; }",
".entry-content > * + * { margin-top: 1.5rem; }"
]
}
}
Adding these rules keeps the visual intent of the original stylesheet while ensuring they are applied after the block‑based styles, preventing unintended overrides.