├── ColorContrast.playground
├── Contents.swift
├── contents.xcplayground
└── timeline.xctimeline
└── README.md
/ColorContrast.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIColor {
4 | static let minContrastRatio: CGFloat = 7.0
5 |
6 | /// Calculates the brightness of the receiver
7 | /// Returns nil if the color space of the receiver is not compatible
8 | func brightnessValue() -> CGFloat? {
9 | var h: CGFloat = 0
10 | var s: CGFloat = 0
11 | var b: CGFloat = 0
12 | var a: CGFloat = 0
13 |
14 | if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
15 | return b
16 | }
17 |
18 | return nil
19 | }
20 |
21 | /// Returns an updated version of the receiver with an adjusted brightness component
22 | /// that ensures the receiver and otherColor meet the minContrastRatio
23 | func adjustedColorForBestContrast(withColor otherColor: UIColor) -> UIColor {
24 | guard let contrastRatio = self.contrastRatio(withColor: otherColor), contrastRatio < UIColor.minContrastRatio else {
25 | return self
26 | }
27 |
28 | guard let adjustedBrightness =
29 | self.brightnessToMeetMinContrast(withColor: otherColor) else {
30 | return self
31 | }
32 | return self.adjustedColor(withNewBrightness: adjustedBrightness)
33 | }
34 |
35 | /// Formula for calculating the contrast ratio of two colors is:
36 | /// (b1 + 0.05) / (b2 + 0.05)
37 | /// where b1 and b2 are the brightness values of two colors, and b1 > b2
38 | func contrastRatio(withColor otherColor: UIColor) -> CGFloat? {
39 | guard let b1 = self.brightnessValue(), let b2 = otherColor.brightnessValue() else {
40 | return nil
41 | }
42 |
43 | if b1 > b2 {
44 | return (b1 + 0.05) / (b2 + 0.05)
45 | } else {
46 | return (b2 + 0.05) / (b1 + 0.05)
47 | }
48 | }
49 |
50 | /// Returns the brightness value needed to adjust the receiver color to meet the minContrastRatio
51 | /// when compared to otherColor
52 | func brightnessToMeetMinContrast(withColor otherColor: UIColor) -> CGFloat? {
53 | guard let b1 = self.brightnessValue(), let b2 = otherColor.brightnessValue() else {
54 | return nil
55 | }
56 |
57 | if b1 > b2 {
58 | return UIColor.minContrastRatio * (b2 + 0.05) - 0.05
59 | } else {
60 | return ((b2 + 0.05) / UIColor.minContrastRatio) + 0.05
61 | }
62 | }
63 |
64 | /// Returns a copy of the receiver with the brightness component changed to be
65 | /// the passed in brightness value
66 | func adjustedColor(withNewBrightness brightness: CGFloat) -> UIColor {
67 | var h: CGFloat = 0
68 | var s: CGFloat = 0
69 | var b: CGFloat = 0
70 | var a: CGFloat = 0
71 | if self.getHue(&h, saturation: &s, brightness: &b, alpha: &a) {
72 | return UIColor(hue: h, saturation: s, brightness: brightness, alpha: a)
73 | }
74 | return self;
75 | }
76 | }
77 |
78 | // Test the code!
79 | // color1 represents the foreground color that we will adjust if the contrast ratio is not high enough between color1 and color2
80 | // color2 is the background color that will only be compared to and not changed
81 |
82 | // Check contrast of black on top of white. Adjust the black color if the contrast is < 7
83 | var color1 = UIColor.black
84 | var color2 = UIColor.white
85 | color1.contrastRatio(withColor: color2)
86 | color1.adjustedColorForBestContrast(withColor: color2) // No adjustment needed since contrast is 21, which is > 7
87 |
88 |
89 | // Check contrast of yellow on top of white. Adjust the yellow color if the contrast is < 7
90 | color1 = UIColor.yellow
91 | color2 = UIColor.white
92 | color1.adjustedColorForBestContrast(withColor: color2) // Darken the yellow so the contrast is 7
93 |
94 |
95 | // Check contrast of white on top of white. Adjust the foreground white color if the contrast is < 7
96 | color1 = UIColor.white
97 | color2 = UIColor.white
98 | color1.adjustedColorForBestContrast(withColor: color2) // Darken the foreground white so the contrast is 7
99 |
100 |
101 | // Check contrast of a dark purple on top of black. Adjust the foreground purple color if the contrast is < 7
102 | color1 = UIColor(hue: 0.8, saturation: 1, brightness: 0.15, alpha: 1)
103 | color2 = UIColor.black
104 | color1.adjustedColorForBestContrast(withColor: color2) // Lighten the foreground color so the contrast is 7
105 |
--------------------------------------------------------------------------------
/ColorContrast.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ColorContrast.playground/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
9 |
10 |
14 |
15 |
19 |
20 |
24 |
25 |
29 |
30 |
34 |
35 |
39 |
40 |
44 |
45 |
49 |
50 |
54 |
55 |
59 |
60 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ColorContrast
2 | UIColor extension in Swift to calculate brightness, color contrast, and more.
3 |
4 | Simply download the ColorContrast Swift Playground and run it! There are colors tests at the bottom of the file to test out the code.
5 |
--------------------------------------------------------------------------------