【问题标题】:Convert CSS background shorthand to longhand将 CSS 背景速记转换为速记
【发布时间】:2011-10-28 11:49:45
【问题描述】:

我正在尝试编写一个函数,将背景的简写 css 声明转换为长手。我已经编写了以下函数,但它有几个问题。它没有考虑到background-color 可以是颜色值,例如blackyellow。此外,如果某些属性包含inheritnone 怎么办?这是一个例子:

url('http://2.bp.blogspot.com/-h28qvOsfm1c/TaGyO_qAFcI/AAAAAAAAA9w/I7zPQLy0zVM/s640/funny-image.jpg') inherit inherit 0 0 #FFFFFF;

将上面的内容转换为 CSS 长手。这是我的功能,是否可以改进以涵盖其他情况?

function rewrite_background($b){

    $long_hand = "";

    $count = count($b); 

    for($i=0; $i < $count; $i++){

        if(stripos($b[$i], '#') !== false){

            $long_hand .= 'background-color: '.$b[$i].'; ';

            unset($b[$i]);

        }else if(stripos($b[$i], 'url') !== false){

            $long_hand .= 'background-image: '.$b[$i].'; ';

            unset($b[$i]);

        }else if((stripos($b[$i], 'repeat') !== false) || (stripos($b[$i], 'no-repeat') !== false) || (stripos($b[$i], 'repeat-x') !== false) || (stripos($b[$i], 'repeat-y') !== false)){

            $long_hand .= 'background-repeat: '.$b[$i].'; ';

            unset($b[$i]);

        }else if((stripos($b[$i], 'scroll') !== false) || (stripos($b[$i], 'fixed') !== false)){

            $long_hand .= 'background-attachment: '.$b[$i].'; ';

            unset($b[$i]);

        }else{

            // not recognized

        }

    }

    $b = array_values($b);

    if(isset($b[0])) $long_hand .= 'background-position: '.$b[0].' '.$b[1].';';  

    return $long_hand;

} 

【问题讨论】:

标签: php html css


【解决方案1】:

解析 CSS 背景快捷方式的类

此类将以任何顺序解析几乎任何一行背景快捷方式属性,包括根据specs 无效的那些。例如,background: top top 被视为background-position: center top

完全支持所有颜色值,包括:rgb、rgba、hls、hlsa、不区分大小写的短格式十六进制(例如#fff)、不区分大小写的长格式十六进制(例如#123Abc)和不区分大小写颜色名称。

现在支持!important

inherit 似乎是最具挑战性的问题,但结果却是最简单的。对于这个属性,我提到了http://reference.sitepoint.com/css/inheritvalue,它指出:

当您使用诸如背景之类的速记符号时,您不能混合使用 与其他值继承。比如下面的背景 声明错误:

p {
  background: #fff inherit left top;
}

...inherit 必须是声明中的唯一值,因为有 根本无法识别价值所在的子属性 inherit 指代——毕竟,它在序列中不是唯一的。在里面 上面的例子,inherit 变得不明确。

为了处理歧义,这个类简单地忽略其他所有内容(除了 !important)并将继承应用于所有属性,就像您使用了 background: inherit 一样。

代码

<?php
class CSSBackground
{
    private $color_names = array(
        'AliceBlue', 'AntiqueWhite', 'Aqua', 'Aquamarine', 'Azure',
        'Beige', 'Bisque', 'Black', 'BlanchedAlmond', 'Blue',
        'BlueViolet', 'Brown', 'BurlyWood', 'CadetBlue', 'Chartreuse',
        'Chocolate', 'Coral', 'CornflowerBlue', 'Cornsilk', 'Crimson',
        'Cyan', 'DarkBlue', 'DarkCyan', 'DarkGoldenRod', 'DarkGray',
        'DarkGrey', 'DarkGreen', 'DarkKhaki', 'DarkMagenta',
        'DarkOliveGreen', 'Darkorange', 'DarkOrchid', 'DarkRed',
        'DarkSalmon', 'DarkSeaGreen', 'DarkSlateBlue', 'DarkSlateGray',
        'DarkSlateGrey', 'DarkTurquoise', 'DarkViolet', 'DeepPink',
        'DeepSkyBlue', 'DimGray', 'DimGrey', 'DodgerBlue', 'FireBrick',
        'FloralWhite', 'ForestGreen', 'Fuchsia', 'Gainsboro',
        'GhostWhite', 'Gold', 'GoldenRod', 'Gray', 'Grey', 'Green',
        'GreenYellow', 'HoneyDew', 'HotPink', 'IndianRed', 'Indigo',
        'Ivory', 'Khaki', 'Lavender', 'LavenderBlush', 'LawnGreen',
        'LemonChiffon', 'LightBlue', 'LightCoral', 'LightCyan',
        'LightGoldenRodYellow', 'LightGray', 'LightGrey', 'LightGreen',
        'LightPink', 'LightSalmon', 'LightSeaGreen', 'LightSkyBlue',
        'LightSlateGray', 'LightSlateGrey', 'LightSteelBlue', 'LightYellow',
        'Lime', 'LimeGreen', 'Linen', 'Magenta', 'Maroon',
        'MediumAquaMarine', 'MediumBlue', 'MediumOrchid', 'MediumPurple',
        'MediumSeaGreen', 'MediumSlateBlue', 'MediumSpringGreen',
        'MediumTurquoise', 'MediumVioletRed', 'MidnightBlue', 'MintCream',
        'MistyRose', 'Moccasin', 'NavajoWhite', 'Navy', 'OldLace', 'Olive',
        'OliveDrab', 'Orange', 'OrangeRed', 'Orchid', 'PaleGoldenRod',
        'PaleGreen', 'PaleTurquoise', 'PaleVioletRed', 'PapayaWhip',
        'PeachPuff', 'Peru', 'Pink', 'Plum', 'PowderBlue', 'Purple', 'Red',
        'RosyBrown', 'RoyalBlue', 'SaddleBrown', 'Salmon', 'SandyBrown',
        'SeaGreen', 'SeaShell', 'Sienna', 'Silver', 'SkyBlue', 'SlateBlue',
        'SlateGray', 'SlateGrey', 'Snow', 'SpringGreen', 'SteelBlue', 'Tan',
        'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'White',
        'WhiteSmoke', 'Yellow', 'YellowGreen'
    );

    private $m_bgcolor = 'transparent';
    private $m_bgimage = 'none';
    private $m_bgrepeat = 'repeat';
    private $m_bgattachment = 'scroll';
    private $m_bgposition = '0% 0%';
    private $m_bgimportant = false;
    private $m_bg;

    public function __construct($bg)
    {
        // reformat array names for efficient pattern matching
        $this->color_names = '/\b('.implode('|',$this->color_names).')\b/i';

        $this->m_bg = $bg;  // save original

        $bg = $this->parse_important($bg);
        $bg = $this->parse_inherit($bg);
        $bg = $this->parse_color($bg);
        $bg = $this->parse_image($bg);
        $bg = $this->parse_repeat($bg);
        $bg = $this->parse_attachment($bg);
        $bg = $this->parse_position($bg);
    }

    public function original()
    {
        return $this->m_bg;
    }

    public function color()
    {
        return $this->m_bgcolor;
    }

    public function image()
    {
        return $this->m_bgimage;
    }

    public function repeat()
    {
        return $this->m_bgrepeat;
    }

    public function attachment()
    {
        return $this->m_bgattachment;
    }

    public function position()
    {
        return $this->m_bgposition;
    }

    public function important()
    {
        return $this->m_bgimportant;
    }

    private function parse_important($c)
    {
        // check for !important
        if (preg_match('/!important/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgimportant = true ;
        }

        return $c;
    }

    private function parse_inherit($c)
    {
        // check for !important
        if (preg_match('/inherit/i', $c, $m))
        {
            $this->m_bgcolor = $this->apply_important('inherit');
            $this->m_bgimage = $this->apply_important('inherit');
            $this->m_bgrepeat = $this->apply_important('inherit');
            $this->m_bgattachment = $this->apply_important('inherit');
            $this->m_bgposition = $this->apply_important('inherit');
            $c = '';
        }

        return $c;
    }

    private function parse_color($c)
    {
        // check for hexit color value
        if (preg_match('/#([[:xdigit:]]{3}){1,2}/', $c, $m))
        {
            $c = str_replace($m[0], '', $c);

            $this->m_bgcolor = $this->apply_important($m[0]);
        }

        // check for rgb color value
        elseif (preg_match('/rgb\(\d{0,3}\,\d{0,3},\d{0,3}\)/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgcolor = $this->apply_important($m[0]);
        }

        // check for rgba color value
        elseif (preg_match('/rgba\(\d{0,3}%?\,\d{0,3}%?,\d{0,3}%?\,\d(\.\d)?\)/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgcolor = $this->apply_important($m[0]);
        }

        // check for hls color value
        elseif (preg_match('/hls\(\d{0,3}\,\d{0,3}%,\d{0,3}%\)/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgcolor = $this->apply_important($m[0]);
        }

        // check for hlsa color value
        elseif (preg_match('/hlsa\(\d{0,3}\,\d{0,3}%,\d{0,3}%\,\d(\.\d)?\)/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgcolor = $this->apply_important($m[0]);
        }

        // check for transparent
        elseif (preg_match('/transparent/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgcolor = $this->apply_important('transparent');
        }

        // check for color names
        elseif (preg_match($this->color_names, $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgcolor = $this->apply_important($m[0]);
        }

        return $c;
    }

    private function parse_image($c)
    {
        // check for double word positions
        if (preg_match('/url\((.*?)\)|none/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            if (isset($m[1]))
            {
                $m[0] = str_replace($m[1], urlencode($m[1]), $m[0]);
            }
            $this->m_bgimage = $this->apply_important($m[0]);
        }

        return $c;
    }

    private function parse_repeat($c)
    {
        // check for repeat values
        if (preg_match('/\b(repeat-x|repeat-y|no-repeat|repeat)\b/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgrepeat = $this->apply_important($m[0]);
        }

        return $c;
    }

    private function parse_attachment($c)
    {
        // check for repeat values
        if (preg_match('/scroll|fixed/i', $c, $m))
        {
            $c = str_replace($m[0], '', $c);
            $this->m_bgattachment = $this->apply_important($m[0]);
        }

        return $c;
    }

    private function parse_position($c)
    {
        // check for position values
        if (preg_match_all('/left|right|center|top|bottom|-?\d+([a-zA-Z]{2}|%?)/i', $c, $m))
        {
            $horz = '0%';
            $vert = '0%';

            if (!isset($m[0][1]))
            {
                $x = strtolower($m[0][0]);
                switch ($x)
                {
                    case 'top':
                    case 'bottom':
                        $horz = 'center';
                        $vert = $x;
                        break;
                    case 'left':
                    case 'right':
                    case 'center':
                        $horz = $x;
                        $vert = 'center';
                        break;
                    default:
                        $horz = is_numeric($x) ? "{$x}px" : $x;
                        $vert = 'center';
                }
            }

            else
            {
                $horz = strtolower($m[0][0]);
                $vert = strtolower($m[0][1]);

                if (($horz === $vert) && in_array($horz, array('left','right')))
                {
                    $vert = 'center';
                }

                if (($horz === $vert) && in_array($horz, array('top','bottom')))
                {
                    $horz = 'center';
                }

                if ($horz === 'top' || $horz === 'bottom')
                {
                    list($horz,$vert) = array($vert,$horz);
                }

                if ($vert === 'left' || $vert === 'right')
                {
                    list($horz,$vert) = array($vert,$horz);
                }
            }

            $this->m_bgposition = $this->apply_important("$horz $vert");
        }

        return $c;
    }

    private function apply_important($prop)
    {
        return $prop . ($this->m_bgimportant ? ' !important' : '');
    }
}

?>

示例用法

<?php
header('Content-type: text/plain');

$bg = 'url("chess.png") gray 50% repeat fixed';

$cssbg = new CSSBackground($bg);

echo "background: ", $cssbg->original(), "\n\n";
echo "background-color: ", $cssbg->color(), "\n";
echo "background-image: ", $cssbg->image(), "\n";
echo "background-repeat: ", $cssbg->repeat(), "\n";
echo "background-attachment: ", $cssbg->attachment(), "\n";
echo "background-position: ", $cssbg->position(), "\n\n";
echo "!important applied: ", $cssbg->important() ? 'true' : 'false', "\n";
?>

这个类是通过对w3c specifications for the CSS background property 的广泛分析而开发的。其他 CSS 属性将需要相同的分析处理。

【讨论】:

  • @Herbert - 这是一堂很棒的课。但是,有一个主要问题是用户不会遵循订单,我看到很多这样的情况发生!
  • @Abs - 感谢您的积极反馈。你有一个有效的观点。正如我所提到的,这只是一个让人们开始的黑客工作。太多的答案说“不可能”,这对我来说是一个 4 个字母的词。我看看能不能改进一下。
  • 完全重写。我对 CSS 背景属性的了解比我想象的要多。
  • @Herbert - 太棒了!细节水平令人印象深刻。一个当之无愧的赏金!非常感谢! :)
  • @Abs - 感谢您的赏金。我为此努力工作......有些人认为你不能用 PHP 做任何有用的事情。 :P
【解决方案2】:

我建议你找一个有很多正则表达式经验的人给你写一个强大的匹配字符串。

你会遇到真正的问题,但你可以假设:

url(.*) 总是作为背景图片

#(.{3})(.{3})?始终是一种颜色(但您可能有其他词与此处的任何其他匹配项都不匹配,这些匹配项也是颜色)

([1-9][0-9]%|[0-9][0-9]+(px|em)|0|inherit|top|bottom|center|left|right) 是背景位置(以及其中的一两个)

(repeat|repeat-x|repeat-y|no-repeat|inherit) 总是背景重复

请记住,它们可能是许多订单之一。

【讨论】:

    【解决方案3】:

    与其使用 stripos 搜索 $b 并根据结果不为 FALSE 分配 CSS 长手属性,不如按顺序进行?每次在将 $b 属性传递给函数之前,您都可以使用设置模式:

    $b[0]=background-attachment;
    $b[1]=background-color;
    $b[2]=background-image;
    $b[3]=background-position;
    $b[4]=background-repeat;
    

    这意味着您需要将速记重新排列为:

    $b=array(inherit, #fff, url('example.jpg'), 0 0, inherit);
    

    因此,您可以处理任何属性值(甚至是“继承”和“无”) - 您只需要确保始终保持正确的顺序并且不要错过任何属性,否则数组键会出错。您可以在另一个 PHP 函数中轻松地将 CSS 颜色名称转换为十六进制值(使用 list of all the CSS names),或者您可以使用 this JavaScript function

    【讨论】:

      【解决方案4】:

      在 PHP 中完美地完成您想做的事情几乎是不可能的。你会得到最好的结果是一个非常接近有缺陷的情况,例如,你的不支持 rgb、rgba、hsl、hsla 颜色格式,这是有效的。


      你应该做的是找到一个好的php css parser,并使用它。

      【讨论】:

      • 我从来没有说过这是不可能的。好好读书。我说这几乎不可能,确实如此。
      • 我在 24 小时内完成了。这很困难,但也不是远程不可能的。此外,“php css 解析器”是用 PHP 编写的!我想这不是进行这种对话的地方,但是这个“答案”和类似的人纯粹是懒惰,他们正在拖累 SO 的质量。回答或不回答问题,但不要告诉 OP 某事不可能仅仅因为 做不到。
      【解决方案5】:

      我认为在这里你能做的最好的事情就是建立一个接近的近似值,因为你的程序必须完全理解 CSS 才能完全转换它,而正则表达式不能完全胜任这项任务。您将需要一个真正的解析库。但首先,这里有一个关于使用 Coco/R 解析器处理 CSS 的非常好的教程:http://www.codeproject.com/KB/recipes/CSSParser.aspx 它会让您更好地了解问题的范围。

      这里还有一个用于 CSS 解析的 PHP 类http://www.phpclasses.org/package/1289-PHP-CSS-parser-class.html#download,但我对此并不抱太大期望。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-09-01
        • 1970-01-01
        • 2018-01-18
        • 1970-01-01
        • 1970-01-01
        • 2018-11-03
        • 1970-01-01
        • 2012-11-22
        相关资源
        最近更新 更多