Introduction
Bulma generates CSS custom properties (also called CSS variables) for all major design tokens. Unlike Sass variables which are set at compile time, CSS variables can be modified at runtime, making them perfect for dynamic theming and component customization.
Variable Naming Convention
All Bulma CSS variables follow a consistent naming pattern:
--bulma-{ property }
--bulma-{ property }-{ variant }
--bulma-{ color }-{ channel }
Examples:
--bulma-primary - Primary color
--bulma-primary-h - Primary hue
--bulma-primary-l - Primary lightness
--bulma-primary-invert - Inverted primary color
--bulma-radius - Border radius
--bulma-text-strong - Strong text color
Color System
Bulma uses the HSL color space, splitting each color into three channels for maximum flexibility:
HSL Channels
:root {
/* Primary color channels */
--bulma-primary-h : 171 ; /* Hue (0-360) */
--bulma-primary-s : 100 % ; /* Saturation (0-100%) */
--bulma-primary-l : 41 % ; /* Lightness (0-100%) */
/* Computed color */
--bulma-primary : hsla (
var ( --bulma-primary-h ),
var ( --bulma-primary-s ),
var ( --bulma-primary-l ),
1
);
}
Using HSL channels allows you to modify individual aspects of a color, like making it lighter or darker without changing hue.
Color Palette Variables
Each semantic color has a complete set of variables:
/* Primary Color */
--bulma-primary /* Base color */
--bulma-primary-h /* Hue */
--bulma-primary-s /* Saturation */
--bulma-primary-l /* Lightness */
--bulma-primary-invert /* Contrasting color */
--bulma-primary-light /* Light variant (90% lightness) */
--bulma-primary-dark /* Dark variant (10% lightness) */
--bulma-primary-soft /* Soft background variant */
--bulma-primary-bold /* Bold foreground variant */
/* 20 shades: 00, 05, 10, 15, ..., 95, 100 */
--bulma-primary-00 /* Nearly black */
--bulma-primary-05
--bulma-primary-10
/* ... */
--bulma-primary-95
--bulma-primary-100 /* Nearly white */
This applies to all semantic colors:
--bulma-primary-*
--bulma-info-*
--bulma-success-*
--bulma-warning-*
--bulma-danger-*
--bulma-link-*
--bulma-dark-*
--bulma-light-*
Scheme Variables
Scheme variables control the overall color scheme:
:root {
/* Base scheme */
--bulma-scheme-h : 221 ;
--bulma-scheme-s : 14 % ;
/* Main backgrounds */
--bulma-scheme-main-l : 100 % ; /* Lightest */
--bulma-scheme-main-bis-l : 98 % ; /* Slightly darker */
--bulma-scheme-main-ter-l : 96 % ; /* Even darker */
--bulma-scheme-main : hsl (
var ( --bulma-scheme-h ),
var ( --bulma-scheme-s ),
var ( --bulma-scheme-main-l )
);
/* Inverted colors (for dark text on light bg) */
--bulma-scheme-invert-l : 4 % ;
--bulma-scheme-invert-bis-l : 9 % ;
--bulma-scheme-invert-ter-l : 14 % ;
}
Text Variables
:root {
/* Text colors */
--bulma-text-h : 221 ;
--bulma-text-s : 14 % ;
--bulma-text-l : 29 % ; /* Base text */
--bulma-text-weak-l : 48 % ; /* Secondary text */
--bulma-text-strong-l : 21 % ; /* Emphasized text */
--bulma-text-title-l : 14 % ; /* Title text */
/* Computed text colors */
--bulma-text : hsl (
var ( --bulma-text-h ),
var ( --bulma-text-s ),
var ( --bulma-text-l )
);
--bulma-text-weak : hsl (
var ( --bulma-text-h ),
var ( --bulma-text-s ),
var ( --bulma-text-weak-l )
);
--bulma-text-strong : hsl (
var ( --bulma-text-h ),
var ( --bulma-text-s ),
var ( --bulma-text-strong-l )
);
}
UI Variables
Background
:root {
--bulma-background-l : 96 % ;
--bulma-background : hsl (
var ( --bulma-scheme-h ),
var ( --bulma-scheme-s ),
var ( --bulma-background-l )
);
}
Borders
:root {
--bulma-border-l : 86 % ;
--bulma-border-weak-l : 93 % ;
--bulma-border : hsl (
var ( --bulma-scheme-h ),
var ( --bulma-scheme-s ),
var ( --bulma-border-l )
);
--bulma-border-weak : hsl (
var ( --bulma-scheme-h ),
var ( --bulma-scheme-s ),
var ( --bulma-border-weak-l )
);
}
Typography Variables
:root {
/* Font families */
--bulma-family-primary : "Inter" , "SF Pro" , "Segoe UI" , sans-serif ;
--bulma-family-secondary : "Inter" , "SF Pro" , "Segoe UI" , sans-serif ;
--bulma-family-code : "Inconsolata" , "Hack" , monospace ;
/* Font sizes */
--bulma-size-1 : 3 rem ; /* 48px */
--bulma-size-2 : 2.5 rem ; /* 40px */
--bulma-size-3 : 2 rem ; /* 32px */
--bulma-size-4 : 1.5 rem ; /* 24px */
--bulma-size-5 : 1.25 rem ; /* 20px */
--bulma-size-6 : 1 rem ; /* 16px */
--bulma-size-7 : 0.75 rem ; /* 12px */
--bulma-size-small : var ( --bulma-size-7 );
--bulma-size-normal : var ( --bulma-size-6 );
--bulma-size-medium : var ( --bulma-size-5 );
--bulma-size-large : var ( --bulma-size-4 );
/* Font weights */
--bulma-weight-light : 300 ;
--bulma-weight-normal : 400 ;
--bulma-weight-medium : 500 ;
--bulma-weight-semibold : 600 ;
--bulma-weight-bold : 700 ;
--bulma-weight-extrabold : 800 ;
}
Spacing Variables
:root {
--bulma-block-spacing : 1.5 rem ;
}
Border Radius Variables
:root {
--bulma-radius-small : 0.25 rem ;
--bulma-radius : 0.375 rem ;
--bulma-radius-medium : 0.5 em ;
--bulma-radius-large : 0.75 rem ;
--bulma-radius-rounded : 9999 px ;
}
Animation Variables
:root {
--bulma-speed : 86 ms ;
--bulma-duration : 294 ms ;
--bulma-easing : ease-out ;
}
Interaction Deltas
Bulma uses “delta” variables for hover and active states:
:root {
/* Light theme - darken on interaction */
--bulma-hover-background-l-delta : -5 % ;
--bulma-active-background-l-delta : -10 % ;
--bulma-hover-border-l-delta : -10 % ;
--bulma-active-border-l-delta : -20 % ;
--bulma-hover-color-l-delta : -5 % ;
--bulma-active-color-l-delta : -10 % ;
}
[ data-theme = "dark" ] {
/* Dark theme - lighten on interaction */
--bulma-hover-background-l-delta : 5 % ;
--bulma-active-background-l-delta : 10 % ;
--bulma-hover-border-l-delta : 10 % ;
--bulma-active-border-l-delta : 20 % ;
}
Customization Examples
Change Primary Color
:root {
--bulma-primary-h : 271 ; /* Purple hue */
--bulma-primary-s : 100 % ;
--bulma-primary-l : 71 % ;
}
Adjust Border Radius Globally
:root {
--bulma-radius : 0 ; /* No rounded corners */
--bulma-radius-small : 0 ;
--bulma-radius-medium : 0 ;
--bulma-radius-large : 0 ;
}
Make Text Lighter
:root {
--bulma-text-l : 40 % ; /* Lighter than default 29% */
--bulma-text-strong-l : 30 % ; /* Lighter strong text */
}
Increase Font Sizes
:root {
--bulma-size-1 : 3.5 rem ;
--bulma-size-2 : 3 rem ;
--bulma-size-3 : 2.5 rem ;
--bulma-size-4 : 2 rem ;
--bulma-size-5 : 1.5 rem ;
--bulma-size-6 : 1.125 rem ; /* 18px base instead of 16px */
--bulma-size-7 : 0.875 rem ;
}
Component-Specific Customization
Scope variables to specific components:
/* Override button colors */
.button.is-primary {
--bulma-primary-h : 200 ;
--bulma-primary-s : 80 % ;
--bulma-primary-l : 50 % ;
}
/* Custom card styling */
.card {
--bulma-radius : 1 rem ;
--bulma-border-l : 90 % ;
}
/* Custom navbar */
.navbar {
--bulma-scheme-main-l : 95 % ;
--bulma-text-l : 20 % ;
}
Runtime Theming with JavaScript
Change variables dynamically with JavaScript:
Change Single Variable
document . documentElement . style . setProperty (
'--bulma-primary-h' ,
'271'
);
Change Multiple Variables
function setThemeColor ( hue , saturation , lightness ) {
const root = document . documentElement ;
root . style . setProperty ( '--bulma-primary-h' , hue );
root . style . setProperty ( '--bulma-primary-s' , ` ${ saturation } %` );
root . style . setProperty ( '--bulma-primary-l' , ` ${ lightness } %` );
}
// Usage
setThemeColor ( 271 , 100 , 71 ); // Purple
Theme Color Picker
< div class = "field" >
< label class = "label" > Primary Color </ label >
< div class = "control" >
< input type = "color" id = "color-picker" class = "input" value = "#00d1b2" >
</ div >
</ div >
< script >
const picker = document . getElementById ( 'color-picker' );
picker . addEventListener ( 'input' , ( e ) => {
const color = e . target . value ;
// Convert hex to HSL
const rgb = hexToRgb ( color );
const hsl = rgbToHsl ( rgb . r , rgb . g , rgb . b );
// Update CSS variables
document . documentElement . style . setProperty ( '--bulma-primary-h' , hsl . h );
document . documentElement . style . setProperty ( '--bulma-primary-s' , ` ${ hsl . s } %` );
document . documentElement . style . setProperty ( '--bulma-primary-l' , ` ${ hsl . l } %` );
});
function hexToRgb ( hex ) {
const result = / ^ # ? ( [ a-f\d ] {2} )( [ a-f\d ] {2} )( [ a-f\d ] {2} ) $ / i . exec ( hex );
return result ? {
r: parseInt ( result [ 1 ], 16 ),
g: parseInt ( result [ 2 ], 16 ),
b: parseInt ( result [ 3 ], 16 )
} : null ;
}
function rgbToHsl ( r , g , b ) {
r /= 255 ;
g /= 255 ;
b /= 255 ;
const max = Math . max ( r , g , b );
const min = Math . min ( r , g , b );
let h , s , l = ( max + min ) / 2 ;
if ( max === min ) {
h = s = 0 ;
} else {
const d = max - min ;
s = l > 0.5 ? d / ( 2 - max - min ) : d / ( max + min );
switch ( max ) {
case r : h = (( g - b ) / d + ( g < b ? 6 : 0 )) / 6 ; break ;
case g : h = (( b - r ) / d + 2 ) / 6 ; break ;
case b : h = (( r - g ) / d + 4 ) / 6 ; break ;
}
}
return {
h: Math . round ( h * 360 ),
s: Math . round ( s * 100 ),
l: Math . round ( l * 100 )
};
}
</ script >
Dynamic Font Size Adjustment
< input
type = "range"
id = "font-scale"
min = "0.8"
max = "1.2"
step = "0.05"
value = "1"
>
< script >
const fontScale = document . getElementById ( 'font-scale' );
fontScale . addEventListener ( 'input' , ( e ) => {
const scale = parseFloat ( e . target . value );
const root = document . documentElement ;
root . style . setProperty ( '--bulma-size-1' , ` ${ 3 * scale } rem` );
root . style . setProperty ( '--bulma-size-2' , ` ${ 2.5 * scale } rem` );
root . style . setProperty ( '--bulma-size-3' , ` ${ 2 * scale } rem` );
root . style . setProperty ( '--bulma-size-4' , ` ${ 1.5 * scale } rem` );
root . style . setProperty ( '--bulma-size-5' , ` ${ 1.25 * scale } rem` );
root . style . setProperty ( '--bulma-size-6' , ` ${ 1 * scale } rem` );
root . style . setProperty ( '--bulma-size-7' , ` ${ 0.75 * scale } rem` );
});
</ script >
Comparison: Sass Variables vs CSS Variables
// Sass variable - compile time
$primary : hsl ( 171 , 100 % , 41 % ) ;
.button {
background-color : $primary ; // → background-color: hsl(171, 100%, 41%);
}
/* CSS variable - runtime */
:root {
--bulma-primary : hsl ( 171 , 100 % , 41 % );
}
.button {
background-color : var ( --bulma-primary ); /* Can be changed dynamically */
}
Bulma uses Sass variables to generate CSS variables, giving you the best of both worlds.
Browser Support
CSS custom properties are supported in all modern browsers:
Chrome 49+
Firefox 31+
Safari 9.1+
Edge 15+
CSS variables are not supported in Internet Explorer 11. Consider using a PostCSS plugin like postcss-custom-properties for fallback support.
Next Steps
Theme System Learn how to implement light/dark themes using CSS variables
Sass Variables Understand the relationship between Sass and CSS variables