Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

julien-deramond
Copy link
Member

@julien-deramond julien-deramond commented Jul 2, 2025

Closes #41543
Supersedes #41551

Description

The color-contrast function in scss/_functions.scss currently uses a strict greater than comparison (>) when checking if a contrast ratio meets the minimum requirement:

@if $contrast-ratio > $min-contrast-ratio {

This excludes colors that produce exactly the minimum contrast ratio (4.5:1), which violates the WCAG 2.1 Success Criterion 1.4.3 Contrast (Minimum). The standard requires "at least 4.5:1" (>= 4.5), not "strictly greater than 4.5:1" (> 4.5).

To comply with the standard, the comparison operator should be changed from > to >=:

@if $contrast-ratio >= $min-contrast-ratio {

This would ensure that colors producing exactly a 4.5:1 contrast ratio are accepted, correctly implementing the WCAG requirement.

Investigation results

After extensive testing, it appears that no specific colors in Bootstrap's current implementation produce exactly a 4.5:1 contrast ratio. This is due to Bootstrap’s use of a precomputed luminance list ($_luminance-list) that maps integer RGB values (0–255) to discrete luminance values.

I tested various colors near the 4.5:1 threshold against #fff and found:

  • #777777 (rgb(119, 119, 119)) → 4.4776:1
  • #767676 (rgb(118, 118, 118)) → 4.5415:1

So, there's no integer RGB color that yields exactly 4.5:1 in Bootstrap's current luminance calculation.

Testing colors like #777777, #767676, #787878, #757575 gives the same results with or without the fix, matching results from tooks like WebAIM: Contrast Checker.

Testing approach

I created a Sass test suite (scss/tests/mixins/_color-contrast.test.scss) that tests the boundary condition using a custom minimum contrast ratio that matches actual color contrast values. This clearly demonstrates the behavioral difference between > and >= and validates edge cases around the 4.5:1 threshold.

The test suite documents specific contrast ratios for real-world color examples and ensures regression prevention for future updates. I included several test cases from my own manuel tests covering various scenarios including colors below, at, and above the 4.5:1 threshold, edge cases with very light and very dark backgrounds, custom minimum contrast ratios, RGBA color handling, and luminance and contrast ratio calculation accuracy.

Reflection on practical impact

It's worth reflecting on whether this change is actually useful given the investigation results. The reality is that no real-world colors in Bootstrap's current implementation are affected by this fix - the luminance calculation uses discrete integer RGB values, so no color produces exactly 4.5:1 contrast ratio.

I don't have a strong opinion regarding the merge of this PR.

I'd say this change could still be reasonable to respect the standards compliance (the "at least 4.5:1") and for future-proofing if Bootstrap ever changes its luminance calculation, or if PRs with new Sass implementations such as https://github.com/twbs/bootstrap/pull/41512/files#diff-de6111a37eb67d027961043ce738e80a3ac4ad61a6e7704d35cb3168369cba01 produce slightly different colors.

It remains a kind of theoretical fix, more of a preventive fix that aligns Bootstrap's implementation with accessibility standards and provides peace of mind that the code correctly handles edge cases, even if they don't currently exist in practice.

Warning

While I'm not an accessibility expert, I've done my best to approach this carefully and welcome feedback from others more experienced in this area. Pinging @patrickhlauke, @ffoodd, @mdo for double-check, and most of all, opinions :)

@patrickhlauke
Copy link
Member

such a long description/investigation/etc... i was ready to approve this after the first sentence ;)

@julien-deramond
Copy link
Member Author

julien-deramond commented Jul 2, 2025

such a long description/investigation/etc... i was ready to approve this after the first sentence ;)

My bad 😬, I was detailing everything along the way mostly to help myself understand the topic better.
Thanks for the quick review :)

Copy link
Member

@ffoodd ffoodd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed 💜 Thanks for the tests, that's really handful !

@julien-deramond julien-deramond merged commit b02d5ed into main Jul 2, 2025
14 checks passed
@julien-deramond julien-deramond deleted the main-jd-fix-color-contrast-function branch July 2, 2025 20:30
mergify bot added a commit to ArcadeData/arcadedb that referenced this pull request Sep 8, 2025
… with 2 updates [skip ci]

