Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 109 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: CI

on:
push:
branches: [ main, master, develop ]
pull_request:
branches: [ main, master, develop ]

jobs:
tests:
name: Tests - PHP ${{ matrix.php-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3']

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: mbstring
coverage: xdebug
tools: composer:v2

- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction

- name: Run test suite
run: vendor/bin/phpunit --coverage-text

code-style:
name: Code Style
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: mbstring
tools: composer:v2, cs2pr

- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction

- name: Check code style
run: vendor/bin/phpcs -q --report=checkstyle | cs2pr

static-analysis:
name: Static Analysis
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: mbstring
tools: composer:v2

- name: Get composer cache directory
id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
restore-keys: ${{ runner.os }}-composer-

- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-interaction

- name: Run PHPStan
run: vendor/bin/phpstan analyse --error-format=github
251 changes: 201 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,64 +1,215 @@
# ColorContrast
Small library to find valid color combinations for a given contrast threshold. The contrast calculation algorithm is based on the WCAG 2.0.
# Color Contrast PHP

<p align="center">
<a href="https://travis-ci.org/davidgorges/color-contrast-php"><img src="https://travis-ci.org/davidgorges/color-contrast-php.svg" alt="Build Status"></a>
<a href="https://packagist.org/packages/davidgorges/color-contrast-php"><img src="https://poser.pugx.org/davidgorges/color-contrast-php/v/stable" alt="Latest Stable Version"></a>
<a href="https://packagist.org/packages/davidgorges/color-contrast-php/stats"><img src="https://poser.pugx.org/davidgorges/color-contrast-php/downloads" alt="Total Downloads"></a>
<a href="https://choosealicense.com/licenses/mit/"><img src="https://poser.pugx.org/davidgorges/color-contrast-php/license" alt="License"></a>
<a href="https://github.com/davidgorges/color-contrast-php"><img src="https://img.shields.io/badge/PHPStan-enabled-brightgreen.svg?style=flat" alt="PHPStan Enabled"></a>
</p>
[![CI](https://github.com/davidgorges/color-contrast-php/workflows/CI/badge.svg)](https://github.com/davidgorges/color-contrast-php/actions)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![PHP Version](https://img.shields.io/badge/php-%3E%3D8.1-blue.svg)](https://www.php.net/)
[![PHPStan](https://img.shields.io/badge/PHPStan-max%20level-brightgreen.svg)](https://phpstan.org/)

------
A modern PHP 8.1+ library for calculating color contrast ratios and finding accessible color combinations according to WCAG 2.0 guidelines.

## Install
## Features

- **Zero dependencies** (except dev dependencies for testing and code quality)
- **Modern PHP 8.1+** with strict types, readonly classes, and constructor property promotion
- **WCAG 2.0 compliant** contrast ratio calculations
- **Comprehensive test suite** with 100+ test cases
- **PHPStan level max** static analysis
- **PSR-12 compliant** code style
- **Fully typed** for better IDE support and type safety

## Requirements

- PHP 8.1 or higher

## Installation

Install via Composer:

Using composer:
```bash
composer require davidgorges/color-contrast
composer require davidgorges/color-contrast-php
```

## Usage
````php
use ColorContrast\ColorContrast;

/* ... */

$contrast = new ColorContrast();
$contrast->addColors(0xff0000, 0x002200, 0x0022ff, 0xffffff);
$combinations = $contrast->getCombinations(ColorContrast::MIN_CONTRAST_AAA);
foreach ($combinations as $combination) {
printf("#%s on the Background color #%s has a contrast value of %f \n", $combination->getForeground(), $combination->getBackground(), $combination->getContrast());
}
````

this would output:
````
#FFFFFF on the Background color #002200 has a contrast value of 17.949476
#FFFFFF on the Background color #0022FF has a contrast value of 8.033817
#002200 on the Background color #FFFFFF has a contrast value of 17.949476
#0022FF on the Background color #FFFFFF has a contrast value of 8.033817
````

### Dark or Light Complimentary Color

````php
$contrast = new ColorContrast();

// imagine having a red background and you need to know if its better
// to display a white or black text on top if it
$complimentary = $contrast->complimentaryTheme('#d80000'); // returns ColorContrast::DARK to indicate you should use a dark color on this background

if($complimentary == ColorContrast::LIGHT) {
// Use a light font
} else {
// use a dark font

### Basic Usage

```php
use ColorContrast\ColorContrast;

$contrast = new ColorContrast();

// Add colors in various formats
$contrast->addColors('#FF0000', '#FFFFFF', '00FF00', 0x0000FF);

// Get all color combinations with their contrast ratios
$combinations = $contrast->getCombinations();

foreach ($combinations as $combination) {
echo sprintf(
"Foreground: %s, Background: %s, Contrast: %.2f\n",
$combination->getForeground()->toHexString(),
$combination->getBackground()->toHexString(),
$combination->getContrast()
);
}
```

### WCAG 2.0 Compliance

Filter combinations by WCAG 2.0 contrast requirements:

```php
use ColorContrast\ColorContrast;

$contrast = new ColorContrast();
$contrast->addColors('#FF0000', '#FFFFFF', '#000000', '#808080');

// Get combinations meeting WCAG AA standards (4.5:1)
$aaCombinations = $contrast->getCombinations(ColorContrast::MIN_CONTRAST_AA);

// Get combinations meeting WCAG AAA standards (7:1)
$aaaCombinations = $contrast->getCombinations(ColorContrast::MIN_CONTRAST_AAA);

// For large text (AA: 3:1, AAA: 4.5:1)
$aaLargeCombinations = $contrast->getCombinations(ColorContrast::MIN_CONTRAST_AA_LARGE);
$aaaLargeCombinations = $contrast->getCombinations(ColorContrast::MIN_CONTRAST_AAA_LARGE);
```

### Complementary Theme Detection

Determine whether to use light or dark text on a background:

```php
use ColorContrast\ColorContrast;

$contrast = new ColorContrast();

// Returns ColorContrast::DARK for light backgrounds
$theme = $contrast->complimentaryTheme('#FFFFFF');
echo $theme; // 'dark'

// Returns ColorContrast::LIGHT for dark backgrounds
$theme = $contrast->complimentaryTheme('#000000');
echo $theme; // 'light'

// Custom threshold (default is 128)
$theme = $contrast->complimentaryTheme('#808080', 100);
```

### Working with Color Objects

```php
use ColorContrast\Color;

// Create colors
$red = new Color(255, 0, 0);
$blue = Color::fromHex(0x0000FF);
$green = Color::fromHexString('#00FF00');
$yellow = Color::fromHexString('FFFF00'); // # is optional

// Short hex notation (e.g., #F00 -> #FF0000)
$shortRed = Color::fromHexString('F00');

// Access RGB values
echo $red->getRed(); // 255
echo $red->getGreen(); // 0
echo $red->getBlue(); // 0

// Convert to hex
echo $red->toHex(); // 16711680 (0xFF0000)
echo $red->toHexString(); // '#FF0000'
echo $red->toHexString(false); // 'FF0000'
```

### Custom Contrast Algorithms

Implement your own contrast calculation algorithm:

```php
use ColorContrast\ColorContrast;
use ColorContrast\ContrastAlgorithm\ContrastAlgorithmInterface;
use ColorContrast\Color;

class CustomAlgorithm implements ContrastAlgorithmInterface
{
public function calculate(Color $foreground, Color $background): float
{
// Your custom contrast calculation
return 5.0;
}
````
}

$contrast = new ColorContrast(new CustomAlgorithm());
// or
$contrast->setAlgorithm(new CustomAlgorithm());
```

## WCAG 2.0 Standards

The library includes constants for WCAG 2.0 contrast ratios:

- `ColorContrast::MIN_CONTRAST_AA` (4.5) - Normal text AA
- `ColorContrast::MIN_CONTRAST_AAA` (7.0) - Normal text AAA
- `ColorContrast::MIN_CONTRAST_AA_LARGE` (3.0) - Large text AA
- `ColorContrast::MIN_CONTRAST_AAA_LARGE` (4.5) - Large text AAA

Large text is defined as 18pt+ or 14pt+ bold.

## Development

### Install Dependencies

```bash
composer install
```

### Run Tests

```bash
composer test
# or
vendor/bin/phpunit
```

### Code Style

Check code style with PHP_CodeSniffer (PSR-12):

```bash
composer phpcs
# or
vendor/bin/phpcs
```

### Static Analysis

Run PHPStan at max level:

```bash
composer phpstan
# or
vendor/bin/phpstan analyse
```

### Run All Checks

```bash
composer check
```

## Contributing

Contributions are welcome! Please ensure:

1. All tests pass
2. Code follows PSR-12 standards
3. PHPStan max level passes
4. Add tests for new features

## Thanks

* [Calculating Color Contrast with PHP](http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php) by Andreas Gohr
* [jxnblk/colorable](https://github.com/jxnblk/colorable) JavaScript Library that inspired ColorContrast
- [Calculating Color Contrast with PHP](http://www.splitbrain.org/blog/2008-09/18-calculating_color_contrast_with_php) by Andreas Gohr
- [jxnblk/colorable](https://github.com/jxnblk/colorable) JavaScript Library that inspired ColorContrast

## License
The MIT License (MIT)
Expand Down
Loading
Loading