I\'m looking for a concise way to compute the color contrast ratio between two UIColor
instances in Swift. I\'ve found examples that are close but are overly compli
If building for WatchOS
where CoreImage
is not available or for whatever reason you do not want to rely on CoreImage
and therefore CIColor
is unavailable, replace @Mobile Dan's luminance
function with:
private func luminance() -> CGFloat {
// https://www.w3.org/TR/WCAG20-TECHS/G18.html#G18-tests
func adjust(colorComponent: CGFloat) -> CGFloat {
return (colorComponent < 0.03928) ? (colorComponent / 12.92) : pow((colorComponent + 0.055) / 1.055, 2.4)
}
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return 0.2126 * adjust(colorComponent: red)
+ 0.7152 * adjust(colorComponent: green)
+ 0.0722 * adjust(colorComponent: blue)
}
UIColor
extension with contrast ratio and luminanceThe following UIColor
extension includes a static and instance contrast ratio method. A bonus luminance method is included since it is used by the static contrastRatio(between:and:)
method.
import UIKit
extension UIColor {
static func contrastRatio(between color1: UIColor, and color2: UIColor) -> CGFloat {
// https://www.w3.org/TR/WCAG20-TECHS/G18.html#G18-tests
let luminance1 = color1.luminance()
let luminance2 = color2.luminance()
let luminanceDarker = min(luminance1, luminance2)
let luminanceLighter = max(luminance1, luminance2)
return (luminanceLighter + 0.05) / (luminanceDarker + 0.05)
}
func contrastRatio(with color: UIColor) -> CGFloat {
return UIColor.contrastRatio(between: self, and: color)
}
func luminance() -> CGFloat {
// https://www.w3.org/TR/WCAG20-TECHS/G18.html#G18-tests
let ciColor = CIColor(color: self)
func adjust(colorComponent: CGFloat) -> CGFloat {
return (colorComponent < 0.04045) ? (colorComponent / 12.92) : pow((colorComponent + 0.055) / 1.055, 2.4)
}
return 0.2126 * adjust(colorComponent: ciColor.red) + 0.7152 * adjust(colorComponent: ciColor.green) + 0.0722 * adjust(colorComponent: ciColor.blue)
}
}
// static method
let contrastRatio1 = UIColor.contrastRatio(between: UIColor.black, and: UIColor.white)
print(contrastRatio1) // 21.0
// instance method
let contrastRatio2 = UIColor.black.contrastRatio(with: UIColor.white)
print(contrastRatio2) // 21.0
Following these links: https://www.w3.org/TR/css-color-4/#predefined https://github.com/dequelabs/axe-core/issues/1629#issuecomment-509880306
For predefinite colorspace (like in iOS see this https://developer.apple.com/videos/play/wwdc2016/712/) and also in general the correct THRESHOLD value is 0.04045 and not 0.03928.