sass-apca 0.0.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/dependabot.yml +11 -0
- package/LICENSE +21 -21
- package/README.md +51 -2
- package/apca.scss +92 -83
- package/package.json +1 -1
- package/test.scss +35 -35
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2023 Philipp Gfeller
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Philipp Gfeller
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,2 +1,51 @@
|
|
|
1
|
-
# sass-apca
|
|
2
|
-
Sass implementation of the [Accessible Perceptual Contrast Algorithm (APCA)](https://git.apcacontrast.com/) for the WCAG 3.0 specification.
|
|
1
|
+
# sass-apca
|
|
2
|
+
Sass implementation of the [Accessible Perceptual Contrast Algorithm (APCA)](https://git.apcacontrast.com/) for the WCAG 3.0 specification.
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
|
|
6
|
+
These scss functions are compatible with [sass (dart sass)](https://www.npmjs.com/package/sass) v1.33 and up.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install sass-apca
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Contrast
|
|
15
|
+
|
|
16
|
+
APCA reports lightness contrast as an L<sup>c</sup> value from L<sup>c</sup> 0 to L<sup>c</sup> 106 for dark text on a light background, and L<sup>c</sup> 0 to L<sup>c</sup> -108 for light text on a dark background (dark mode). The minus sign merely indicates negative contrast, which means light text on a dark background[^1].
|
|
17
|
+
|
|
18
|
+
| Parameter | Type | Description |
|
|
19
|
+
|:--- |:--- |:--- |
|
|
20
|
+
| $text-color | [Sass Color](https://sass-lang.com/documentation/values/colors) | Color of the text |
|
|
21
|
+
| $background-color | [Sass Color](https://sass-lang.com/documentation/values/colors) | Color of the background |
|
|
22
|
+
|
|
23
|
+
```scss
|
|
24
|
+
@use 'sass-apca/apca';
|
|
25
|
+
|
|
26
|
+
$contrast-black-on-white: apca.contrast(black, white); // 106.0406668287
|
|
27
|
+
$contrast-white-on-black: apca.contrast(white, black); // -107.8847261151
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## About
|
|
31
|
+
These general levels are appropriate for use by themselves, without the need to reference a lookup table. APCA reports contrast as an L<sup>c</sup> value (lightness contrast) from L<sup>c</sup> 0 to L<sup>c</sup> 105+. For accessibility, consider L<sup>c</sup> 15 the point of invisibility for many users, and L<sup>c</sup> 90 is preferred for body text[^2].
|
|
32
|
+
|
|
33
|
+
- **L<sup>c</sup> 90** • Preferred level for fluent text and columns of body text with a font no smaller than 14px/weight 400 (normal).
|
|
34
|
+
- **L<sup>c</sup> 75** • The minimum level for columns of body text with a font no smaller than 18px/400. L<sup>c</sup> 75 should be considered a minimum for text where readability is important.
|
|
35
|
+
- **L<sup>c</sup> 60** • The minimum level recommended for content text that is not body, column, or block text. In other words, text you want people to read. The minimums: 24px normal weight (400) or 16px/700 (bold). These values based on the reference font Helvetica.
|
|
36
|
+
- **L<sup>c</sup> 45** • The minimum for larger, heavier text (36px normal weight or 24px bold) such as headlines. This is also the minimum for pictograms with fine details.
|
|
37
|
+
- **L<sup>c</sup> 30** • The absolute minimum for any text not listed above. This includes placeholder text and disabled element text. This is also the minimum for large/solid semantic & understandable non-text elements.
|
|
38
|
+
- **L<sup>c</sup> 15** • The absolute minimum for any non-text that needs to be discernible and differentiable, and is no less than 6px in its smallest dimension. This may include disabled large buttons. Designers should treat anything below this level as invisible, as it will not be visible for many users. This minimum level should be avoided for any items important to the use, understanding, or interaction of the site.
|
|
39
|
+
|
|
40
|
+
## Roadmap
|
|
41
|
+
- Polarity function for figuring out if light or dark text has a higher contrast on any given background
|
|
42
|
+
- Compliance check for getting the current level of compliance of a given contrast ratio
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
## License
|
|
47
|
+
|
|
48
|
+
Code published in this repository licensed under the [MIT license](https://github.com/gfellerph/sass-apca/blob/main/LICENSE).
|
|
49
|
+
|
|
50
|
+
[^1]: APCA contrast calculator (https://www.myndex.com/APCA/)
|
|
51
|
+
[^2]: Why APCA (https://git.apcacontrast.com/documentation/WhyAPCA#use-case-ranges)
|
package/apca.scss
CHANGED
|
@@ -1,83 +1,92 @@
|
|
|
1
|
-
@use "sass:math";
|
|
2
|
-
@use "sass:color";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
$
|
|
15
|
-
$
|
|
16
|
-
$
|
|
17
|
-
$
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
$
|
|
22
|
-
$
|
|
23
|
-
$
|
|
24
|
-
$
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
$
|
|
29
|
-
$
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
$
|
|
43
|
-
$
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
$
|
|
47
|
-
$
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
$
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
1
|
+
@use "sass:math";
|
|
2
|
+
@use "sass:color";
|
|
3
|
+
@use "sass:meta";
|
|
4
|
+
|
|
5
|
+
// -------------------
|
|
6
|
+
//
|
|
7
|
+
// Sass APCA
|
|
8
|
+
//
|
|
9
|
+
// Implementation of the [Accessible Perceptual Contrast Algorithm (APCA)](https://git.apcacontrast.com/) for the WCAG 3.0 specification.
|
|
10
|
+
//
|
|
11
|
+
// -------------------
|
|
12
|
+
|
|
13
|
+
// Powercurve exponents
|
|
14
|
+
$_Strc: 2.4;
|
|
15
|
+
$_Ntx: 0.57;
|
|
16
|
+
$_Nbg: 0.56;
|
|
17
|
+
$_Rtx: 0.62;
|
|
18
|
+
$_Rbg: 0.65;
|
|
19
|
+
|
|
20
|
+
// Clamps and scalers
|
|
21
|
+
$_Bclip: 1.414;
|
|
22
|
+
$_Bthrsh: 0.022;
|
|
23
|
+
$_Wscale: 1.14;
|
|
24
|
+
$_Woffset: 0.027;
|
|
25
|
+
$_Wclamp: 0.1;
|
|
26
|
+
|
|
27
|
+
// Multipliers
|
|
28
|
+
$_redMultiplier: 0.2126729;
|
|
29
|
+
$_greenMultiplier: 0.7151522;
|
|
30
|
+
$_blueMultiplier: 0.072175;
|
|
31
|
+
|
|
32
|
+
@function _luminance($color) {
|
|
33
|
+
// The floating point precision is poor so white would return 1.000001
|
|
34
|
+
@if ($color == white) {
|
|
35
|
+
@return 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@if ($color == black) {
|
|
39
|
+
@return 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
$red: color.red($color);
|
|
43
|
+
$green: color.green($color);
|
|
44
|
+
$blue: color.blue($color);
|
|
45
|
+
|
|
46
|
+
$redLuminance: math.pow($red / 255, $_Strc) * $_redMultiplier;
|
|
47
|
+
$greenLuminance: math.pow($green / 255, $_Strc) * $_greenMultiplier;
|
|
48
|
+
$blueLuminance: math.pow($blue / 255, $_Strc) * $_blueMultiplier;
|
|
49
|
+
|
|
50
|
+
@return $redLuminance + $greenLuminance + $blueLuminance;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@function _softClip($luminance) {
|
|
54
|
+
@if ($luminance < 0) {
|
|
55
|
+
@return 0;
|
|
56
|
+
} @else if ($luminance < $_Bthrsh) {
|
|
57
|
+
@return $luminance + math.pow(($_Bthrsh - $luminance), $_Bclip);
|
|
58
|
+
} @else {
|
|
59
|
+
@return $luminance;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@function _polarity($textColor, $backgroundColor) {
|
|
64
|
+
$Ytxt: _softClip(_luminance($textColor));
|
|
65
|
+
$Ybg: _softClip(_luminance($backgroundColor));
|
|
66
|
+
|
|
67
|
+
@if ($Ybg > $Ytxt) {
|
|
68
|
+
@return (math.pow($Ybg, $_Nbg) - math.pow($Ytxt, $_Ntx)) * $_Wscale;
|
|
69
|
+
} @else {
|
|
70
|
+
@return (math.pow($Ybg, $_Rbg) - math.pow($Ytxt, $_Rtx)) * $_Wscale;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@function contrast($textColor, $backgroundColor) {
|
|
75
|
+
@if (meta.type-of($textColor) != 'color') {
|
|
76
|
+
@error "Type Error: apca.contrast expects a color as first argument but received #{meta.type-of($textColor)}. Please provide a valid color.";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
@if (meta.type-of($backgroundColor) != 'color') {
|
|
80
|
+
@error "Type Error: apca.contrast expects a color as second argument but received #{meta.type-of($backgroundColor)}. Please provide a valid color.";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
$polarity: _polarity($textColor, $backgroundColor);
|
|
84
|
+
|
|
85
|
+
@if (math.abs($polarity) < $_Wclamp) {
|
|
86
|
+
@return 0;
|
|
87
|
+
} @else if ($polarity > 0) {
|
|
88
|
+
@return ($polarity - $_Woffset) * 100;
|
|
89
|
+
} @else {
|
|
90
|
+
@return ($polarity + $_Woffset) * 100;
|
|
91
|
+
}
|
|
92
|
+
}
|
package/package.json
CHANGED
package/test.scss
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
@use './apca';
|
|
2
|
-
|
|
3
|
-
/* tests */
|
|
4
|
-
luminances {
|
|
5
|
-
--red-luminance: apca.luminance(red);
|
|
6
|
-
--green-luminance: apca.luminance(green);
|
|
7
|
-
--blue-luminance: apca.luminance(blue);
|
|
8
|
-
|
|
9
|
-
--yellow-luminance: apca.luminance(yellow);
|
|
10
|
-
--brown-luminance: apca.luminance(brown);
|
|
11
|
-
--violet-luminance: apca.luminance(violet);
|
|
12
|
-
|
|
13
|
-
--white-luminance: apca.luminance(white);
|
|
14
|
-
--black-luminance: apca.luminance(black);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
softClip {
|
|
18
|
-
--black: apca.softClip(apca.luminance(black));
|
|
19
|
-
--white: apca.softClip(apca.luminance(white));
|
|
20
|
-
--brown: apca.softClip(apca.luminance(brown));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
polarity {
|
|
24
|
-
--black-on-white: apca.polarity(black, white);
|
|
25
|
-
--white-on-black: apca.polarity(white, black);
|
|
26
|
-
--red-on-green: apca.polarity(red, green);
|
|
27
|
-
--green-on-red: apca.polarity(green, red);
|
|
28
|
-
--yellow-on-white: apca.polarity(#fc0, white);
|
|
29
|
-
--white-on-yellow: apca.polarity(white, #fc0);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
contrast {
|
|
33
|
-
--black-on-white: apca.contrast(black, white);
|
|
34
|
-
--white-on-black: apca.contrast(white, black);
|
|
35
|
-
}
|
|
1
|
+
@use './apca';
|
|
2
|
+
|
|
3
|
+
/* tests */
|
|
4
|
+
luminances {
|
|
5
|
+
--red-luminance: apca.luminance(red);
|
|
6
|
+
--green-luminance: apca.luminance(green);
|
|
7
|
+
--blue-luminance: apca.luminance(blue);
|
|
8
|
+
|
|
9
|
+
--yellow-luminance: apca.luminance(yellow);
|
|
10
|
+
--brown-luminance: apca.luminance(brown);
|
|
11
|
+
--violet-luminance: apca.luminance(violet);
|
|
12
|
+
|
|
13
|
+
--white-luminance: apca.luminance(white);
|
|
14
|
+
--black-luminance: apca.luminance(black);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
softClip {
|
|
18
|
+
--black: apca.softClip(apca.luminance(black));
|
|
19
|
+
--white: apca.softClip(apca.luminance(white));
|
|
20
|
+
--brown: apca.softClip(apca.luminance(brown));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
polarity {
|
|
24
|
+
--black-on-white: apca.polarity(black, white);
|
|
25
|
+
--white-on-black: apca.polarity(white, black);
|
|
26
|
+
--red-on-green: apca.polarity(red, green);
|
|
27
|
+
--green-on-red: apca.polarity(green, red);
|
|
28
|
+
--yellow-on-white: apca.polarity(#fc0, white);
|
|
29
|
+
--white-on-yellow: apca.polarity(white, #fc0);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
contrast {
|
|
33
|
+
--black-on-white: apca.contrast(black, white);
|
|
34
|
+
--white-on-black: apca.contrast(white, black);
|
|
35
|
+
}
|