Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validation check for type scale accessibility #2

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions properties/type-scale.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,22 @@ import { generateTypeScaleProperties, defaultConfig } from '../lib/scales.mjs'
export default function typeScaleProperties(state = {}) {
const { config = {} } = state
const { typeScale = defaultConfig } = config
const validateAccessibility = typeScale.validateAccessibility ?? true

if (!validateTypeScaleAccessibility(typeScale)) {
let message = 'Your requested type scale fails the WCAG SC 1.4.4 accessibility rule. ';
if (validateAccessibility) {
throw Error(message
+ "If you would like to proceed anyway, then set 'validateAccessibility' "
+ 'to false in your typeScale config.'
)
} else {
console.warn(message
+ "This is just a warning instead of an error because 'validateAccessibility' "
+ 'is set to false.'
)
}
}

let output = ''

Expand All @@ -14,3 +30,36 @@ export default function typeScaleProperties(state = {}) {

return output
}

function validateTypeScaleAccessibility(typeScale) {
// WCAG SC 1.4.4 check, ported from https://github.com/barvian/fluid-tailwind/blob/f85f1ae5a50ec1a37f99418d6d087a3a2e783e1b/packages/fluid-tailwind/src/util/expr.ts#L116
// @see https://www.smashingmagazine.com/2023/11/addressing-accessibility-concerns-fluid-type/
const { baseMin, baseMax, viewportMin, viewportMax } = typeScale
const slope = (baseMax - baseMin) / (viewportMax - viewportMin)
const intercept = baseMin - viewportMin * slope

// 2*zoom1(vw) is the AA requirement
const zoom1 = (vw) => clamp(baseMin, intercept + slope * vw, baseMax)
const zoom5 = (vw) =>
// browser doesn't scale vw units when zooming, so this isn't 5*zoom1(vw)
clamp(5 * baseMin, 5 * intercept + slope * vw, 5 * baseMax)

// Check the clamped points on the lines 2*z1(vw) and zoom5(vw) and fail if zoom5 < 2*zoom1
if (5 * baseMin < 2 * zoom1(5 * viewportMin)) {
return false
}
if (zoom5(viewportMax) < 2 * baseMax) {
return false
}
return true
}

/**
* Simulate the math that CSS `clamp` does
* @param {number} min
* @param {number} n
* @param {number} max
*/
function clamp(min, n, max) {
return Math.min(Math.max(n, min), max)
}
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ The configuration file must provide an object as its default export (i.e. `expor
| `typeScale.baseMax` | The base font size, in pixels, at the maximum viewport width | number | `18` |
| `typeScale.scaleMin` | The ratio, either as a rational number or a named ratio, to use for font size intervals at the minimum viewport width | number or string | `minor-third` |
| `typeScale.scaleMax` | The ratio, either as a rational number or a named ratio, to use for font size intervals at the maximum viewport width | number or string | `perfect-fourth` |
| `typeScale.validateAccessibility` | By default, Paramour will throw an error if your type scale would potentially cause a violation of the [WCAG accessibility rule SC 1.4.4](https://www.w3.org/WAI/WCAG22/Understanding/resize-text), which requires that text can be enlarged to twice its original size when zooming. Set this to false to generate such a type scale anyway (a warning message will still appear for awareness). | boolean | `true` |

For the space and type scales, the following common ratios can be referenced by name for the `scaleMin` and `scaleMax` properties:

Expand Down
46 changes: 46 additions & 0 deletions test/lib/scales.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
generateTypeScaleProperties,
generateSpaceScaleProperties,
} from '../../lib/scales.mjs'
import typeScaleProperties from '../../properties/type-scale.mjs'

test('getRatioValue', t => {
const num = 1.5
Expand Down Expand Up @@ -115,3 +116,48 @@ test('generateSpaceScaleProperties', t => {
t.ok(isSymmetrical, 'produces a symmetrical set of negative and positive intervals')
t.end()
})

test('validates type scale accessibility', t => {
const commonConfig = {
viewportMin: 320,
viewportMax: 1500,
}

t.throws(() => {
typeScaleProperties({
config: {
typeScale: {
...commonConfig,
baseMin: 7,
baseMax: 18,
}
}
})
});

// should not throw because `validateAccessibility` is set to false
typeScaleProperties({
config: {
typeScale: {
...commonConfig,
validateAccessibility: false,
baseMin: 7,
baseMax: 18,
}
}
})

// should not throw because it meets the accessibility requirement
typeScaleProperties({
config: {
typeScale: {
...commonConfig,
validateAccessibility: false,
baseMin: 8,
baseMax: 18,
}
}
})

t.end()
})