Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save iamsaief/dad6b1d3b4bb96d374d415cff0e01dfd to your computer and use it in GitHub Desktop.
Save iamsaief/dad6b1d3b4bb96d374d415cff0e01dfd to your computer and use it in GitHub Desktop.
Responsive Typography | Fluid Font Size, SASS Mixin, Utility Class

Responsive Typography | Fluid Font Size, SASS Mixin, Utility Class

This Sass mixin allows you to create fluid font sizes that will scale responsively based on the viewport width. It takes two arguments:

  • Min font size: The minimum font size in pixels.
  • Max font size: The maximum font size in pixels.
  • (optional) Min viewport width: The minimum viewport width in pixels.
  • (optional) Max viewport width: The maximum viewport width in pixels.

The mixin will then calculate a fluid font size that falls within that range, based on the current viewport width.

/**
* Fluid Typography | SASS mixin with clamp() - @include fluid-font-size()
* @param {$min_font_size} - Number in px
* @param {$max_font_size} - Number in px,
* @param {$min_viewport} - Number in px (optional | default 576px)
* @param {$max_viewport} - Number in px (optional | default 1366px)
* @returns - Font Size using clamp()
* 
* Gist: https://gist.github.com/iamsaief/dad6b1d3b4bb96d374d415cff0e01dfd 
*/

@use "sass:math";

@mixin fluid-font-size($min_font_size, $max_font_size, $min_viewport: 576px, $max_viewport: 1366px) {
	font-size: clamp(
		$min_font_size,
		get-fluid-size($min_font_size, $max_font_size, $min_viewport, $max_viewport),
		$max_font_size
	);
}

@function get-fluid-size($min_font_size, $max_font_size, $min_viewport, $max_viewport) {
	$min_font_size_in_rem: #{math.div(strip-unit($min_font_size), 16)}rem;
	$font_size_diff: strip-unit($max_font_size) - strip-unit($min_font_size);
	$viewport_diff: strip-unit($max_viewport) - strip-unit($min_viewport);

	$fluid_size: calc($min_font_size_in_rem + $font_size_diff * ((100vw - $min_viewport) / ($viewport_diff)));

	@return $fluid-size;
}

@function strip-unit($number) {
	@if type-of($number) == "number" and not unitless($number) {
		@return math.div($number, ($number * 0) + 1);
	}

	@return $number;
}

// $fluid-sizes($name, $max, $min)
$fluid-sizes: (
	"h1" 60px 48px,
	"h2" 48px 36px,
	"h3" 36px 30px,
	"h4" 30px 24px,
	"h5" 24px 20px,
	"h6" 20px 18px,
	"p" 16px 14px
);

@each $name, $max, $min in $fluid-sizes {
	.fluid-text-#{$name} {
		@include fluid-font-size($min, $max);
	}
}

Usage

There are 3 ways to use the mixin:

  1. As a utility class: You can apply these classes to your elements or you could create your own utility classes.
  2. @include mixin: You can also use the mixin directly in your Sass code.
  3. @extend utility class: You can also use the @extend at-rule to extend the utility classes created by the mixin.
<!-- Usage #1 - as utility class  -->

<h1 class="fluid-text-h1">I am heading 1</h1>
<h2 class="fluid-text-h2">I am heading 2</h2>
...
...
<h6 class="fluid-text-h6">I am heading 6</h6>

<!-- utility classes
.fluid-text-h1 {
  font-size: clamp(48px, 3rem + 12 * (100vw - 576px) / 790, 60px);
}

.fluid-text-h2 {
  font-size: clamp(36px, 2.25rem + 12 * (100vw - 576px) / 790, 48px);
}

...
...

.fluid-text-h6 {
  font-size: clamp(18px, 1.125rem + 2 * (100vw - 576px) / 790, 20px);
}
 -->
// Usage #2 - @include mixin
body {
	@include fluid-font-size(14px, 16px);
}

// Usage #3 - @extend utility class
h1 {
	@extend .fluid-text-h1;
}
/**
* Returns a clamp expression for fluid typography based on the given parameters.
* @param {string} minFontSize - The minimum font size in pixels.
* @param {string} maxFontSize - The maximum font size in pixels.
* @param {string} [minViewport='768px'] - The minimum viewport width in pixels.
* @param {string} [maxViewport='1400px'] - The maximum viewport width in pixels.
* @returns {string} A clamp expression that can be used in CSS.
*/
export function getFluidFontSize(minFontSize, maxFontSize, minViewport = '768px', maxViewport = '1400px') {
// Convert the parameters to numbers
minFontSize = parseFloat(minFontSize);
maxFontSize = parseFloat(maxFontSize);
minViewport = parseFloat(minViewport);
maxViewport = parseFloat(maxViewport);
let fontSizeInRem = minFontSize / 16;
let fontSizeDiff = maxFontSize - minFontSize;
let viewportDiff = maxViewport - minViewport;
// Return the clamp expression as a string
return `clamp(${minFontSize}px, calc(${fontSizeInRem}rem + ${fontSizeDiff} * ((100vw - ${minViewport}px) / ${viewportDiff})), ${maxFontSize}px)`;
}
console.log(getFluidFontSize('70px', '200px')) // clamp(70px, calc(4.375rem + 130 * ((100vw - 768px) / 632)), 200px)
console.log(getFluidFontSize('60px', '140px')) // clamp(60px, calc(3.75rem + 80 * ((100vw - 768px) / 632)), 140px)
console.log(getFluidFontSize('50px', '100px')) // clamp(50px, calc(3.125rem + 50 * ((100vw - 768px) / 632)), 100px)
/**
* Fluid Typography | SASS mixin with clamp() - @include fluid-font-size()
* @param {$min_font_size} - Number in px
* @param {$max_font_size} - Number in px,
* @param {$min_viewport} - Number in px (optional | default 576px)
* @param {$max_viewport} - Number in px (optional | default 1366px)
* @returns - Font Size using clamp()
*
* Gist: https://gist.github.com/iamsaief/dad6b1d3b4bb96d374d415cff0e01dfd
*/
@use "sass:math";
@mixin fluid-font-size($min_font_size, $max_font_size, $min_viewport: 576px, $max_viewport: 1366px) {
font-size: clamp(
$min_font_size,
get-fluid-size($min_font_size, $max_font_size, $min_viewport, $max_viewport),
$max_font_size
);
}
@function get-fluid-size($min_font_size, $max_font_size, $min_viewport, $max_viewport) {
$min_font_size_in_rem: #{math.div(strip-unit($min_font_size), 16)}rem;
$font_size_diff: strip-unit($max_font_size) - strip-unit($min_font_size);
$viewport_diff: strip-unit($max_viewport) - strip-unit($min_viewport);
$fluid_size: calc($min_font_size_in_rem + $font_size_diff * ((100vw - $min_viewport) / ($viewport_diff)));
@return $fluid-size;
}
@function strip-unit($number) {
@if type-of($number) == "number" and not unitless($number) {
@return math.div($number, ($number * 0) + 1);
}
@return $number;
}
// $fluid-sizes($name, $max, $min)
$fluid-sizes: (
"h1" 60px 48px,
"h2" 48px 36px,
"h3" 36px 30px,
"h4" 30px 24px,
"h5" 24px 20px,
"h6" 20px 18px,
"p" 16px 14px
);
@each $name, $max, $min in $fluid-sizes {
.fluid-text-#{$name} {
@include fluid-font-size($min, $max);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment