Table of contents:
WP Rig CSS philosophy
WP Rig promotes modern CSS best-practices by enabling developers to write and use modern CSS today and take advantage of upcoming CSS features even when these are not yet available in browsers. WP Rig uses pure CSS markup without pre-processors. The CSS provided by WP Rig follows these principles:
Layouts
WP Rig uses the modern layout modules CSS grid and Flex to support a minimalist HTML structure. The mobile-first layout serves as the baseline across all screen widths, and two-dimensional layouts are served as a progressive enhancement. As a result, browsers without grid/flex support are served with the mobile layout.
The layouts in WP Rig follow these design principles:
- Mobile layout for all screen sizes as baseline and fallback for older browsers.
- Two-dimensional layouts using CSS grid.
- One dimensional block/list-based displays using flex.
- In-content wrapping using float and clear.
File structure and CSS modules
The file structure of CSS in WP Rig is modular with a strong focus on performance. This modular nature of the CSS files makes working with CSS easier, and improves performance thanks to progressive loading. Here’s how CSS works out of the box:
- In WP Rig,
style.css found in the root folder serves only as a container for the required theme configuration data. - All editable CSS is found under
assets/css/src/. The contents of this folder are linted to WordPress Coding Standards using stylelint, minified, and output to assets/css/ by the build process. global.css serves as the main stylesheet. This file is loaded in the <head> section of every template.- All other files without an
_ prefix are loaded conditionally by their respective components (see below). - Files prefixed by a
_ (eg _blocks.css) are partials, compiled into their parent files using @import rules. Lightning CSS imports the contents of these partials during processing to become part of the parent file. - Editor styles are found in
assets/css/src/editor/editor-styles.css.
This modular file structure has several benefits including
- discoverability (rules are grouped based on their function and/or module and easy to find)
- performance (files are only loaded when used)
- caching and bandwidth (individual files can be updated without the entire set of styles being updated) CSS can be modified, deleted, and/or added to all existing files in
assets/css/src/. When files are removed or new files are added to this folder, they need to be registered with the theme for use and called from the appropriate component. See Progressive Loading of CSS for further details.
Modern CSS via Lightning CSS
All CSS is processed through Lightning CSS and leveraging modern and future CSS markup like custom properties (variables), custom-media (breakpoints stored as variables. We also included other custom parsing QOL features like dynamically referring to image paths for images bundled with the theme.
Custom Properties
Modern browsers support Custom Properties, aka CSS variables. Custom properties allow developers to declare a value once and reference this declaration throughout the stylesheet just like a regular variable in another coding language. Custom properties are scoped to the elements they are declared on, and follow the cascade, meaning a custom property can be declared, and then changed for a specific scope in a stylesheet.
A prototypical example of custom properties looks like this:
:root {
--first-color: #488cff;
--second-color: #ffff8c;
}
#firstParagraph {
background-color: var(--first-color);
color: var(--second-color);
}WP Rig uses custom properties for a long list of values including font families and sizes, and colors. The custom properties are declarations in a CSS partial at ./assets/css/src/_custom-properties.css. This file is included at the top of global.css.
All custom properties in WP Rig are declared using the :root selector, a pseudo-class applying to “the root element of a tree representing the document”. This means the custom properties apply to the entire document. The reason for this is backwards compatibility: While modern browsers support custom properties, older browsers do not. The resulting CSS looks like this:
body,
button,
input,
select,
optgroup,
textarea {
color: #333;
color: var(--global-font-color);
font-family: "Crimson Text", serif;;
font-family: var(--global-font-family);
font-size: calc(20 / 16 * 1rem);
font-size: var(--font-size-regular);
line-height: 1.4;
line-height: var(--global-font-line-height);
}This approach is deliberately conservative to provide a backwards-compatible starting point. Custom properties are quickly becoming a standard feature on the web, and developers are encouraged to use them with scoping when appropriate.
Custom Media
CSS custom properties can not be used in media queries. For variables in media queries, the Media Queries Level 5 specification introduces the @custom-media rule. This is bleeding-edge technology currently not supported by any browsers.
Lightning CSS plus some custom node scripts add support for this upcoming feature, and WP Rig uses @custom-media with full backwards compatibility.
The custom media declarations are in a CSS partial at ./assets/css/src/_custom-media.css. Unlike custom properties, custom media references used in media queries in all CSS files are transformed into traditional media queries. This is done to prevent rule duplication. For developers this means you can safely use custom media in your themes and have WP Rig output functional CSS today as long as you declare the @custom-media rules in ./assets/css/src/_custom-media.css.
When custom media gains proper support in modern browsers, WP Rig will be updated to incorporate this feature without transformations.
Nesting
One popular feature of preprocessors like Sass and LESS is nesting, the ability to nest CSS rules inside one another for simpler cascade inheritance and less specificity. Thanks to the popularity of this feature, CSS Nesting is now a level 1 module in the CSS spec meaning it will be implemented by modern browsers at some point in the not-too-distant future.
The CSS nesting specification has detailed information about how the feature works. The prototypical example is as follows:
a, b {
color: red;
& c, & d {
color: white;
}
}
/* becomes */
a, b {
color: red;
}
a c, a d, b c, b d {
color: white;
}Why no Sass support?
WP Rig does not provide a build process for preprocessing SCSS (Sass) files and partials. This is a deliberate decision in line with the overall philosophy of WP Rig: promote the latest best practices for progressive web content and optimization.
Sass is to CSS what jQuery is to JavaScript: A tool to prototype simpler/better/different development techniques for relatively rigid languages. And just like modern JavaScript and ESNext has adopted and built on many features from jQuery rendering jQuery less relevant, so has modern CSS done the same with Sass. The WP Rig team decided to drop support for Sass because all major features of Sass are now available in modern CSS:
Partials, imports, custom properties (variables), custom media, and nesting are available to use in WP Rig. Advanced math is already part of the CSS spec thanks to calc and other operators.
At present, the only major Sass features not covered in WP Rig are mixins and extend/inherit, this is because they are presently not part of current or future CSS specifications. If you need features similar to this, please explore the documentation for Lightning CSS, as they do have some comparable concepts like CSS modules and others.
Progressive loading of CSS
WP Rig employs progressive loading of CSS through in-body tags. Module-specific styles are held in module-specific stylesheets and loaded at module level. This is fundamentally different from how traditional WordPress themes handle CSS, and it has several advantages:
- The main stylesheet file size is reduced.
- Styles are only loaded if and when a module is present in the view.
- Stylesheets are associated with their modules making them easier to work with.
- Leverages HTTP/2 multiplexing and can be extended to include preloading, server push etc.
- Module-level stylesheets are cached and can be individually updated without forcing reload of all styles on the site.
As explained in File structure and CSS modules above, only one stylesheet, global.css is always loaded by every template. All other stylesheets are loaded by their respective modules. This is done using the wp_rig()->print_styles() which takes a stylesheet handle as its parameter. As an example, content.css is loaded by index.php at line 19:
wp_rig()->print_styles( 'wp-rig-content' );
Each individual stylesheet is registered in the get_css_files() function found in ./inc/Styles/Component.php under the $css_files array:
$css_files = array(
'wp-rig-global' => array(
'file' => 'global.min.css',
'global' => true,
),
'wp-rig-comments' => array(
'file' => 'comments.min.css',
'preload_callback' => function() {
return ! post_password_required() && is_singular() && ( comments_open() || get_comments_number() );
},
),
'wp-rig-content' => array(
'file' => 'content.min.css',
'preload_callback' => '__return_true',
),
'wp-rig-sidebar' => array(
'file' => 'sidebar.min.css',
'preload_callback' => function() {
return wp_rig()->is_primary_sidebar_active();
},
),
'wp-rig-widgets' => array(
'file' => 'widgets.min.css',
'preload_callback' => function() {
return wp_rig()->is_primary_sidebar_active();
},
),
'wp-rig-front-page' => array(
'file' => 'front-page.min.css',
'preload_callback' => function() {
global $template; return 'front-page.php' === basename( $template );
},
),
);Each entry in the $css_files array must follow the same convention:
‘wp-rig-[label]’ => array(
‘file’ => ‘[filename].min.css’, // required
‘preload_callback’ => ‘[callback function or __return_true], // optional if file should be preloaded
‘global’ => true, // optional if file should be loaded in every template
)
The preload_callback value controls whether the stylesheet is preloaded in the <head> section of the document. This improves performance in some circumstances, but counteracts the performance benefits of using in-body tags because stylesheets are loaded before they are used. For stylesheets that should not be preloaded, use:
`'preload_callback' => '__return_false'`
Tip: When preloading a stylesheet, use the console in Chrome developer tools to ensure no unnecessary stylesheets are loaded. A warning will appear letting you know if a stylesheet is preloaded but not used. Note: This approach has raised some questions and concerns around the use of wp_print_styles and how to handle custom CSS from the Customizer. For those interested in further reading, these issues, along with some extended research, was addressed by @kevinhoffman in a comment to issue #277.
Code linting
WP Rig provides CSS code linting to WordPress Coding Standards via stylelint. Out of the box, this linting takes place during the build process and errors are referenced in the command line terminal. VS Code users can take full advantage of WP Rig’s stylelint configuration and get real-time coding assistance and format-on-save capability by enabling the stylelint and Prettier extensions and adding the following to Workspace Settings:
{
"prettier.stylelintIntegration": true,
"editor.formatOnSave": true
}This assumes VS Code was opened into the wp-content/themes/wprig folder as the workspace.