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

时间:2022-01-14 15:41:23

Ok so lets say I have a variable $css that contains some CSS code. What I want to do is to add a certain text in front of each selector. So for example, the following code:

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

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

Would be converted into:

将被转换为:

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

I have been trying to use several explode()s. However, I haven't been able to accomplish the task effectively. Any thoughts?

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

Thanks! JCOC611

5 个解决方案

#1


4  

Based on Jon's suggestion I wrote the following code:

根据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;

To see that it works see http://codepad.org/bqRd83gu

要查看它的工作原理,请参阅http://codepad.org/bqRd83gu

#2


3  

I wrote improved version because I also need media query. This is my function based on Jan's answer:

我写了改进版,因为我还需要媒体查询。这是我根据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;   
} 

It works with media query and also @font-face.

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

#3


1  

This is more advanced JohnyFree's variant, with few dirty modifications.

这是更高级的JohnyFree的变种,几乎没有任何肮脏的修改。

This variant packs whole css into a single line, removes all css comments as well, and checks if $partDetails[1] is actually isset at the end, and than goes the imploding *(last else)

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

Give JohnyFree more reputation folks, he deserves it.

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

ps: I have added # shell style comments on places where modifications were performed by me.

ps:我已经在我执行修改的地方添加了#hell样式注释。

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)));
}

#4


0  

It looks like you need a proper CSS parser in order to be able to tell where is the start of each selector.

看起来你需要一个合适的CSS解析器才能分辨出每个选择器的起点。

However, you might be able to get away with a quick and dirty solution by considering that } signals the end of each selector, and inserting the necessary text after each occurrence of the closing brace except the last one.

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

#5


0  

This method will add prefixes to all selectors.

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

/**
 * 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;
}

#1


4  

Based on Jon's suggestion I wrote the following code:

根据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;

To see that it works see http://codepad.org/bqRd83gu

要查看它的工作原理,请参阅http://codepad.org/bqRd83gu

#2


3  

I wrote improved version because I also need media query. This is my function based on Jan's answer:

我写了改进版,因为我还需要媒体查询。这是我根据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;   
} 

It works with media query and also @font-face.

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

#3


1  

This is more advanced JohnyFree's variant, with few dirty modifications.

这是更高级的JohnyFree的变种,几乎没有任何肮脏的修改。

This variant packs whole css into a single line, removes all css comments as well, and checks if $partDetails[1] is actually isset at the end, and than goes the imploding *(last else)

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

Give JohnyFree more reputation folks, he deserves it.

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

ps: I have added # shell style comments on places where modifications were performed by me.

ps:我已经在我执行修改的地方添加了#hell样式注释。

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)));
}

#4


0  

It looks like you need a proper CSS parser in order to be able to tell where is the start of each selector.

看起来你需要一个合适的CSS解析器才能分辨出每个选择器的起点。

However, you might be able to get away with a quick and dirty solution by considering that } signals the end of each selector, and inserting the necessary text after each occurrence of the closing brace except the last one.

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

#5


0  

This method will add prefixes to all selectors.

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

/**
 * 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;
}