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

发布于 2024-12-10 23:53:14 字数 442 浏览 0 评论 0原文

好吧,假设我有一个包含一些 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

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:

#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?

Thanks! JCOC611

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

给不了的爱 2024-12-17 23:53:14

根据乔恩的建议,我编写了以下代码:

<?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

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

<?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

别挽留 2024-12-17 23:53:14

我写了改进版本,因为我还需要媒体查询。这是我基于 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。

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

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.

夏尔 2024-12-17 23:53:14

这是更高级的 JohnyFree 变体,几乎没有什么修改。

这个变体将整个 css 打包到一行中,
也删除所有 css 注释,并检查 $partDetails[1] 是否确实在最后设置,然后内爆 *(last 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)));
}

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

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)

Give JohnyFree more reputation folks, he deserves it.

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

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)));
}
指尖凝香 2024-12-17 23:53:14

看起来您需要一个合适的 CSS 解析器才能知道每个选择器的开始位置。

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

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

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.

带上头具痛哭 2024-12-17 23:53:14

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

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

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;
}
偷得浮生 2024-12-17 23:53:14

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

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

Thanks for solution guys.
The only thing that was missing for me was keyframes support.
Here is my addition for it:

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)));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文