CSS variables

Overview

Custom properties (sometimes referred to as CSS variables or cascading variables) are entities defined by CSS authors that contain specific values to be reused throughout a document. They are set using custom property notation (e.g., --main-color: black;) and are accessed using the var() function (e.g., color: var(--main-color);).

Limitless version 4.0 has been completely re-written to support CSS variables in all layouts, components and extensions. It also includes a logic of re-using global CSS variables in any 3rd party components that you might need to add in the future. CSS variables are used for the following properties in CSS:

  • background and text colors
  • margin
  • padding
  • size
  • font size
  • font family
  • line height
  • border radius
  • box shadow

CSS variables simplify template customization that can be done at runtime and don't require SCSS build process. Deep customization still requires SCSS editing and values for CSS variables are coming from SCSS variables as they work in combination. Some examples of global CSS variables:

										
											// Typography
											--body-font-size-lg: 1rem;
											--body-font-size-sm: 0.75rem;
											--body-font-size-xs: 0.625rem;
											--body-line-height-computed: calc(1375rem / 1000);
											--body-line-height-lg: 1.375;
											--body-line-height-sm: 1.8334;
											--body-line-height-xs: 2.2;

											// Spacing
											--spacer-1: 0.3125rem;
											--spacer-2: 0.625rem;
											--spacer: 1.25rem;
											--spacer-4: 1.875rem;
											--spacer-5: 3.75rem;

											// Border radius
											--border-radius: 0.375rem;
											--border-radius-sm: 0.25rem;
											--border-radius-lg: 0.5rem;

											// Box shadow
											--box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.125);
											--box-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
											--box-shadow-lg: 0 6px 12px rgba(0, 0, 0, 0.15);

											// Sizing
											--icon-font-size: 1.25rem;
											--icon-font-size-lg: 1.5rem;
											--icon-font-size-sm: 1rem;

											// Colors
											--gray-100: #F9FAFB;
											--gray-200: #F3F4F6;
											--gray-300: #E5E7EB;
											--gray-400: #D1D5DB;
											--gray-500: #9CA3AF;
											--gray-600: #6B7280;
											--gray-700: #4B5563;
											--gray-800: #374151;
											--gray-900: #1F2937;
										
									

The logic

