Skip to content

Instantly share code, notes, and snippets.

@souporserious
Created April 5, 2022 07:29
Show Gist options
  • Save souporserious/7d0f834ec293482e86dc84eceb119a55 to your computer and use it in GitHub Desktop.
Save souporserious/7d0f834ec293482e86dc84eceb119a55 to your computer and use it in GitHub Desktop.
type Step = number | string
/**
* Create a fluid type scale that can be interpolated between a minimum and maximum screen width.
*
* Forked from: https://www.aleksandrhovhannisyan.com/blog/fluid-type-scale-with-css-clamp/
*/
export function createTypeScale<Steps extends ReadonlyArray<Step>>({
baseFontSize,
ratio,
screen,
baseStep,
steps,
}: {
baseFontSize: [minFontSize: number, maxFontSize: number]
ratio: [minRatio: number, maxRatio: number]
screen: [minWidth: number, maxWidth: number]
baseStep: Steps[number]
steps: Steps
}) {
const [minFontSize, maxFontSize] = baseFontSize
const [minRatio, maxRatio] = ratio
const [minWidth, maxWidth] = screen
const round = (value: number) => Number(value.toFixed(4))
const remUnit = (value: number) => `${round(value)}rem`
const baseStepIndex = steps.indexOf(baseStep)
return steps.map((step, index) => {
const minSize = minFontSize * Math.pow(minRatio, index - baseStepIndex)
const maxSize = maxFontSize * Math.pow(maxRatio, index - baseStepIndex)
const slope = (maxSize - minSize) / (maxWidth - minWidth)
const intercept = minSize - slope * minWidth
const minUnit = remUnit(minSize)
const maxUnit = remUnit(maxSize)
const slopeUnit = `${round(slope * 100)}vw`
const interceptUnit = remUnit(intercept)
const css = `clamp(${minUnit}, calc(${slopeUnit} + ${interceptUnit}), ${maxUnit})`
function getFontSizeAtScreenWidth(width: number) {
let preferredFontSize = slope * width + intercept
preferredFontSize = Math.min(maxSize, preferredFontSize)
preferredFontSize = Math.max(minSize, preferredFontSize)
return round(preferredFontSize)
}
return { css, step, getFontSizeAtScreenWidth }
})
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment