使用PHP在CSS的摘录中为所有选择器添加前缀?

时间:2011-10-20 21:30:54

标签: php css parsing

好的,假设我有一个包含一些CSS代码的变量$css。我想要做的是在每个选择器前添加一个特定的文本。例如,以下代码:

#hello, .class{width:1px;height:1px;background-color:#AAA;}
div{font-size:1px}
input, a, span{padding:4px}

将转换为:

#someId #hello, #someId .class{ ... }
#someId div{ ... }
#someId input, #someId a, #someId span{ ... }

我一直在尝试使用多个explode()。但是,我无法有效地完成任务。有什么想法吗?

谢谢! JCOC611

6 个答案:

答案 0 :(得分:4)

根据Jon的建议,我写了以下代码:

<?php

$prefix = '#someId';
$css = '#hello, .class{width:1px;height:1px;background-color:#AAA;}
div{font-size:1px}
input, a, span{padding:4px}';

$parts = explode('}', $css);
foreach ($parts as &$part) {
    if (empty($part)) {
        continue;
    }

    $subParts = explode(',', $part);
    foreach ($subParts as &$subPart) {
        $subPart = $prefix . ' ' . trim($subPart);
    }

    $part = implode(', ', $subParts);
}

$prefixedCss = implode("}\n", $parts);

echo $prefixedCss;

要查看其有效,请参阅http://codepad.org/bqRd83gu

答案 1 :(得分:4)

我写了改进版,因为我还需要媒体查询。这是我基于Jan的回答的函数:

function getPrefixedCss($css,$prefix){
  $parts = explode('}', $css);  
  $mediaQueryStarted = false;
  foreach ($parts as &$part) {
      if (empty($part)) {
          continue;
      }

      $partDetails = explode('{',$part);
      if(substr_count($part,"{")==2){
        $mediaQuery = $partDetails[0]."{";
        $partDetails[0] = $partDetails[1];
        $mediaQueryStarted = true;
      }

      $subParts = explode(',', $partDetails[0]);
      foreach ($subParts as &$subPart) {
          if(trim($subPart)=="@font-face") continue;    
          $subPart = $prefix . ' ' . trim($subPart);
      }       

      if(substr_count($part,"{")==2){
        $part = $mediaQuery."\n".implode(', ', $subParts)."{".$partDetails[2];
      }elseif(empty($part[0]) && $mediaQueryStarted){
        $mediaQueryStarted = false;
        $part = implode(', ', $subParts)."{".$partDetails[2]."}\n"; //finish media query
      }else{
        $part = implode(', ', $subParts)."{".$partDetails[1];
      }        
  }

  $prefixedCss = implode("}\n", $parts);

  return $prefixedCss;   
} 

它适用于媒体查询和@ font-face。

答案 2 :(得分:2)

这是更高级的JohnyFree变体,很少dirty次修改。

此变体将整个css打包成一行, 同时删除所有css注释,并检查最后是否实际上是$partDetails[1],而不是内爆*(最后else

给予JohnyFree更多声誉的人,他应得的。

ps:我已经在我执行修改的地方添加了# shell style comments

function getPrefixedCss($css,$prefix)
{
    # Wipe all block comments
    $css = preg_replace('!/\*.*?\*/!s', '', $css);

    $parts = explode('}', $css);
    $mediaQueryStarted = false;

    foreach($parts as &$part)
    {
        $part = trim($part); # Wht not trim immediately .. ?
        if(empty($part)) continue;
        else # This else is also required
        {
            $partDetails = explode('{', $part);
            if(substr_count($part, "{")==2)
            {
                $mediaQuery = $partDetails[0]."{";
                $partDetails[0] = $partDetails[1];
                $mediaQueryStarted = true;
            }

            $subParts = explode(',', $partDetails[0]);
            foreach($subParts as &$subPart)
            {
                if(trim($subPart)==="@font-face") continue;
                else $subPart = $prefix . ' ' . trim($subPart);
            }

            if(substr_count($part,"{")==2)
            {
                $part = $mediaQuery."\n".implode(', ', $subParts)."{".$partDetails[2];
            }
            elseif(empty($part[0]) && $mediaQueryStarted)
            {
                $mediaQueryStarted = false;
                $part = implode(', ', $subParts)."{".$partDetails[2]."}\n"; //finish media query
            }
            else
            {
                if(isset($partDetails[1]))
                {   # Sometimes, without this check,
                    # there is an error-notice, we don't need that..
                    $part = implode(', ', $subParts)."{".$partDetails[1];
                }
            }

            unset($partDetails, $mediaQuery, $subParts); # Kill those three ..
        }   unset($part); # Kill this one as well
    }

    # Finish with the whole new prefixed string/file in one line
    return(preg_replace('/\s+/',' ',implode("} ", $parts)));
}

答案 3 :(得分:0)

看起来你需要一个合适的CSS解析器才能告诉每个选择器的起点在哪里。

但是,您可以通过考虑}发出每个选择器结束的信号并在每次出现右括号之后插入必要的文本(最后一个除外)来解决快速而肮脏的解决方案。

答案 4 :(得分:0)

此方法将为所有选择器添加前缀。

/**
 * Prefix CSS code.
 * 
 * @param  $prefix prefix to add to all selectors.
 * @param  $css    CSS code to prefix.
 * @return CSS     the prefixed CSS
 */
function prefixCSS($prefix, $css) {
    $parts = explode('}', $css);
    foreach ($parts as &$part) {
        if (empty($part)) {
            continue;
        }

        $firstPart = substr($part, 0, strpos($part, '{') + 1);
        $lastPart = substr($part, strpos($part, '{') + 2);
        $subParts = explode(',', $firstPart);
        foreach ($subParts as &$subPart) {
            $subPart = str_replace("\n", '', $subPart);
            $subPart = $prefix . ' ' . trim($subPart);
        }

        $part = implode(', ', $subParts) . $lastPart;
    }

    $prefixedCSS = implode("}\n", $parts);

    return $prefixedCSS;
}

答案 5 :(得分:0)

感谢解决方案专家。 我唯一缺少的是关键帧支持。 这是我的补充:

function getPrefixedCss($css,$prefix)
{
    # Wipe all block comments
    $css = preg_replace('!/\*.*?\*/!s', '', $css);

    $parts = explode('}', $css);
    $keyframeStarted = false;
    $mediaQueryStarted = false;

    foreach($parts as &$part)
    {
        $part = trim($part); # Wht not trim immediately .. ?
        if(empty($part)) {
            $keyframeStarted = false;
            continue;
        }
        else # This else is also required
        {
            $partDetails = explode('{', $part);

            if (strpos($part, 'keyframes') !== false) {
                $keyframeStarted = true;
                continue;
            }

            if($keyframeStarted) {
                continue;
            }

            if(substr_count($part, "{")==2)
            {
                $mediaQuery = $partDetails[0]."{";
                $partDetails[0] = $partDetails[1];
                $mediaQueryStarted = true;
            }

            $subParts = explode(',', $partDetails[0]);
            foreach($subParts as &$subPart)
            {
                if(trim($subPart)==="@font-face") continue;
                else $subPart = $prefix . ' ' . trim($subPart);
            }

            if(substr_count($part,"{")==2)
            {
                $part = $mediaQuery."\n".implode(', ', $subParts)."{".$partDetails[2];
            }
            elseif(empty($part[0]) && $mediaQueryStarted)
            {
                $mediaQueryStarted = false;
                $part = implode(', ', $subParts)."{".$partDetails[2]."}\n"; //finish media query
            }
            else
            {
                if(isset($partDetails[1]))
                {   # Sometimes, without this check,
                    # there is an error-notice, we don't need that..
                    $part = implode(', ', $subParts)."{".$partDetails[1];
                }
            }

            unset($partDetails, $mediaQuery, $subParts); # Kill those three ..
        }   unset($part); # Kill this one as well
    }

    # Finish with the whole new prefixed string/file in one line
    return(preg_replace('/\s+/',' ',implode("} ", $parts)));
}