Typography
Veltix provides comprehensive typography management with flexible font systems and responsive text scaling.
Overview
Typography features include:
- Font Families: Multiple font stack options
- Font Sizes: Responsive size scales
- Font Weights: Complete weight ranges
- Line Heights: Optimized spacing
- Text Utilities: Ready-to-use text styles
Font Families
Default Font Stacks
// Veltix default font families
const fontFamilies = {
sans: [
'Inter',
'system-ui',
'-apple-system',
'BlinkMacSystemFont',
'Segoe UI',
'Roboto',
'Helvetica Neue',
'Arial',
'sans-serif'
],
serif: [
'Georgia',
'Cambria',
'Times New Roman',
'Times',
'serif'
],
mono: [
'SF Mono',
'Monaco',
'Inconsolata',
'Roboto Mono',
'Source Code Pro',
'Menlo',
'Consolas',
'DejaVu Sans Mono',
'monospace'
],
display: [
'Poppins',
'Inter',
'system-ui',
'sans-serif'
]
};Custom Font Configuration
// Custom font configuration
const customFonts = {
brand: {
name: 'Brand Font',
family: ['BrandFont', 'Inter', 'sans-serif'],
weights: [300, 400, 500, 600, 700],
styles: ['normal', 'italic']
},
heading: {
name: 'Heading Font',
family: ['HeadingFont', 'Poppins', 'sans-serif'],
weights: [400, 500, 600, 700, 800],
styles: ['normal']
},
body: {
name: 'Body Font',
family: ['BodyFont', 'Inter', 'sans-serif'],
weights: [300, 400, 500],
styles: ['normal', 'italic']
}
};
// Font loading utility
const loadFonts = async (fonts) => {
const fontPromises = fonts.map(font => {
return new FontFace(font.name, `url(${font.url})`).load();
});
const loadedFonts = await Promise.all(fontPromises);
loadedFonts.forEach(font => document.fonts.add(font));
return loadedFonts;
};Font Sizes
Responsive Size Scale
// Responsive font size scale
const fontSizes = {
xs: {
base: '0.75rem', // 12px
sm: '0.875rem', // 14px
lg: '1rem' // 16px
},
sm: {
base: '0.875rem', // 14px
sm: '1rem', // 16px
lg: '1.125rem' // 18px
},
base: {
base: '1rem', // 16px
sm: '1.125rem', // 18px
lg: '1.25rem' // 20px
},
lg: {
base: '1.125rem', // 18px
sm: '1.25rem', // 20px
lg: '1.5rem' // 24px
},
xl: {
base: '1.25rem', // 20px
sm: '1.5rem', // 24px
lg: '1.875rem' // 30px
},
'2xl': {
base: '1.5rem', // 24px
sm: '1.875rem', // 30px
lg: '2.25rem' // 36px
},
'3xl': {
base: '1.875rem', // 30px
sm: '2.25rem', // 36px
lg: '3rem' // 48px
},
'4xl': {
base: '2.25rem', // 36px
sm: '3rem', // 48px
lg: '4rem' // 64px
},
'5xl': {
base: '3rem', // 48px
sm: '4rem', // 64px
lg: '5rem' // 80px
}
};Fluid Typography
// Fluid typography utility
const createFluidTypography = (minSize, maxSize, minWidth = 320, maxWidth = 1200) => {
const minSizeRem = minSize / 16;
const maxSizeRem = maxSize / 16;
const minWidthRem = minWidth / 16;
const maxWidthRem = maxWidth / 16;
const slope = (maxSizeRem - minSizeRem) / (maxWidthRem - minWidthRem);
const intercept = minSizeRem - slope * minWidthRem;
return `clamp(${minSizeRem}rem, ${intercept}rem + ${slope * 100}vw, ${maxSizeRem}rem)`;
};
// Fluid typography examples
const fluidTypography = {
h1: createFluidTypography(32, 64),
h2: createFluidTypography(24, 48),
h3: createFluidTypography(20, 36),
h4: createFluidTypography(18, 30),
h5: createFluidTypography(16, 24),
h6: createFluidTypography(14, 20),
body: createFluidTypography(14, 18),
small: createFluidTypography(12, 14)
};Font Weights
Weight Scale
// Font weight scale
const fontWeights = {
thin: 100,
extralight: 200,
light: 300,
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
extrabold: 800,
black: 900
};
// Weight utilities
const weightUtils = {
// Get weight value
getWeight: (weight) => fontWeights[weight] || weight,
// Check if weight is available for font
isWeightAvailable: (fontFamily, weight) => {
const weights = getAvailableWeights(fontFamily);
return weights.includes(weight);
},
// Get available weights for font
getAvailableWeights: (fontFamily) => {
// This would typically check the loaded font
return [300, 400, 500, 600, 700];
}
};Line Heights
Optimized Line Heights
// Line height scale
const lineHeights = {
none: 1,
tight: 1.25,
snug: 1.375,
normal: 1.5,
relaxed: 1.625,
loose: 2
};
// Responsive line heights
const responsiveLineHeights = {
xs: {
base: 1.25,
sm: 1.375,
lg: 1.5
},
sm: {
base: 1.375,
sm: 1.5,
lg: 1.625
},
base: {
base: 1.5,
sm: 1.625,
lg: 1.75
},
lg: {
base: 1.625,
sm: 1.75,
lg: 1.875
},
xl: {
base: 1.75,
sm: 1.875,
lg: 2
}
};
// Calculate optimal line height
const calculateLineHeight = (fontSize, lineHeight = 'normal') => {
const size = typeof fontSize === 'string' ?
parseInt(fontSize) : fontSize;
const baseLineHeight = lineHeights[lineHeight] || lineHeight;
return size * baseLineHeight;
};Text Utilities
Typography Components
// Typography component
function Typography({
variant = 'body',
size = 'base',
weight = 'normal',
family = 'sans',
color = 'inherit',
align = 'left',
children,
...props
}) {
const typographyStyles = {
fontFamily: fontFamilies[family].join(', '),
fontSize: fontSizes[size].base,
fontWeight: fontWeights[weight],
lineHeight: responsiveLineHeights[size].base,
color,
textAlign: align,
...getVariantStyles(variant)
};
return (
<div style={typographyStyles} {...props}>
{children}
</div>
);
}
// Variant styles
const getVariantStyles = (variant) => {
const variants = {
h1: {
fontSize: fontSizes['4xl'].base,
fontWeight: fontWeights.bold,
lineHeight: lineHeights.tight
},
h2: {
fontSize: fontSizes['3xl'].base,
fontWeight: fontWeights.semibold,
lineHeight: lineHeights.snug
},
h3: {
fontSize: fontSizes['2xl'].base,
fontWeight: fontWeights.semibold,
lineHeight: lineHeights.snug
},
h4: {
fontSize: fontSizes.xl.base,
fontWeight: fontWeights.medium,
lineHeight: lineHeights.normal
},
h5: {
fontSize: fontSizes.lg.base,
fontWeight: fontWeights.medium,
lineHeight: lineHeights.normal
},
h6: {
fontSize: fontSizes.base.base,
fontWeight: fontWeights.medium,
lineHeight: lineHeights.normal
},
body: {
fontSize: fontSizes.base.base,
fontWeight: fontWeights.normal,
lineHeight: lineHeights.relaxed
},
small: {
fontSize: fontSizes.sm.base,
fontWeight: fontWeights.normal,
lineHeight: lineHeights.normal
},
caption: {
fontSize: fontSizes.xs.base,
fontWeight: fontWeights.normal,
lineHeight: lineHeights.normal
}
};
return variants[variant] || variants.body;
};Text Utilities Hook
// Typography utilities hook
const useTypography = () => {
const getFontSize = useCallback((size, responsive = false) => {
if (responsive) {
return fontSizes[size];
}
return fontSizes[size].base;
}, []);
const getLineHeight = useCallback((size, responsive = false) => {
if (responsive) {
return responsiveLineHeights[size];
}
return responsiveLineHeights[size].base;
}, []);
const getFontWeight = useCallback((weight) => {
return fontWeights[weight] || weight;
}, []);
const getFontFamily = useCallback((family) => {
return fontFamilies[family].join(', ');
}, []);
const createTextStyle = useCallback(({
size = 'base',
weight = 'normal',
family = 'sans',
lineHeight = 'normal',
color = 'inherit'
}) => {
return {
fontSize: getFontSize(size),
fontWeight: getFontWeight(weight),
fontFamily: getFontFamily(family),
lineHeight: lineHeights[lineHeight],
color
};
}, [getFontSize, getFontWeight, getFontFamily]);
return {
getFontSize,
getLineHeight,
getFontWeight,
getFontFamily,
createTextStyle
};
};Responsive Typography
Breakpoint-based Typography
// Responsive typography system
const responsiveTypography = {
h1: {
xs: { fontSize: '1.5rem', lineHeight: 1.25 },
sm: { fontSize: '2rem', lineHeight: 1.25 },
md: { fontSize: '2.5rem', lineHeight: 1.2 },
lg: { fontSize: '3rem', lineHeight: 1.2 },
xl: { fontSize: '3.5rem', lineHeight: 1.1 }
},
h2: {
xs: { fontSize: '1.25rem', lineHeight: 1.3 },
sm: { fontSize: '1.5rem', lineHeight: 1.3 },
md: { fontSize: '1.875rem', lineHeight: 1.25 },
lg: { fontSize: '2.25rem', lineHeight: 1.25 },
xl: { fontSize: '2.5rem', lineHeight: 1.2 }
},
body: {
xs: { fontSize: '0.875rem', lineHeight: 1.5 },
sm: { fontSize: '1rem', lineHeight: 1.5 },
md: { fontSize: '1.125rem', lineHeight: 1.6 },
lg: { fontSize: '1.25rem', lineHeight: 1.6 },
xl: { fontSize: '1.375rem', lineHeight: 1.6 }
}
};
// Responsive text component
function ResponsiveText({
variant = 'body',
breakpoint = 'md',
children,
...props
}) {
const styles = responsiveTypography[variant][breakpoint];
return (
<div style={styles} {...props}>
{children}
</div>
);
}CSS-in-JS Responsive Typography
// CSS-in-JS responsive typography
const createResponsiveTypography = (variant) => {
const styles = responsiveTypography[variant];
return `
font-size: ${styles.xs.fontSize};
line-height: ${styles.xs.lineHeight};
@media (min-width: 640px) {
font-size: ${styles.sm.fontSize};
line-height: ${styles.sm.lineHeight};
}
@media (min-width: 768px) {
font-size: ${styles.md.fontSize};
line-height: ${styles.md.lineHeight};
}
@media (min-width: 1024px) {
font-size: ${styles.lg.fontSize};
line-height: ${styles.lg.lineHeight};
}
@media (min-width: 1280px) {
font-size: ${styles.xl.fontSize};
line-height: ${styles.xl.lineHeight};
}
`;
};Typography Themes
Theme-based Typography
// Typography theme configuration
const typographyTheme = {
fonts: {
primary: fontFamilies.sans,
secondary: fontFamilies.serif,
mono: fontFamilies.mono,
display: fontFamilies.display
},
sizes: {
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
'2xl': '1.5rem',
'3xl': '1.875rem',
'4xl': '2.25rem',
'5xl': '3rem'
},
weights: {
light: 300,
normal: 400,
medium: 500,
semibold: 600,
bold: 700,
extrabold: 800
},
lineHeights: {
none: 1,
tight: 1.25,
snug: 1.375,
normal: 1.5,
relaxed: 1.625,
loose: 2
},
letterSpacing: {
tighter: '-0.05em',
tight: '-0.025em',
normal: '0em',
wide: '0.025em',
wider: '0.05em',
widest: '0.1em'
}
};
// Apply typography theme
const applyTypographyTheme = (theme) => {
const root = document.documentElement;
// Apply font families
Object.entries(theme.fonts).forEach(([name, family]) => {
root.style.setProperty(`--font-family-${name}`, family.join(', '));
});
// Apply font sizes
Object.entries(theme.sizes).forEach(([size, value]) => {
root.style.setProperty(`--font-size-${size}`, value);
});
// Apply font weights
Object.entries(theme.weights).forEach(([weight, value]) => {
root.style.setProperty(`--font-weight-${weight}`, value);
});
// Apply line heights
Object.entries(theme.lineHeights).forEach(([height, value]) => {
root.style.setProperty(`--line-height-${height}`, value);
});
// Apply letter spacing
Object.entries(theme.letterSpacing).forEach(([spacing, value]) => {
root.style.setProperty(`--letter-spacing-${spacing}`, value);
});
};Performance Optimization
Font Loading Optimization
// Font loading optimization
const optimizeFontLoading = (fonts) => {
// Preload critical fonts
const criticalFonts = fonts.filter(font => font.critical);
criticalFonts.forEach(font => {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'font';
link.href = font.url;
link.crossOrigin = 'anonymous';
document.head.appendChild(link);
});
// Load non-critical fonts with lower priority
const nonCriticalFonts = fonts.filter(font => !font.critical);
nonCriticalFonts.forEach(font => {
const link = document.createElement('link');
link.rel = 'preload';
link.as = 'font';
link.href = font.url;
link.crossOrigin = 'anonymous';
link.media = 'print';
link.onload = () => {
link.media = 'all';
};
document.head.appendChild(link);
});
};
// Font display optimization
const fontDisplayOptions = {
auto: 'auto',
block: 'block',
swap: 'swap',
fallback: 'fallback',
optional: 'optional'
};
// Optimize font display
const optimizeFontDisplay = (fontFamily, display = 'swap') => {
const style = document.createElement('style');
style.textContent = `
@font-face {
font-family: '${fontFamily}';
font-display: ${display};
}
`;
document.head.appendChild(style);
};Best Practices
1. Font Selection
- Choose fonts that match your brand
- Consider readability and accessibility
- Test fonts across different devices
- Optimize font loading performance
2. Size and Spacing
- Use consistent size scales
- Ensure sufficient contrast
- Optimize line heights for readability
- Test typography at different screen sizes
3. Performance
- Optimize font loading
- Use font-display: swap
- Minimize font file sizes
- Cache font resources
4. Accessibility
- Ensure sufficient color contrast
- Use appropriate font sizes
- Provide alternative fonts
- Test with screen readers
Troubleshooting
Common Issues
Fonts not loading
- Check font URLs and paths
- Verify CORS settings
- Test font loading performance
- Check browser compatibility
Typography inconsistencies
- Verify font family fallbacks
- Check font weight availability
- Test across different browsers
- Validate CSS specificity
Performance issues
- Optimize font loading
- Use font-display strategies
- Minimize font file sizes
- Implement proper caching
Last updated on