Style loading utilities that provide CSS-in-JS functionality with automatic vendor prefixing, RTL support, and server-side rendering capabilities.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Functions for registering custom fonts and CSS animations using JavaScript objects. These utilities enable you to define fonts and keyframe animations programmatically and use them in your styles.
Registers a custom font face definition that can be used throughout your application. The font is immediately available after registration.
/**
* Registers a font face for use in styles
* @param font - Font face definition with family, source, and properties
*/
function fontFace(font: IFontFace): void;Usage Examples:
import { fontFace, mergeStyles } from '@uifabric/merge-styles';
// Register a custom font
fontFace({
fontFamily: 'MyCustomFont',
src: `url('fonts/MyCustomFont.woff2') format('woff2'),
url('fonts/MyCustomFont.woff') format('woff')`,
fontWeight: 'normal',
fontStyle: 'normal',
fontDisplay: 'swap'
});
// Use the registered font in styles
const textClass = mergeStyles({
fontFamily: 'MyCustomFont, Arial, sans-serif',
fontSize: '16px'
});Google Fonts Integration:
// Register Google Font
fontFace({
fontFamily: 'Roboto',
src: `url('https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxKKTU1Kg.woff2') format('woff2')`,
fontWeight: '400',
fontStyle: 'normal',
fontDisplay: 'swap'
});
// Register bold variant
fontFace({
fontFamily: 'Roboto',
src: `url('https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmWUlfBBc4AMP6lQ.woff2') format('woff2')`,
fontWeight: '700',
fontStyle: 'normal',
fontDisplay: 'swap'
});
// Use with different weights
const titleClass = mergeStyles({
fontFamily: 'Roboto, sans-serif',
fontWeight: '700',
fontSize: '24px'
});
const bodyClass = mergeStyles({
fontFamily: 'Roboto, sans-serif',
fontWeight: '400',
fontSize: '16px'
});Icon Fonts:
// Register icon font
fontFace({
fontFamily: 'MyIcons',
src: `url('fonts/icons.woff2') format('woff2')`,
fontWeight: 'normal',
fontStyle: 'normal'
});
// Create icon classes
const iconClass = mergeStyles({
fontFamily: 'MyIcons',
fontSize: '20px',
lineHeight: 1,
'&::before': {
content: '"\\e001"' // Unicode for specific icon
}
});Registers CSS keyframe animations and returns the animation name that can be used in styles. Supports all CSS animation properties and timing functions.
/**
* Registers keyframe definitions for CSS animations
* @param timeline - Object defining keyframe percentages and their styles
* @returns Animation name string that can be used in animationName property
*/
function keyframes(timeline: IKeyframes): string;Usage Examples:
import { keyframes, mergeStyles } from '@uifabric/merge-styles';
// Define fade in animation
const fadeIn = keyframes({
from: {
opacity: 0
},
to: {
opacity: 1
}
});
// Use animation in styles
const fadeInClass = mergeStyles({
animationName: fadeIn,
animationDuration: '0.3s',
animationTimingFunction: 'ease-in-out'
});
// Alternative percentage syntax
const slideIn = keyframes({
'0%': {
transform: 'translateX(-100%)',
opacity: 0
},
'50%': {
transform: 'translateX(-10%)',
opacity: 0.7
},
'100%': {
transform: 'translateX(0)',
opacity: 1
}
});
const slideInClass = mergeStyles({
animationName: slideIn,
animationDuration: '0.5s',
animationFillMode: 'both'
});Complex Animations:
// Bounce animation with multiple properties
const bounce = keyframes({
'0%, 20%, 53%, 80%, 100%': {
transform: 'translate3d(0, 0, 0)'
},
'40%, 43%': {
transform: 'translate3d(0, -30px, 0)'
},
'70%': {
transform: 'translate3d(0, -15px, 0)'
},
'90%': {
transform: 'translate3d(0, -4px, 0)'
}
});
// Pulse animation with scale and opacity
const pulse = keyframes({
'0%': {
transform: 'scale(1)',
opacity: 1
},
'50%': {
transform: 'scale(1.05)',
opacity: 0.8
},
'100%': {
transform: 'scale(1)',
opacity: 1
}
});
// Use multiple animations
const animatedButtonClass = mergeStyles({
background: 'blue',
color: 'white',
border: 'none',
padding: '10px 20px',
borderRadius: '4px',
cursor: 'pointer',
// Apply animations on hover
':hover': {
animationName: pulse,
animationDuration: '0.6s',
animationIterationCount: 'infinite'
},
// Apply different animation when active
':active': {
animationName: bounce,
animationDuration: '0.8s'
}
});Loading Spinners:
// Rotating spinner
const spin = keyframes({
from: {
transform: 'rotate(0deg)'
},
to: {
transform: 'rotate(360deg)'
}
});
const spinnerClass = mergeStyles({
width: '20px',
height: '20px',
border: '2px solid #f3f3f3',
borderTop: '2px solid #3498db',
borderRadius: '50%',
animationName: spin,
animationDuration: '1s',
animationIterationCount: 'infinite',
animationTimingFunction: 'linear'
});
// Pulsing dots loader
const pulseDot = keyframes({
'0%, 80%, 100%': {
transform: 'scale(0)',
opacity: 0.5
},
'40%': {
transform: 'scale(1)',
opacity: 1
}
});
const dotLoaderClass = mergeStyles({
display: 'inline-block',
width: '8px',
height: '8px',
borderRadius: '50%',
background: '#3498db',
animationName: pulseDot,
animationDuration: '1.4s',
animationIterationCount: 'infinite',
animationFillMode: 'both',
// Delay for multiple dots
'&:nth-child(1)': { animationDelay: '-0.32s' },
'&:nth-child(2)': { animationDelay: '-0.16s' }
});Animation Classes with Parameters:
// Create reusable animation function
const createSlideAnimation = (direction: 'left' | 'right' | 'up' | 'down') => {
const transforms = {
left: 'translateX(-100%)',
right: 'translateX(100%)',
up: 'translateY(-100%)',
down: 'translateY(100%)'
};
return keyframes({
from: {
transform: transforms[direction],
opacity: 0
},
to: {
transform: 'translate(0, 0)',
opacity: 1
}
});
};
// Use parameterized animations
const slideLeftAnimation = createSlideAnimation('left');
const slideRightAnimation = createSlideAnimation('right');
const modalClass = mergeStyles({
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
background: 'white',
padding: '20px',
borderRadius: '8px',
boxShadow: '0 4px 6px rgba(0, 0, 0, 0.1)',
// Enter animation
animationName: slideLeftAnimation,
animationDuration: '0.3s',
animationFillMode: 'both'
});Responsive Animations:
// Different animations for different screen sizes
const mobileSlide = keyframes({
from: { transform: 'translateY(100%)' },
to: { transform: 'translateY(0)' }
});
const desktopFade = keyframes({
from: { opacity: 0, transform: 'scale(0.9)' },
to: { opacity: 1, transform: 'scale(1)' }
});
const responsiveModalClass = mergeStyles({
// Base styles
background: 'white',
padding: '20px',
// Desktop animation
animationName: desktopFade,
animationDuration: '0.3s',
// Mobile animation
'@media (max-width: 768px)': {
animationName: mobileSlide,
animationDuration: '0.4s'
}
});interface IFontFace {
fontFamily: string;
src: string;
fontWeight?: IFontWeight;
fontStyle?: 'normal' | 'italic' | 'oblique';
fontDisplay?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
unicodeRange?: string;
fontVariant?: string;
fontFeatureSettings?: string;
fontStretch?: string;
}
type IFontWeight =
| 'normal' | 'bold' | 'bolder' | 'lighter'
| '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'
| 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
type IKeyframes = Record<string, IRawStyle>;
interface IRawStyle {
[key: string]: any;
displayName?: string;
}Font Loading Strategy:
// Preload critical fonts
fontFace({
fontFamily: 'CriticalFont',
src: `url('fonts/critical.woff2') format('woff2')`,
fontDisplay: 'swap' // Shows fallback font while loading
});
// Load non-critical fonts with fallback
fontFace({
fontFamily: 'DecoratieFont',
src: `url('fonts/decorative.woff2') format('woff2')`,
fontDisplay: 'optional' // Only shows if already cached
});Performance-Conscious Animations:
// Use transform and opacity for better performance
const efficientSlide = keyframes({
from: {
transform: 'translateX(-100%)', // Uses GPU acceleration
opacity: 0
},
to: {
transform: 'translateX(0)',
opacity: 1
}
});
// Avoid animating layout properties
const inefficientSlide = keyframes({
from: {
left: '-100px', // ❌ Causes layout recalculation
width: '0px' // ❌ Causes layout recalculation
},
to: {
left: '0px',
width: '200px'
}
});