Bumps the security-critical group in /studio with 2 updates: [bootstrap](https://github.com/twbs/bootstrap) and [sweetalert2](https://github.com/sweetalert2/sweetalert2).
Updates `bootstrap` from 5.3.7 to 5.3.8
Release notes

*Sourced from [bootstrap's releases](https://github.com/twbs/bootstrap/releases).*

> v5.3.8
> ------
>
> What's Changed
> --------------
>
> * Streamline release prep script by [`@​mdo`](https://github.com/mdo) in [twbs/bootstrap#41539](https://redirect.github.com/twbs/bootstrap/pull/41539)
> * Docs: restore local dev port to 9001 by [`@​chalin`](https://github.com/chalin) in [twbs/bootstrap#41545](https://redirect.github.com/twbs/bootstrap/pull/41545)
> * Docs: use Example shortcode instead of divs with only `.bd-example` class by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41556](https://redirect.github.com/twbs/bootstrap/pull/41556)
> * Docs: fix scss autorecompile in dev mode by [`@​MaxLardenois`](https://github.com/MaxLardenois) in [twbs/bootstrap#41574](https://redirect.github.com/twbs/bootstrap/pull/41574)
> * Fix `color-contrast()` function for WCAG 2.1 compliance by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41585](https://redirect.github.com/twbs/bootstrap/pull/41585)
> * OSSF Scorecard by [`@​mdo`](https://github.com/mdo) in [twbs/bootstrap#41571](https://redirect.github.com/twbs/bootstrap/pull/41571)
> * Workflows: Use SHA-1 for third-party actions by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41595](https://redirect.github.com/twbs/bootstrap/pull/41595)
> * Docs: unminify downloadable example HTML files by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41637](https://redirect.github.com/twbs/bootstrap/pull/41637)
> * Docs: Add tooltips to buttons when `<Example>` is used, not just `<Code>` by [`@​louismaximepiton`](https://github.com/louismaximepiton) in [twbs/bootstrap#41582](https://redirect.github.com/twbs/bootstrap/pull/41582)
> * Set cursor pointer on input search cancel button by [`@​mdo`](https://github.com/mdo) in [twbs/bootstrap#41639](https://redirect.github.com/twbs/bootstrap/pull/41639)
> * CSS: Prevent spinner distortion in flex containers with multiline content by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41654](https://redirect.github.com/twbs/bootstrap/pull/41654)
> * Migrate MyGet script to GH actions by [`@​supergibbs`](https://github.com/supergibbs) in [twbs/bootstrap#41583](https://redirect.github.com/twbs/bootstrap/pull/41583)
> * Revert "Attempt to return focus explicitly to dropdown trigger" by [`@​mdo`](https://github.com/mdo) in [twbs/bootstrap#41668](https://redirect.github.com/twbs/bootstrap/pull/41668)
> * docs: Minor range example code optimization by [`@​coliff`](https://github.com/coliff) in [twbs/bootstrap#41665](https://redirect.github.com/twbs/bootstrap/pull/41665)
> * Remove Themes from docs by [`@​mdo`](https://github.com/mdo) in [twbs/bootstrap#41671](https://redirect.github.com/twbs/bootstrap/pull/41671)
> * Release v5.3.8 by [`@​mdo`](https://github.com/mdo) in [twbs/bootstrap#41669](https://redirect.github.com/twbs/bootstrap/pull/41669)
>
> Dependencies
> ------------
>
> * Build(deps-dev): Bump the development-dependencies group with 3 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41540](https://redirect.github.com/twbs/bootstrap/pull/41540)
> * Build(deps-dev): Bump the development-dependencies group with 2 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41544](https://redirect.github.com/twbs/bootstrap/pull/41544)
> * Build(deps-dev): Bump stylelint-config-twbs-bootstrap from 16.0.0 to 16.1.0 by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41546](https://redirect.github.com/twbs/bootstrap/pull/41546)
> * Build(deps-dev): Bump the development-dependencies group with 5 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41552](https://redirect.github.com/twbs/bootstrap/pull/41552)
> * Build(deps-dev): Bump the development-dependencies group with 4 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41560](https://redirect.github.com/twbs/bootstrap/pull/41560)
> * Build(deps-dev): Bump the development-dependencies group with 3 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41566](https://redirect.github.com/twbs/bootstrap/pull/41566)
> * Build(deps): Bump actions/upload-artifact from 4.6.1 to 4.6.2 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41594](https://redirect.github.com/twbs/bootstrap/pull/41594)
> * Build(deps-dev): Bump the development-dependencies group with 4 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41599](https://redirect.github.com/twbs/bootstrap/pull/41599)
> * Build(deps-dev): Bump the development-dependencies group with 2 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41609](https://redirect.github.com/twbs/bootstrap/pull/41609)
> * Build(deps): Bump github/codeql-action from 3.29.2 to 3.29.3 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41611](https://redirect.github.com/twbs/bootstrap/pull/41611)
> * Build(deps): Bump streetsidesoftware/cspell-action from 7.1.1 to 7.1.2 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41610](https://redirect.github.com/twbs/bootstrap/pull/41610)
> * Build(deps-dev): Bump the development-dependencies group with 4 updates by [`@​julien-deramond`](https://github.com/julien-deramond) in [twbs/bootstrap#41621](https://redirect.github.com/twbs/bootstrap/pull/41621)
> * Build(deps): Bump streetsidesoftware/cspell-action from 7.1.2 to 7.2.0 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41625](https://redirect.github.com/twbs/bootstrap/pull/41625)
> * Build(deps): Bump actions-cool/issues-helper from 3.6.0 to 3.6.2 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41623](https://redirect.github.com/twbs/bootstrap/pull/41623)
> * Build(deps): Bump github/codeql-action from 3.29.3 to 3.29.4 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41624](https://redirect.github.com/twbs/bootstrap/pull/41624)
> * Build(deps-dev): Bump the development-dependencies group across 1 directory with 3 updates by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41626](https://redirect.github.com/twbs/bootstrap/pull/41626)
> * Build(deps): Bump github/codeql-action from 3.29.4 to 3.29.5 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41640](https://redirect.github.com/twbs/bootstrap/pull/41640)
> * Build(deps): Bump tmp from 0.2.3 to 0.2.4 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41649](https://redirect.github.com/twbs/bootstrap/pull/41649)
> * Build(deps): Bump github/codeql-action from 3.29.7 to 3.29.8 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41657](https://redirect.github.com/twbs/bootstrap/pull/41657)
> * Build(deps): Bump actions/checkout from 4.2.2 to 5.0.0 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41655](https://redirect.github.com/twbs/bootstrap/pull/41655)
> * Build(deps): Bump github/codeql-action from 3.29.8 to 3.29.10 by [`@​dependabot`](https://github.com/dependabot)[bot] in [twbs/bootstrap#41664](https://redirect.github.com/twbs/bootstrap/pull/41664)
>
> New Contributors
> ----------------
>
> * [`@​chalin`](https://github.com/chalin) made their first contribution in [twbs/bootstrap#41545](https://redirect.github.com/twbs/bootstrap/pull/41545)
>
> **Full Changelog**: <twbs/bootstrap@v5.3.7...v5.3.8>


Commits

* [`25aa8cc`](twbs/bootstrap@25aa8cc) Release v5.3.8 ([#41669](https://redirect.github.com/twbs/bootstrap/issues/41669))
* [`122bff5`](twbs/bootstrap@122bff5) Remove Themes from docs ([#41671](https://redirect.github.com/twbs/bootstrap/issues/41671))
* [`320f713`](twbs/bootstrap@320f713) docs: Minor range example code optimization ([#41665](https://redirect.github.com/twbs/bootstrap/issues/41665))
* [`ac5f51c`](twbs/bootstrap@ac5f51c) Revert "Attempt to return focus explicitly to dropdown trigger ([#41365](https://redirect.github.com/twbs/bootstrap/issues/41365))" ([#41](https://redirect.github.com/twbs/bootstrap/issues/41)...
* [`4bd8b6c`](twbs/bootstrap@4bd8b6c) Migrate MyGet script to GH actions ([#41583](https://redirect.github.com/twbs/bootstrap/issues/41583))
* [`f50f38b`](twbs/bootstrap@f50f38b) CSS: Fix spinner deformation in flex boxes when content is multiline ([#41654](https://redirect.github.com/twbs/bootstrap/issues/41654))
* [`47c75b8`](twbs/bootstrap@47c75b8) Set cursor pointer on input search cancel button ([#41639](https://redirect.github.com/twbs/bootstrap/issues/41639))
* [`26c86ba`](twbs/bootstrap@26c86ba) Build(deps): Bump github/codeql-action from 3.29.8 to 3.29.10 ([#41664](https://redirect.github.com/twbs/bootstrap/issues/41664))
* [`099b02b`](twbs/bootstrap@099b02b) Build(deps-dev): Bump rollup from 4.46.2 to 4.46.3
* [`4b8a2c9`](twbs/bootstrap@4b8a2c9) Build(deps-dev): bump dependencies
* Additional commits viewable in [compare view](twbs/bootstrap@v5.3.7...v5.3.8)
  
Updates `sweetalert2` from 11.22.4 to 11.23.0
Release notes

*Sourced from [sweetalert2's releases](https://github.com/sweetalert2/sweetalert2/releases).*

> v11.23.0
> --------
>
> [11.23.0](sweetalert2/sweetalert2@v11.22.4...v11.23.0) (2025-09-04)
> ==============================================================================================
>
> ### Features
>
> * replace deprecated word-wrap with overflow-wrap ([2667a49](sweetalert2/sweetalert2@2667a49))
>
> v11.22.5
> --------
>
> No release notes provided.


Changelog

*Sourced from [sweetalert2's changelog](https://github.com/sweetalert2/sweetalert2/blob/main/CHANGELOG.md).*

> [11.23.0](sweetalert2/sweetalert2@v11.22.4...v11.23.0) (2025-09-04)
> ==============================================================================================
>
> ### Features
>
> * replace deprecated word-wrap with overflow-wrap ([2667a49](sweetalert2/sweetalert2@2667a49))


Commits

* [`fc465a4`](sweetalert2/sweetalert2@fc465a4) chore(release): 11.23.0 [skip ci]
* [`2667a49`](sweetalert2/sweetalert2@2667a49) feat: replace deprecated word-wrap with overflow-wrap
* [`cf4b189`](sweetalert2/sweetalert2@cf4b189) chore: bump yarn.lock
* [`b27bacf`](sweetalert2/sweetalert2@b27bacf) chore: add venuslovedolls to sponsors
* [`9dc7802`](sweetalert2/sweetalert2@9dc7802) chore(deps): update dependency cypress to v15 ([#2857](https://redirect.github.com/sweetalert2/sweetalert2/issues/2857))
* [`f824237`](sweetalert2/sweetalert2@f824237) chore: remove code comment that got missed in PR [#2847](https://redirect.github.com/sweetalert2/sweetalert2/issues/2847) ([#2854](https://redirect.github.com/sweetalert2/sweetalert2/issues/2854))
* [`2af063c`](sweetalert2/sweetalert2@2af063c) chore(deps): update dependency eslint-plugin-jsdoc to v54 ([#2851](https://redirect.github.com/sweetalert2/sweetalert2/issues/2851))
* [`80d573e`](sweetalert2/sweetalert2@80d573e) chore(deps): update dependency eslint-plugin-jsdoc to v53 ([#2850](https://redirect.github.com/sweetalert2/sweetalert2/issues/2850))
* [`4a490d5`](sweetalert2/sweetalert2@4a490d5) chore(deps): update actions/checkout action to v5 ([#2849](https://redirect.github.com/sweetalert2/sweetalert2/issues/2849))
* [`47b4da4`](sweetalert2/sweetalert2@47b4da4) Update SPONSORS.md
* See full diff in [compare view](sweetalert2/sweetalert2@v11.22.4...v11.23.0)
  
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
  
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show  ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore  major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore  minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore  ` will remove the ignore condition of the specified dependency and ignore conditions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Incorrect comparison in color-contrast function (should be >= instead of >)
3 participants