There are multiple approaches to implementing CSS variables, the most popular and the most meaningful is a combination of SCSS and CSS, where CSS var values are dynamically generated from SCSS variables. This method allows to use a full power of SASS (such as mixins, conditions, color functions etc etc) while using CSS vars as properties. For example:

										
											// Define color using SASS color function
											$yellow-100: tint-color($yellow, 90%);

											// Use CSS variable in component
											.element-container {

												// Define CSS variable on component level	
												--#{$prefix}element-color: #{$yellow-100};

												// Use CSS variable in component
												.element {
													color: var(--#{$prefix}element-color);	
												}
											}
										
									

Bootstrap logic of CSS variables is somewhat strange - it includes a bunch of CSS variables on :root level and on component level, making it a bit hard to follow and customize. This means if I want to apply styles from default form select component to any select in any 3rd party component, I need to create the same set of CSS variables specifically this component, which increases bundle size. This concern was raised multiple times to Bootstrap dev team, but no changes planned in upcoming releases.

Another concern is about the level of customization. Originally the idea of introducing CSS vars was to allow users to change only colors/shapes/shadows/typography, but adding also spacing/sizing to the list leads to full layout shift, making SASS with its power almost useless. That is why Limitless core includes CSS variables only when it's necessary and all of them are linked to global vars on :root level.

To follow the same approach Limitless also uses component-based configuration of CSS variables, but still has an option to jump from component styling to global styling with low-to-medium efforts.

How to use

In development environment, all CSS variables are stored in SCSS files: _root.scss file contains all global variables added to the root level, all Bootstrap-related and 3rd party components are stored in corresponding files. If you need to make a deep customization, you need to edit _variables-core.scss and _variables-custom.scss files. All values assigned to CSS variables are coming from there. For example:

											
												// SCSS variables in _variables-core.scss
												$input-color:         var(--#{$prefix}body-color);
												$input-border-color:  var(--#{$prefix}gray-400);

												// How it's used in _form-control.scss file
												.form-control {
													--#{$prefix}input-color: #{$input-color};
													--#{$prefix}input-border-color: #{$input-border-color};

													color: var(--#{$prefix}input-color);
													border-color: var(--#{$prefix}input-border-color);
												}
											
										
Same logic is applicable to all components. It is recommended to make as less changes in component SCSS files as possible, instead if you need to change values, do it in 2 files with variables mentioned above.
Global CSS variables
If you need to style third-party components, you can re-use global CSS variables available in :root level. Here is a full list of available CSS variables:
											
												:root,
												[data-color-theme=light] {
													--body-font-size-lg: 1rem;
													--body-font-size-sm: 0.75rem;
													--body-font-size-xs: 0.625rem;
													--body-line-height-computed: calc(1375rem / 1000);
													--body-line-height-lg: 1.375;
													--body-line-height-sm: 1.8334;
													--body-line-height-xs: 2.2;
													--component-active-bg: #0c83ff;
													--component-active-bg-rgb: 12, 131, 255;
													--component-active-color: #fff;
													--focus-ring-box-shadow: 0 0 0 0.125rem rgba(12, 131, 255, 0.25);
													--spacer-1: 0.3125rem;
													--spacer-2: 0.625rem;
													--spacer: 1.25rem;
													--spacer-4: 1.875rem;
													--spacer-5: 3.75rem;
													--icon-font-family: Phosphor;
													--icon-font-size: 1.25rem;
													--icon-font-size-lg: 1.5rem;
													--icon-font-size-sm: 1rem;
													--box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.125);
													--box-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1);
													--box-shadow-lg: 0 6px 12px rgba(0, 0, 0, 0.15);
													--transition-base-timer: 0.15s;
													--transition-collapse-timer: 0.3s;
													--gray-100: #F9FAFB;
													--gray-200: #F3F4F6;
													--gray-300: #E5E7EB;
													--gray-400: #D1D5DB;
													--gray-500: #9CA3AF;
													--gray-600: #6B7280;
													--gray-700: #4B5563;
													--gray-800: #374151;
													--gray-900: #1F2937;
													--indigo: #5C6BC0;
													--purple: #8e70c1;
													--pink: #f35c86;
													--teal: #26A69A;
													--yellow: #ffd648;
													--primary: #0c83ff;
													--secondary: #247297;
													--success: #059669;
													--info: #049aad;
													--warning: #f58646;
													--danger: #EF4444;
													--light: #F3F4F6;
													--dark: #252b36;
													--black: #000;
													--white: #fff;
													--indigo-rgb: 92, 107, 192;
													--purple-rgb: 142, 112, 193;
													--pink-rgb: 243, 92, 134;
													--teal-rgb: 38, 166, 154;
													--yellow-rgb: 255, 214, 72;
													--primary-rgb: 12, 131, 255;
													--secondary-rgb: 36, 114, 151;
													--success-rgb: 5, 150, 105;
													--info-rgb: 4, 154, 173;
													--warning-rgb: 245, 134, 70;
													--danger-rgb: 239, 68, 68;
													--light-rgb: 243, 244, 246;
													--dark-rgb: 37, 43, 54;
													--black-rgb: 0, 0, 0;
													--white-rgb: 255, 255, 255;
													--body-color-rgb: 31, 41, 55;
													--body-bg-rgb: 241, 244, 249;
													--font-sans-serif: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
													--font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
													--gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
													--body-font-family: var(--font-sans-serif);
													--body-font-size: 0.875rem;
													--body-font-weight: 400;
													--body-line-height: 1.5715;
													--body-color: #1F2937;
													--body-bg: #f1f4f9;
													--border-width: 1px;
													--border-style: solid;
													--border-color: #D1D5DB;
													--border-color-translucent: rgba(0, 0, 0, 0.125);
													--border-radius: 0.375rem;
													--border-radius-sm: 0.25rem;
													--border-radius-lg: 0.5rem;
													--border-radius-xl: 1rem;
													--border-radius-2xl: 2rem;
													--border-radius-pill: 50rem;
													--link-color: #0c83ff;
													--link-hover-color: #0962bf;
													--code-color: #f35c86;
													--highlight-bg: rgba(0, 0, 0, 0.15);
												}
											
										
Variable prefix

In SCSS code all CSS variables have prefix addon, which looks like this - --#{$prefix}input-color. This option is coming from Bootstrap core, where default value is bs-. In Limitless this prefix is set to null to keep the code more readable. If you would like to set your custom prefix, you need to edit $prefix variable located in _variables-core.scss file.

											
												// Variable in _variables-core.scss
												$prefix: null;
											
										
Note: it's highly recommended to use #{$prefix} in all your CSS variables.
Editing

Using CSS variables as primary method in template styling allows to easily customize typography, colors, spacing and other properties on-the-fly simply by editing or overriding CSS variables that can be done in a separate .css. You can edit CSS variables using 2 different options:

  1. Overriding CSS variables This method doesn't require build process and works best if you are not planning to change too much in CSS and use all styles as is with some minor corrections.
  2. Editing SCSS sources This method works best when you need to make lots of changes. It requires SCSS compilation.
											
												// Variables in all.css file
												--body-bg: #f1f4f9;
												--body-bg-rgb: 241, 244, 249;

												// Create a new CSS file, copy/paste variables that you want to edit
												// and change values
												--body-bg: #fff;
												--body-bg-rgb: 255, 255, 255;
											
										
Note: it's highly recommended to use #{$prefix} in all your CSS variables.