RegExp search and replace path to image in css - css

It is necessary to perform a search and replace strings in css file. And found only the title picture with.
While the search is done so with the exception of
/:(\s*)url\(((.(?!.*https:|.*http:|.*base64|.*data:image))*)\)/ig
and replace
:$1url(\'../dist/img/vendor/$2\')
In this case, I replace the path in a similar way. And I get this result
background-image: url('../dist/img/vendor/"../images/preloader.gif"');
A need of a string
background-image: url("../images/preloader.gif");
get
background-image: url('../dist/img/vendor/preloader.gif');

Find
/(url\(\s*[\"\'])(?:[^\"\']+\/)?([^\/\"\']+[\"\']\s*\))/ig
Replace
$1../dist/img/vendor/$2
Demo https://regex101.com/r/kU7cC9/3

Using a css parser is a better way if you want among other things to avoid quotes problems (single quotes, double quotes, no quotes).
As an aside, the background-image CSS property isn't the only one that can contain a path to an image file, since the background property can compile all the data from other background- properties.
An example with sabberworm PHP CSS Parser that automatically encloses paths between double quotes:
require __DIR__ . '/vendor/autoload.php';
define('NEW_PATH', '../dist/img/vendor/');
$oCssParser = new Sabberworm\CSS\Parser($css);
$oCssDocument = $oCssParser->parse();
$properties = ['background-image', 'background'];
foreach($oCssDocument->getAllRuleSets() as $oRuleSet) {
foreach($properties as $property) {
$oCssRules = $oRuleSet->getRules($property);
foreach ($oCssRules as $oCssRule) {
$value = $oCssRule->getValue()->__toString();
if (!preg_match('~https?:|base64|data:image~S', $value)) {
$value = preg_replace('~url\("\K(?:[^"/]*/)*~', NEW_PATH, $value);
$oCssRule->setValue($value);
}
}
}
}
echo $oCssDocument->render(Sabberworm\CSS\OutputFormat::createPretty());

Related

Create multiple background using SASS mixin

I'm trying to create a mixin in Sass to generate multiple background, problem is the number of background is unknow, it's can be 3, 4 or even 5. Here what I try and fail.
#mixin multiBg($page: index, $sec: sec01,$from: 1, $to: 3, $type: jpg){
$url: (); // i'm try to create a empty array first
$newUrl: null; // and an empty variable
#for $i from $from through $to {
$newUrl: append($url, url(../img/#{$page}/#{$sec}_bg0#{$i}.#{$type})); // then append value to variable;
}
background: $newUrl;
}
#sec05 {
#include multiBg(index,sec05);
}
current output:
background: url(../img/index/sec05_bg03.jpg);
expected output:
background: url(../img/sec05_bg01.jpg),url(../img/sec05_bg02.jpg), url(../img/sec05_bg03.jpg);
I don't know how to fix this problem since i'm still learing SASS. Can someone enlighten me please.
You're on the right track! But your syntax and logic are slightly off. Here's what I came up with:
#mixin multiBg($page: index, $sec: sec01, $from: 1, $to: 5, $type: jpg) {
$url_list: ();
#for $i from $from through $to {
// I broke constructing the url and adding it to the set into two steps here.
// We could do this all at once, but separating it can make it easier to read.
// First, generate the url.
$url_string: url(../img/#{$page}/#{$sec}_bg0#{$i}.#{$type});
// Then add it to the list (the 'comma' part is important)
$url_list: append($url_list, $url_string, comma);
}
// Done looping? Output the final list!
background-image: $url_list;
}
That seems to return what you're looking for. Here are the official docs on list functions - I always forget one or two, may be useful for you too.
Also, since you mentioned you're new to sass - check out Sassmeister if you haven't already. It's a handy little sandbox for quickly prototyping and trying things out in sass; similar to Codepen but a bit more specialized. It's what I used to experiment with this question.
This is a cleaner answer, I believe.
#mixin image-resolve($image) {
$images: ();
#each $i in $image {
$path: ();
$images: append($images, $path, comma);
}
background-image: $images;
}

regex to delete specific entries in .css file

trying to delete the following entries in a .css file
UNUSEDbody.sticky-menu-active {
padding-top: 26px;
}
all the css entries I want to remove are prefixed with UNUSED followed by characters { }
so I want to delete everything starting with UNUSED and including the declaration
in javascript:
var text = "...";
var regex = /^UNUSED[^{]*?{[^}]*}[\r\n ]*/gm;
console.log(text.replace(regex, ''));
You should be more specific about regex and css. Are you trying to run some command in cmd/sh to remove these entries from file, or you are trying to do that from you code?

