diff --git a/CHANGELOG.md b/CHANGELOG.md index a92ad218..3cae9f51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ Please also have a look at our ### Fixed +- Don't render `rgb` colors with percentage values using hex notation (#803) - Parse `@font-face` `src` property as comma-delimited list (#790) - Fix type errors in PHP strict mode (#664) - Fix undefined local variable in `CalcFunction::parse()` (#593) diff --git a/src/Value/Color.php b/src/Value/Color.php index 85890393..07f11c34 100644 --- a/src/Value/Color.php +++ b/src/Value/Color.php @@ -225,7 +225,11 @@ public function __toString(): string public function render(OutputFormat $outputFormat): string { // Shorthand RGB color values - if ($outputFormat->getRGBHashNotation() && \implode('', \array_keys($this->aComponents)) === 'rgb') { + if ( + $outputFormat->getRGBHashNotation() + && \implode('', \array_keys($this->aComponents)) === 'rgb' + && $this->allComponentsAreNumbers() + ) { $result = \sprintf( '%02x%02x%02x', $this->aComponents['r']->getSize(), @@ -237,4 +241,19 @@ public function render(OutputFormat $outputFormat): string } return parent::render($outputFormat); } + + /** + * Test whether all color components are absolute numbers (CSS type `number`), not percentages or anything else. + * If any component is not an instance of `Size`, the method will also return `false`. + */ + private function allComponentsAreNumbers(): bool + { + foreach ($this->aComponents as $component) { + if (!$component instanceof Size || $component->getUnit() !== null) { + return false; + } + } + + return true; + } } diff --git a/tests/Unit/Value/ColorTest.php b/tests/Unit/Value/ColorTest.php index 822ba5be..2b533a7f 100644 --- a/tests/Unit/Value/ColorTest.php +++ b/tests/Unit/Value/ColorTest.php @@ -54,6 +54,10 @@ public static function provideValidColorAndExpectedRendering(): array 'rgb(0, 118, 0)', '#007600', ], + 'legacy rgb with percentage components' => [ + 'rgb(0%, 60%, 0%)', + 'rgb(0%,60%,0%)', + ], 'legacy rgba with fractional alpha' => [ 'rgba(0, 119, 0, 0.5)', 'rgba(0,119,0,.5)', @@ -62,6 +66,14 @@ public static function provideValidColorAndExpectedRendering(): array 'rgba(0, 119, 0, 50%)', 'rgba(0,119,0,50%)', ], + 'legacy rgba with percentage components and fractional alpha' => [ + 'rgba(0%, 60%, 0%, 0.5)', + 'rgba(0%,60%,0%,.5)', + ], + 'legacy rgba with percentage components and percentage alpha' => [ + 'rgba(0%, 60%, 0%, 50%)', + 'rgba(0%,60%,0%,50%)', + ], 'legacy rgb as rgba' => [ 'rgba(0, 119, 0)', '#070', @@ -74,16 +86,73 @@ public static function provideValidColorAndExpectedRendering(): array 'rgb(0 119 0)', '#070', ], + // The "legacy" syntax currently used for rendering does not allow a mixture of percentages and numbers. + /* + 'modern rgb with percentage R' => [ + 'rgb(0% 119 0)', + 'rgb(0% 119 0)', + ], + 'modern rgb with percentage G' => [ + 'rgb(0 60% 0)', + 'rgb(0 60% 0)', + ], + 'modern rgb with percentage B' => [ + 'rgb(0 119 0%)', + 'rgb(0 119 0%)', + ], + 'modern rgb with percentage R&G' => [ + 'rgb(0% 60% 0)', + 'rgb(0% 60% 0)', + ], + 'modern rgb with percentage R&B' => [ + 'rgb(0% 119 0%)', + 'rgb(0% 119 0%)', + ], + 'modern rgb with percentage G&B' => [ + 'rgb(0 60% 0%)', + 'rgb(0 60% 0%)', + ], + //*/ + 'modern rgb with percentage components' => [ + 'rgb(0% 60% 0%)', + 'rgb(0%,60%,0%)', + ], /* 'modern rgb with none' => [ 'rgb(none 119 0)', 'rgb(none 119 0)', ], //*/ - 'modern rgba' => [ + 'modern rgba with fractional alpha' => [ 'rgb(0 119 0 / 0.5)', 'rgba(0,119,0,.5)', ], + 'modern rgba with percentage alpha' => [ + 'rgb(0 119 0 / 50%)', + 'rgba(0,119,0,50%)', + ], + /* + 'modern rgba with percentage R' => [ + 'rgb(0% 119 0 / 0.5)', + 'rgba(0% 119 0/.5)', + ], + 'modern rgba with percentage G' => [ + 'rgb(0 60% 0 / 0.5)', + 'rgba(0 60% 0/.5)', + ], + 'modern rgba with percentage B' => [ + 'rgb(0 119 0% / 0.5)', + 'rgba(0 119 0%/.5)', + ], + //*/ + 'modern rgba with percentage RGB' => [ + 'rgb(0% 60% 0% / 0.5)', + 'rgba(0%,60%,0%,.5)', + ], + 'modern rgba with percentage components' => [ + 'rgb(0% 60% 0% / 50%)', + 'rgba(0%,60%,0%,50%)', + ], /* 'modern rgba with none as alpha' => [ 'rgb(0 119 0 / none)',