Last week, I published a SCSS code to fix inaccurate color contrast calculations. It is a Dart Sass implementation and based on an older implementation. However, for another project I needed yet another implementation that was built with scssphp, which has an own implementation.

And as the website of the project declares:

Note that scssphp is not fully compliant with the Sass specification yet. Sass modules are not implemented yet either.

scssphp website

So there are some missing features in this implementation. And one of them is the Sass module sass:math, which I used in my previous post. Fortunately, the only real functionality we need from this module is the pow function.

I looked for several polyfills, which are able to implement the pow function via plain SCSS code, but they’re either written too easy (e.g. they can only use integers as exponent) or they’re simply not working for me (resulting in a timeout while using them).

Luckily, scssphp comes with a handy feature to register custom functions in PHP, which can be used within SCSS. And as you might know, of course there is an implementation of pow in PHP, which also should make everything performant. You could also just implement the whole color contrast functionality within PHP, but that’s something for another blog post.

To register our own pow function, the code looks like this:

$compiler = new ScssPhp\ScssPhp\Compiler();
$compiler->registerFunction(
	'pow',
	function( $args ) use ( $compiler ) {
		$number = $compiler->assertNumber( $args[0], 'number' );
		$exponent = $compiler->assertNumber( $args[1], 'exponent' );
		$number->assertNoUnits( 'number' );
		$exponent->assertNoUnits( 'exponent' );
		
		return pow( $number->getDimension(), $exponent->getDimension() );
	},
	[ 'number', 'exponent' ]
);
Code language: PHP (php)

And now we can use it as pow() inside of our SCSS:

@function de-gamma($n) { 
	@if $n <= 0.04045 {
		@return $n / 12.92;
	}
	@else {
		@return pow((($n + 0.055)/1.055),2.4); 
	}
 }

@function re-gamma($n) { 
	@if $n <= 0.0031308 { 
		@return $n * 12.92; 
	}
	@else { 
		@return 1.055 * pow($n,1/2.4) - 0.055;
	}
 }

// sRGB BT-709 BRIGHTNESS
@function brightness($c) {
	$rlin: de-gamma(red($c) / 255);
	$glin: de-gamma(green($c) / 255);
	$blin: de-gamma(blue($c) / 255);
	
	@return re-gamma(0.2126 * $rlin + 0.7152 * $glin + 0.0722 * $blin) * 100;
}

// Compares contrast of a given color to the light/dark arguments and returns whichever is most "contrasty"
@function contrast-color($color, $dark: #000, $light: #fff) {
	@if $color == null {
		@return null;
	}

	@else {
		$color-brightness: brightness($color);
		$light-text-brightness: brightness($light);
		$dark-text-brightness: brightness($dark);

		@return if(abs($color-brightness - $light-text-brightness) > abs($color-brightness - $dark-text-brightness), $light, $dark);
	}
}
Code language: SCSS (scss)

The implementation is pretty similar as the one in my previous post, but without the sass:math module.

Leave a Reply

Your email address will not be published. Required fields are marked *