@@ -316,7 +316,9 @@ public function execute($path = null, $parents = array())
316316 $ css = $ this ->replace ($ css );
317317
318318 $ css = $ this ->stripWhitespace ($ css );
319- $ css = $ this ->shortenColors ($ css );
319+ $ css = $ this ->convertLegacyColors ($ css );
320+ $ css = $ this ->cleanupModernColors ($ css );
321+ $ css = $ this ->shortenHEXColors ($ css );
320322 $ css = $ this ->shortenZeroes ($ css );
321323 $ css = $ this ->shortenFontWeights ($ css );
322324 $ css = $ this ->stripEmptyTags ($ css );
@@ -480,64 +482,152 @@ protected function move(ConverterInterface $converter, $content)
480482 }
481483
482484 /**
483- * Shorthand hex color codes.
484- * #FF0000 -> #F00.
485+ * Shorthand HEX color codes.
486+ * #FF0000FF -> #f00 -> red
487+ * #FF00FF00 -> transparent
485488 *
486- * @param string $content The CSS content to shorten the hex color codes for
489+ * @param string $content The CSS content to shorten the HEX color codes for
487490 *
488491 * @return string
489492 */
490- protected function shortenColors ($ content )
493+ protected function shortenHexColors ($ content )
491494 {
492- $ content = preg_replace ('/(?<=[: ])#([0-9a-z]) \\1([0-9a-z]) \\2([0-9a-z]) \\3(?:([0-9a-z]) \\4)?(?=[; }])/i ' , '#$1$2$3$4 ' , $ content );
495+ // shorten repeating patterns within HEX ..
496+ $ content = preg_replace ('/(?<=[: ])#([0-9a-f]) \\1([0-9a-f]) \\2([0-9a-f]) \\3(?:([0-9a-f]) \\4)?(?=[; }])/i ' , '#$1$2$3$4 ' , $ content );
493497
494- // remove alpha channel if it's pointless...
495- $ content = preg_replace ('/(?<=[: ])#([0-9a-z]{6})ff?(?=[; }])/i ' , '#$1 ' , $ content );
496- $ content = preg_replace ('/(?<=[: ])#([0-9a-z]{3})f?(?=[; }])/i ' , '#$1 ' , $ content );
498+ // remove alpha channel if it's pointless ..
499+ $ content = preg_replace ('/(?<=[: ])#([0-9a-f]{6})ff(?=[; }])/i ' , '#$1 ' , $ content );
500+ $ content = preg_replace ('/(?<=[: ])#([0-9a-f]{3})f(?=[; }])/i ' , '#$1 ' , $ content );
501+
502+ // replace `transparent` with shortcut ..
503+ $ content = preg_replace ('/(?<=[: ])#[0-9a-f]{6}00(?=[; }])/i ' , '#fff0 ' , $ content );
497504
498505 $ colors = array (
506+ // make these more readable
507+ '#00f ' => 'blue ' ,
508+ '#dc143c ' => 'crimson ' ,
509+ '#0ff ' => 'cyan ' ,
510+ '#8b0000 ' => 'darkred ' ,
511+ '#696969 ' => 'dimgray ' ,
512+ '#ff69b4 ' => 'hotpink ' ,
513+ '#0f0 ' => 'lime ' ,
514+ '#fdf5e6 ' => 'oldlace ' ,
515+ '#87ceeb ' => 'skyblue ' ,
516+ '#d8bfd8 ' => 'thistle ' ,
499517 // we can shorten some even more by replacing them with their color name
500- '#F0FFFF ' => 'azure ' ,
501- '#F5F5DC ' => 'beige ' ,
502- '#A52A2A ' => 'brown ' ,
503- '#FF7F50 ' => 'coral ' ,
504- '#FFD700 ' => 'gold ' ,
518+ '#f0ffff ' => 'azure ' ,
519+ '#f5f5dc ' => 'beige ' ,
520+ '#ffe4c4 ' => 'bisque ' ,
521+ '#a52a2a ' => 'brown ' ,
522+ '#ff7f50 ' => 'coral ' ,
523+ '#ffd700 ' => 'gold ' ,
505524 '#808080 ' => 'gray ' ,
506525 '#008000 ' => 'green ' ,
507- '#4B0082 ' => 'indigo ' ,
508- '#FFFFF0 ' => 'ivory ' ,
509- '#F0E68C ' => 'khaki ' ,
510- '#FAF0E6 ' => 'linen ' ,
526+ '#4b0082 ' => 'indigo ' ,
527+ '#fffff0 ' => 'ivory ' ,
528+ '#f0e68c ' => 'khaki ' ,
529+ '#faf0e6 ' => 'linen ' ,
511530 '#800000 ' => 'maroon ' ,
512531 '#000080 ' => 'navy ' ,
513532 '#808000 ' => 'olive ' ,
514- '#CD853F ' => 'peru ' ,
515- '#FFC0CB ' => 'pink ' ,
516- '#DDA0DD ' => 'plum ' ,
533+ '#ffa500 ' => 'orange ' ,
534+ '#da70d6 ' => 'orchid ' ,
535+ '#cd853f ' => 'peru ' ,
536+ '#ffc0cb ' => 'pink ' ,
537+ '#dda0dd ' => 'plum ' ,
517538 '#800080 ' => 'purple ' ,
518- '#F00 ' => 'red ' ,
519- '#FA8072 ' => 'salmon ' ,
520- '#A0522D ' => 'sienna ' ,
521- '#C0C0C0 ' => 'silver ' ,
522- '#FFFAFA ' => 'snow ' ,
523- '#D2B48C ' => 'tan ' ,
524- '#FF6347 ' => 'tomato ' ,
525- '#EE82EE ' => 'violet ' ,
526- '#F5DEB3 ' => 'wheat ' ,
539+ '#f00 ' => 'red ' ,
540+ '#fa8072 ' => 'salmon ' ,
541+ '#a0522d ' => 'sienna ' ,
542+ '#c0c0c0 ' => 'silver ' ,
543+ '#fffafa ' => 'snow ' ,
544+ '#d2b48c ' => 'tan ' ,
545+ '#008080 ' => 'teal ' ,
546+ '#ff6347 ' => 'tomato ' ,
547+ '#ee82ee ' => 'violet ' ,
548+ '#f5deb3 ' => 'wheat ' ,
527549 // or the other way around
528- 'WHITE ' => '#fff ' ,
529- 'BLACK ' => '#000 ' ,
550+ 'black ' => '#000 ' ,
551+ 'fuchsia ' => '#f0f ' ,
552+ 'magenta ' => '#f0f ' ,
553+ 'white ' => '#fff ' ,
554+ 'yellow ' => '#ff0 ' ,
555+ // and also `transparent`
556+ 'transparent ' => '#fff0 '
530557 );
531558
532559 return preg_replace_callback (
533560 '/(?<=[: ])( ' . implode ('| ' , array_keys ($ colors )) . ')(?=[; }])/i ' ,
534561 function ($ match ) use ($ colors ) {
535- return $ colors [strtoupper ($ match [0 ])];
562+ return $ colors [strtolower ($ match [0 ])];
536563 },
537564 $ content
538565 );
539566 }
540567
568+ /**
569+ * Convert RGB|HSL color codes.
570+ * rgb(255,0,0,.5) -> rgb(255 0 0 / .5).
571+ * rgb(255,0,0) -> #f00.
572+ *
573+ * @param string $content The CSS content to shorten the RGB color codes for
574+ *
575+ * @return string
576+ */
577+ protected function convertLegacyColors ($ content )
578+ {
579+ /*
580+ https://drafts.csswg.org/css-color/#color-syntax-legacy
581+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb
582+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl
583+ */
584+
585+ // convert legacy color syntax
586+ $ content = preg_replace ('/(rgb|hsl)a?\(([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^\s\)]+)\)/i ' , '$1($2 $3 $4 / $5) ' , $ content );
587+ $ content = preg_replace ('/(rgb|hsl)a?\(([^,\s]+)\s*,\s*([^,\s]+)\s*,\s*([^,\s]+)\)/i ' , '$1($2 $3 $4) ' , $ content );
588+
589+ // convert `rgb` to `hex`
590+ $ dec = '([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5]) ' ;// [000-255] THX @ https://www.regular-expressions.info/numericranges.html
591+ return preg_replace_callback (
592+ "/rgb\( $ dec $ dec $ dec\)/i " ,
593+ function ($ match )
594+ {
595+ return sprintf ('#%02x%02x%02x ' , $ match [1 ],$ match [2 ],$ match [3 ]);
596+ },
597+ $ content
598+ );
599+ }
600+
601+ /**
602+ * Cleanup RGB|HSL|HWB|LCH|LAB
603+ * rgb(255 0 0 / 1) -> rgb(255 0 0).
604+ * rgb(255 0 0 / 0) -> transparent.
605+ *
606+ * @param string $content The CSS content to cleanup HSL|HWB|LCH|LAB
607+ *
608+ * @return string
609+ */
610+ protected function cleanupModernColors ($ content )
611+ {
612+ /*
613+ https://drafts.csswg.org/css-color/#color-syntax-modern
614+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb
615+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch
616+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab
617+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch
618+ https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab
619+ */
620+ $ tag = '(rgb|hsl|hwb|(?:(?:ok)?(?:lch|lab))) ' ;
621+
622+ // remove alpha channel if it's pointless ..
623+ $ content = preg_replace ('/ ' .$ tag .'\(([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+\/\s+1(?:[\.\d]*|00%)?\)/i ' , '$1($2 $3 $4) ' , $ content );
624+
625+ // replace `transparent` with shortcut ..
626+ $ content = preg_replace ('/ ' .$ tag .'\([^\s]+\s+[^\s]+\s+[^\s]+\s+\/\s+0(?:[\.0%]*)?\)/i ' , '#fff0 ' , $ content );
627+
628+ return $ content ;
629+ }
630+
541631 /**
542632 * Shorten CSS font weights.
543633 *
0 commit comments