Sass variable in quotes for href

I'm struggling with a project. I'm using the selector [href*=#{web}] on a variable that I use multiple times on an each loop. The purpose on the each loop is to go through the links on a navigation bar and give a font icon to those that align with social media platforms. The variable that is being run through are things like twitter, facebook, linkedin, and I'm trying to use it to call the url and set up the mixin included. My big problem is that everytime I try to quote the variable $web to get it to show up as a link for the css, it stops parsing the variable and becomes something like "#{$web}" in the compiled css file. What can I do to make variable compile but still quote for href?
So, something like:
$sites: ("twitter.com", "facebook.com", "linkedin.com");
#each $site in $sites {
a[href*="#{$site}"] {
background-image: url("/images/" + $site + ".png");
}
}
Results in:
a[href*="twitter.com"] {
background-image: url("/images/twitter.com.png");
}
a[href*="facebook.com"] {
background-image: url("/images/facebook.com.png");
}
a[href*="linkedin.com"] {
background-image: url("/images/linkedin.com.png");
}
Try this as your selector:
[href*="#{$web}"]
Based on some brief research, it looks like the dollar sign forces the variable value to be output.

Is there a CSS optimizer that will discover identical single properties in selectors and group them together?

Here is an example of what I'd expect:
Input:
a {
background: red;
}
p {
background: red;
}
strong {
background: red;
color: green;
}
Output:
strong{color:green;}
a,p,strong{background:red;}
Most optimisers will output something like this:
strong{background:red;color:green;}
a,p{background:red;}
Notice how it hasn't picked up the fact that strong, although it contains color: green;, also contains background: red; thus it can be grouped with the others?
Any help you could provide would be greatly appreciated
All the best
Iain
Maybe CSSTidy could help, here.
If you take a look at this CSS "before", you'll see this portion of code :
a:hover{
color: #DD6900;
}
a.admin:hover,a.mod:hover{
color: #DD6900;
}
In in the CSS "after", you'll get :
a:hover,a.admin:hover,a.mod:hover,a.topictitle:hover {
color:#DD6900
}
Not sure it'll deal with every possible case -- but in some situations, it seems it's doing what you're asking ;-)
Okay, so it seems like what I was after either doesn't exist or is very hard to come by, so I wrote a script that solves my particular problem. I'm pasting it here in the hope that someone sometime might find it useful.
<?php
$css = file_get_contents('test.css');
//Strip comments and whitespace. Tabs to spaces
$css = preg_replace("/\s{2,}/e", ' ', $css);
$css = preg_replace("/\/\*.*?\*\//", '', $css);
$css = str_replace("\t", " ", $css);
$css = str_replace(": ", ":", $css);
$css = str_replace(" }", "}", $css);
$css = str_replace("{", "{", $css);
$css = str_replace(";}", "}", $css);
//Break each rule out onto a new line
$css = preg_replace("/}\s*/", "}\r\n", $css);
//Break # rules out onto new lines
$css = preg_replace('/(#.*?;\s*)/', '\0'."\r\n", $css);
//Parse CSS Rules
$parsed = array();
$css = explode("\r\n", $css);
foreach($css as $line => $rule){
if (preg_match('/(.*?)\{(.*?)\}/i', $rule, $regs)) {
$clean_selectors = preg_replace('/\s*,\s*/', ',', $regs[1]);
$clean_selectors = preg_replace('/,\s*$|\s$/', '', $clean_selectors);
$parsed[$line]['selectors'] = explode(',', $clean_selectors);
$parsed[$line]['properties'] = explode(';', $regs[2]);
} elseif(trim($rule) != '') {
$parsed[$line] = $rule;
}
}
//Group CSS by property
$groups = array();
foreach($parsed as $line => $css){
if(is_array($css)){
foreach($css['properties'] as $pline => $property){
if(isset($groups[$property])){
$groups[$property] = array_merge($groups[$property], $css['selectors']);
} else {
$groups[$property] = $css['selectors'];
}
}
} else {
$groups[$line] = $css;
}
}
//Output CSS sorted by property
foreach($groups as $property => $selectors){
if(is_array($selectors)){
asort($selectors);
echo implode(",\r\n", $selectors)." {\r\n\t".trim($property).";\r\n}\r\n\r\n";
} else {
echo $selectors."\r\n\r\n";
}
}
?>
Now, a couple of cavaets.
No, this is not the most beautiful code in the world, it was done quickly to solve one particular problem I was having once and it's tailored pretty heavily to the CSS I've been given to work with. That said, it should be generic enough to work with most CSS you throw at it.
It is the nature of CSS that sometimes the order in which a rule appears is important to the rendering of the final document. It is likely that if you just run all your CSS through this script that your page won't render as you expect anymore. I'm just using this script to group page-specific css on a web application that I have no layout control over. As each rule applies to a particular element on a particular page, I'm not expecting huge amounts of dodgyness when I group in this way - it's just going to make the CSS more maintainable.

