Scales
Overview
The scale composables help you create harmonious, proportional design systems using modular scales. They generate scale variables based on mathematical ratios and powers, enabling consistent sizing relationships across typography, spacing, and other design elements.
Why use scale composables?
Scale composables help you:
- Create harmonious proportions: Use time-tested ratios from music theory and mathematics for visually pleasing designs.
- Maintain consistency: Apply the same scale ratio across all sizing decisions for a cohesive design system.
- Scale systematically: Generate size variations using powers of your base scale for predictable growth.
- Simplify sizing decisions: Replace arbitrary values with a systematic approach to sizing.
useScale
The useScale()
function creates a set of predefined scale ratio variables based on musical intervals and the golden ratio. It also creates a default scale
variable that references one of the predefined scales.
import { styleframe } from 'styleframe';
import { useScale } from '@styleframe/theme';
const s = styleframe();
const {
scaleMinorSecond, // 1.067
scaleMajorSecond, // 1.125
scaleMinorThird, // 1.2
scaleMajorThird, // 1.25
scalePerfectFourth, // 1.333
scaleAugmentedFourth, // 1.414
scalePerfectFifth, // 1.5
scaleGolden, // 1.618
scale, // References minor-third by default
} = useScale(s);
export default s;
:root {
--scale--minor-second: 1.067;
--scale--major-second: 1.125;
--scale--minor-third: 1.2;
--scale--major-third: 1.25;
--scale--perfect-fourth: 1.333;
--scale--augmented-fourth: 1.414;
--scale--perfect-fifth: 1.5;
--scale--golden: 1.618;
--scale: var(--scale--minor-third);
}
Each scale ratio is named after its musical interval or mathematical origin. These ratios have been used in design and architecture for centuries to create harmonious proportions.
The scale
variable is a convenient reference to your chosen default scale. By default, it references --scale--minor-third
, but you can customize this by passing a second argument to useScale()
.
Customizing the Default Scale
You can specify which scale should be the default by passing a second argument:
import { styleframe } from 'styleframe';
import { useScale } from '@styleframe/theme';
const s = styleframe();
// Set Perfect Fourth as the default scale
const { scale } = useScale(s, 'perfect-fourth');
export default s;
:root {
--scale--minor-second: 1.067;
--scale--major-second: 1.125;
--scale--minor-third: 1.2;
--scale--major-third: 1.25;
--scale--perfect-fourth: 1.333;
--scale--augmented-fourth: 1.414;
--scale--perfect-fifth: 1.5;
--scale--golden: 1.618;
--scale: var(--scale--perfect-fourth);
}
Valid default scale values are: "minor-second"
, "major-second"
, "minor-third"
, "major-third"
, "perfect-fourth"
, "augmented-fourth"
, "perfect-fifth"
, and "golden"
.
scale
variable makes it easy to change your entire design system's scale in one place. You can also override it at different breakpoints or for specific components.useScalePowers
The useScalePowers()
function generates size multipliers by raising a scale to different powers, creating a systematic sizing system.
import { styleframe } from 'styleframe';
import { useScale } from '@styleframe/theme';
const s = styleframe();
const { scalePerfectFourth } = useScale(s);
// Create a sizing system from -3 to 6
const sizes = useScalePowers(s, scalePerfectFourth, [-3, -2, -1, 0, 1, 2, 3, 4, 5, 6]);
export default s;
:root {
--scale--perfect-fourth: 1.333;
}
/* Generated calculations:
Power -3: 1 / 1.333 / 1.333 / 1.333 ≈ 0.422
Power -2: 1 / 1.333 / 1.333 ≈ 0.563
Power -1: 1 / 1.333 ≈ 0.750
Power 0: 1 (base size)
Power 1: 1.333
Power 2: 1.333 * 1.333 ≈ 1.777
Power 3: 1.333 * 1.333 * 1.333 ≈ 2.369
Power 4: 1.333 * 1.333 * 1.333 * 1.333 ≈ 3.157
Power 5: 1.333 * 1.333 * 1.333 * 1.333 * 1.333 ≈ 4.209
Power 6: 1.333 * 1.333 * 1.333 * 1.333 * 1.333 * 1.333 ≈ 5.610
*/
useScalePowers()
generates the multipliers, you'll typically want to use them with useMultiplier()
to create properly named variables for your design system.Positive powers multiply the scale (making things larger), while negative powers divide it (making things smaller). This creates a harmonious progression of sizes both above and below your base size.
useMultiplier
The useMultiplier()
function creates a set of variables by multiplying a base variable by different multipliers. This is perfect for combining with useScalePowers()
to create complete size scales.
import { styleframe } from 'styleframe';
import { useScale, useScalePowers, useMultiplier, useFontSize, defaultScalePowerValues } from '@styleframe/theme';
const s = styleframe();
const { scale } = useScale(s);
const { fontSize } = useFontSize(s, { default: '1rem' });
// Generate scale powers
const scalePowers = useScalePowers(s, scale);
// Create font size variables using the base fontSize and scale powers
const {
fontSizeXs, // Variable<'font-size--xs'>
fontSizeSm, // Variable<'font-size--sm'>
fontSizeMd, // Variable<'font-size--md'>
fontSizeLg, // Variable<'font-size--lg'>
fontSizeXl, // Variable<'font-size--xl'>
fontSize2xl, // Variable<'font-size--2xl'>
} = useMultiplier(s, fontSize, {
xs: scalePowers[-2],
sm: scalePowers[-1],
md: scalePowers[0],
lg: scalePowers[1],
xl: scalePowers[2],
'2xl': scalePowers[3],
});
export default s;
:root {
--scale--perfect-fourth: 1.333;
--scale: var(--scale--perfect-fourth);
--font-size: 1rem;
--font-size--xs: calc(var(--font-size) * 1 / var(--scale) / var(--scale));
--font-size--sm: calc(var(--font-size) * 1 / var(--scale));
--font-size--md: calc(var(--font-size) * 1);
--font-size--lg: calc(var(--font-size) * var(--scale));
--font-size--xl: calc(var(--font-size) * var(--scale) * var(--scale));
--font-size--2xl: calc(var(--font-size) * var(--scale) * var(--scale) * var(--scale));
}
The useMultiplier()
function automatically:
- Creates properly named variables following the base variable's naming pattern
- Generates
calc()
expressions that reference the base variable - Provides type-safe return values with correct variable names
useMultiplier()
with scale powers keeps your design system flexible. Change the base fontSize
or scale
variable, and all derived sizes update automatically throughout your design system.Examples
Typography Scale
Here's how to create a complete typographic scale using a specific scale:
import { styleframe } from 'styleframe';
import { useScale, useScalePowers, useMultiplier, useFontSize } from '@styleframe/theme';
const s = styleframe();
// Set your preferred default scale
const { scale } = useScale(s);
// Define base font size
const { fontSize } = useFontSize(s, { default: '1rem' });
// Create typographic scale using the default scale variable
const scalePowers = useScalePowers(s, scale, [-2, -1, 0, 1, 2]);
// Create font size variables automatically
const {
fontSizeXs,
fontSizeSm,
fontSizeMd,
fontSizeLg,
fontSizeXl,
} = useMultiplier(s, fontSize, {
xs: scalePowers[-2], // ~0.563rem
sm: scalePowers[-1], // ~0.750rem
md: scalePowers[0], // ~1.000rem
lg: scalePowers[1], // ~1.333rem
xl: scalePowers[2], // ~1.777rem
});
export default s;
:root {
--scale--minor-third: 1.2;
--scale: var(--scale--minor-third);
--font-size: 1rem;
--font-size--xs: calc(var(--font-size) * 1 / var(--scale) / var(--scale));
--font-size--sm: calc(var(--font-size) * 1 / var(--scale));
--font-size--md: calc(var(--font-size) * 1);
--font-size--lg: calc(var(--font-size) * var(--scale));
--font-size--xl: calc(var(--font-size) * var(--scale) * var(--scale));
}
Using the scale
variable means you can change your entire design system's proportions by overriding just one variable.
Spacing Scale
Create a consistent spacing system using the same modular scale:
import { styleframe } from 'styleframe';
import { useScale, useScalePowers, useMultiplier, useSpacing } from '@styleframe/theme';
const s = styleframe();
// Use the Major Second scale (1.125) for subtle spacing differences
const { scale } = useScale(s);
// Define base spacing unit
const { spacing } = useSpacing(s, { default: '1rem' });
// Create spacing scale
const scalePowers = useScalePowers(s, scale, [-3, -2, -1, 1, 2, 3, 4, 5]);
// Create spacing variables automatically
const {
spacing3xs,
spacing2xs,
spacingXs,
spacingMd,
spacingLg,
spacingXl,
spacing2xl,
spacing3xl,
} = useMultiplier(s, spacing, {
'3xs': scalePowers[-3], // ~0.704rem
'2xs': scalePowers[-2], // ~0.790rem
xs: scalePowers[-1], // ~0.889rem
md: scalePowers[1], // ~1.125rem
lg: scalePowers[2], // ~1.266rem
xl: scalePowers[3], // ~1.424rem
'2xl': scalePowers[4], // ~1.602rem
'3xl': scalePowers[5], // ~1.802rem
});
export default s;
:root {
--scale--minor-third: 1.2;
--scale: var(--scale--minor-third);
--spacing: 1rem;
--spacing--xs: calc(var(--spacing) * 1 / var(--scale) / var(--scale));
--spacing--sm: calc(var(--spacing) * 1 / var(--scale));
--spacing--md: calc(var(--spacing) * 1);
--spacing--lg: calc(var(--spacing) * var(--scale));
--spacing--xl: calc(var(--spacing) * var(--scale) * var(--scale));
}
Scale Reference Guide
Here's a reference for each scale ratio and its typical use cases:
Scale | Ratio | Use Case |
---|---|---|
Minor Second | 1.067 | Very subtle scaling, ideal for fine-tuned adjustments |
Major Second | 1.125 | Subtle but noticeable, great for spacing systems |
Minor Third | 1.2 | Balanced scaling, versatile for most applications |
Major Third | 1.25 | Popular for web typography, clear hierarchy |
Perfect Fourth | 1.333 | Classic choice, strong but not overwhelming |
Augmented Fourth | 1.414 | Square root of 2, mathematically derived |
Perfect Fifth | 1.5 | Pronounced scaling, creates clear distinctions |
Golden Ratio | 1.618 | Dramatic scaling, ideal for hero sections |
Best Practices
- Choose one primary scale for most of your design system to maintain consistency.
- Use smaller ratios (1.125-1.25) for spacing and line-height where subtle differences work best.
- Use larger ratios (1.333-1.618) for typography and major layout elements where clear hierarchy is important.
- Limit your power range to avoid too many size options (typically -3 to 6 is sufficient).
- Document your scale decisions so team members understand which scale to use for different purposes.
- Test on real content to ensure your scale works well across different contexts and viewport sizes.
FAQ
scale
variable acts as a single control point for your design system. Instead of hardcoding specific scales like scalePerfectFourth
, you reference the generic scale
variable. This lets you switch your entire design's proportions by changing one variable at different breakpoints or in different themes, making your system more flexible and maintainable.scale
variable at any breakpoint. For example, use a subtle scale (1.125) on mobile where space is limited, and a more dramatic scale (1.333) on desktop where larger type differences are easier to read. Your power-based sizes will automatically adjust while maintaining their relationships.Absolutely. Since scale
is a CSS variable, you can override it anywhere. For example, use the code below to switch to a tighter scale for compact UI areas while keeping the rest of your design unchanged.
s.selector('.compact', ({ variable }) => {
variable(scale, s.ref(scaleMajorSecond));
});
calc()
with CSS variables keeps your scale system dynamic. When you change the base scale ratio or base size, all derived values update automatically without rebuilding your CSS. This is especially powerful for theming, responsive adjustments, and maintaining consistency across your design system.useMultiplier()
automates the creation of size variables based on your scale. Instead of manually writing s.variable('font-size--<size>', ...)
for each size, it generates all variables automatically with consistent naming, creates proper calc()
expressions, and returns type-safe values. This reduces boilerplate and makes it easier to maintain a consistent naming convention.Fluid Design 🚧
Styleframe variables are the foundation of your design system. They let you define design tokens such as colors, spacing, typography, and more.
Spacing
Create and manage spacing design tokens with CSS variables for consistent layout spacing, padding, margins, and gaps across your application.