Font loading, text utilities, and accessibility helpers for consistent typography and visual presentation. These mixins handle font-face declarations, text truncation, accessibility improvements, and text overflow behavior.
Generates @font-face declarations with support for multiple font formats and Rails Asset Pipeline integration.
/**
* Generates @font-face declarations
* @param $font-family - The font family name
* @param $file-path - Path to font files (without extension)
* @param $file-formats - List of font formats to include (optional, defaults to setting)
* @param $asset-pipeline - Enable Rails Asset Pipeline support (optional, defaults to setting)
* @content - Additional CSS properties for the @font-face rule
* @requires _font-source-declaration function
* @requires _fetch-bourbon-setting function
*/
@mixin font-face(
$font-family,
$file-path,
$file-formats: _fetch-bourbon-setting("global-font-file-formats"),
$asset-pipeline: _fetch-bourbon-setting("rails-asset-pipeline")
);Usage Examples:
// Basic font-face with default formats
@include font-face(
"source-sans-pro",
"fonts/source-sans-pro-regular"
) {
font-style: normal;
font-weight: 400;
}
// Result:
// @font-face {
// font-family: "source-sans-pro";
// src: url("fonts/source-sans-pro-regular.woff2") format("woff2"),
// url("fonts/source-sans-pro-regular.woff") format("woff");
// font-style: normal;
// font-weight: 400;
// }
// Custom font formats
@include font-face(
"custom-font",
"fonts/custom-font-bold",
("woff2", "woff", "ttf")
) {
font-weight: 700;
font-display: swap;
}
// With Rails Asset Pipeline
@include font-face(
"app-font",
"app-font-regular",
("woff2", "woff"),
true
) {
font-style: normal;
font-weight: 400;
}Truncates text with ellipsis using CSS text-overflow property.
/**
* Truncates text with ellipsis
* @param $width - Maximum width before truncation (optional, defaults to 100%)
* @param $display - Display property value (optional, defaults to inline-block)
*/
@mixin ellipsis($width: 100%, $display: inline-block);Usage Examples:
// Basic ellipsis
.title {
@include ellipsis;
// Result:
// display: inline-block;
// max-width: 100%;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
}
// Custom width and display
.truncated-label {
@include ellipsis(200px, block);
// Result:
// display: block;
// max-width: 200px;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
}
// Responsive ellipsis
.card-title {
@include ellipsis(calc(100% - 2rem), block);
}Hides text in an element while preserving its box model, typically used for image replacement techniques.
/**
* Hides text in element (for image replacement)
* Uses text-indent method for better performance and accessibility
*/
@mixin hide-text;Usage Examples:
// Logo replacement
.logo {
@include hide-text;
background-image: url('logo.png');
@include size(150px, 50px);
// Result:
// overflow: hidden;
// text-indent: 101%;
// white-space: nowrap;
}
// Icon buttons with text labels
.icon-button {
@include hide-text;
background: url('icon.svg') no-repeat center;
@include size(32px);
}Hides elements visually while preserving them for screen readers and accessibility tools.
/**
* Hides element visually while preserving accessibility
* @param $toggle - "hide" or "unhide" (optional, defaults to "hide")
*/
@mixin hide-visually($toggle: "hide");Usage Examples:
// Hide for visual users, keep for screen readers
.sr-only {
@include hide-visually;
// Result:
// border: 0;
// clip: rect(0, 0, 0, 0);
// height: 1px;
// margin: -1px;
// overflow: hidden;
// padding: 0;
// position: absolute;
// white-space: nowrap;
// width: 1px;
}
// Show element again
.sr-only-focusable:focus {
@include hide-visually("unhide");
// Result: Resets all properties to their default values
}
// Skip links pattern
.skip-link {
@include hide-visually;
&:focus {
@include hide-visually("unhide");
position: absolute;
top: 0;
left: 0;
z-index: 1000;
}
}Sets overflow-wrap (word-wrap) with legacy browser support.
/**
* Sets overflow-wrap with legacy word-wrap fallback
* @param $wrap - CSS overflow-wrap value (optional, defaults to "break-word")
*/
@mixin overflow-wrap($wrap: break-word);Usage Examples:
// Default break-word behavior
.long-content {
@include overflow-wrap;
// Result:
// word-wrap: break-word;
// overflow-wrap: break-word;
}
// Normal wrapping
.normal-text {
@include overflow-wrap(normal);
// Result:
// word-wrap: normal;
// overflow-wrap: normal;
}
// Anywhere wrapping (where supported)
.break-anywhere {
@include overflow-wrap(anywhere);
// Result:
// word-wrap: anywhere;
// overflow-wrap: anywhere;
}Typography mixins can be configured globally:
$bourbon: (
"global-font-file-formats": ("woff2", "woff", "ttf"),
"rails-asset-pipeline": true
);Set configuration before importing Bourbon.
The font-face mixin supports these font formats:
// Good: Provides context for screen readers
.icon-only-button {
@include hide-visually;
&::after {
content: "Close dialog";
@include hide-visually("unhide");
position: absolute;
// Position off-screen but accessible
}
}
// Better: Use proper ARIA attributes
// <button aria-label="Close dialog">×</button>// Optimize font loading with font-display
@include font-face("body-font", "fonts/body-regular") {
font-display: swap; // Improves perceived performance
}
// Preload critical fonts in HTML
// <link rel="preload" href="fonts/body-regular.woff2" as="font" type="font/woff2" crossorigin>// Responsive typography with ellipsis
.responsive-title {
@include ellipsis(100%, block);
font-size: clamp(1.2rem, 4vw, 2rem);
}
// Accessible skip navigation
.skip-nav {
@include hide-visually;
&:focus {
@include hide-visually("unhide");
position: fixed;
top: 0;
left: 0;
background: #000;
color: #fff;
padding: 1rem;
z-index: 9999;
}
}
// Icon replacement with fallback
.social-icon {
@include hide-text;
@include size(32px);
background: url('icon.svg') no-repeat center;
background-size: contain;
// Fallback for when images don't load
&::before {
content: attr(data-label);
@include hide-visually("unhide");
font-size: 0.8rem;
}
}