Automatic CSS Preview Generator - Have css file, want to automatically generate html to preview styles

I have a fairly large CSS file developed by my web designer.
There are, of course, plenty of IDs, classes and tag properties assigned therein. Are there any tools to automatically generate HTML based on a CSS source file?
For example:
#basicInfoHead{
background:url(../images/leftHeaders.jpg) no-repeat;
margin-left: 0px;
width:185px;
height:28px;
}
#basicInfoHead span{
float: left;
}
Would generate
<div id=basicInfoHead><span>#basicInfoHead span</span></div>
Etc etc.
From there, I could preview the generated code in my browser, and see what each of the individual (primarily text) styles would look like.
Thanks in advance!
This doesn't sound really applicable to a real world stylesheet. Your example is straightforward enough (even though it would have to be a div#basicInfoHead for any generator to know what to generate) but what if it becomes more complicated? What about elements that get defined in different was for multiple pages? What about elements that need to be on top of element x, or that need an element y directly following to look well? What about "incomplete" classes e.g. for a <table><tr><th> series that doesn't define anything for the tr? What about specific rules for combined classes .class1.class2.class3?
In the list of style sheets I've been working on, there is not one that could be turned into sensible HTML code by a generator like the one you are looking for. Not sure whether a tool like this exists.
Your designer should be delivering HTML for you to test the CSS. That's the usual way and as far as I can see, the only way that really makes sense.
Here we go. I'm making several assumptions that will only hold because my designer uses a certain style:
Everything is a div
I only want to see text styles, so I'll ignore anything that doesn't seem text-related
Not my best stuff, but it works for the majority of my styles. Had to manually edit a few tags, such as ul, ol, li, and remove 'body'.
#!/usr/bin/perl
use warnings;
use strict;
my $css;
open(FILE, '<', 'styles.css') or die();
while (<FILE>) { $css .= $_; }
close(FILE);
my (#css) = $css =~ m/^([a-zA-Z.#][^\n\r]+{.+?})/gmxs;
my #text_css = grep { /\s(h[1-5]|span|font|color|p|a|ol|ul)\b/ } #css;
foreach my $css(#text_css) {
my ($selector_text) = $css =~ /^([^{]*){/;
my (#selector) = split(/[\s{]/,(split(/[\n\r]+/,$selector_text))[0]);
#selector = grep { !/{/ } #selector;
my $start_html = '';
my $middle_html = join(" ",#selector);
my $end_html = '';
my $result = '';
for (my $i=0; $i< scalar(#selector); $i++) {
$selector[$i] =~ s/:[-\w]+//g;
if (substr($selector[$i],0,1) eq '#') {
$selector[$i] =~ s/^#//g;
$start_html .= qq(<div id="$selector[$i]">);
$end_html = "</div>" . $end_html;
}
elsif (substr($selector[$i],0,1) eq '.') {
$selector[$i] =~ s/^\.//g;
$start_html .= qq(<div class="$selector[$i]">);
$end_html = "</div>" . $end_html;
}
else {
# we have a tag, possibly with an id/class
my($tag,$extra,$type);
if ($selector[$i] =~ m/\./) {
($tag,$extra) = split('.', $selector[$i]);
$extra =~ s/^\.//g;
$type = 'class';
}
elsif ($selector[$i] =~ m/#/) {
($tag,$extra) = split('#', $selector[$i]);
$extra =~ s/^#//g;
$type = 'id';
}
else {
$tag = $selector[$i];
}
if ($extra and $type) {
$start_html .= qq(<$tag $type="$extra">);
}
else {
$start_html .= qq(<$tag>);
}
$end_html = "</$tag>" . $end_html;
}
# is this the last one?
if ($i == scalar(#selector) - 1) {
$result = $start_html . $middle_html . $end_html;
}
print "<div>$result</div>\n" if ($result);
}
}
A python-based CSS preview generator: https://github.com/glowinthedark/css_stylesheet_preview_generator
Depends on cssutils (install with pip3 install cssutils).
Usage:
python3 css_preview_generator.py mystyle.css > preview.html

Resources