8

I need to check a user's input to be valid CSS syntax (the input string is basically a CSS file). It can contain classes, selectors, !important etc.

I didn't start working on it, because I was hoping there is already some regex syntax out there, so I don't have to start from scratch.

I tried googling but all I've found is partial css matching strings, not a regex that validates all possible css.

5
  • 7
    I doubt regexes can do this. It's not a regular language. Commented Jan 19, 2014 at 22:23
  • Yes I did, but all the results let me to finding particular properties inside a css file, not validating a whole style sheet. Commented Jan 19, 2014 at 22:24
  • 1
    You'd be better off with a CSS parser, like: github.com/reworkcss/css-parse Commented Jan 19, 2014 at 22:25
  • 1
    First of all what language are you using ? Second, do you plan to support advanced CSS features, think about media queries, animation, transition etc ... ? Is .test{ fail:red;} valid ? Commented Jan 20, 2014 at 0:45
  • 1
    I think it's probably possible, but geesh! It would be a quite seriously complicated regex with many variations.. I think one would start with referencing this.. w3.org/TR/css3-syntax/#detailed-grammar. I would be quite impress to see someone put in the work to make a sufficient regex to validate a valid css syntax yet return false on the correct false css syntax.. Commented Jan 20, 2014 at 2:40

2 Answers 2

10

Ok, so I came up with a regex that matches valid css styles..

([#.@]?[\w.:> ]+)[\s]{[\r\n]?([A-Za-z\- \r\n\t]+[:][\s]*[\w .\/()\-!]+;[\r\n]*(?:[A-Za-z\- \r\n\t]+[:][\s]*[\w .\/()\-!]+;[\r\n]*(?2)*)*)}

Working example here:

http://regex101.com/r/fK9mY3

Keep in mind.. After examining my example link above, you see this regex works for common, basic CSS2 styling, however, to match ALL CSS3 styling variations, pertaining to http://www.w3.org/TR/css3-syntax/#detailed-grammar, this regex would need some tweaking... The above regex IS a starting point however..

Sign up to request clarification or add additional context in comments.

4 Comments

Doesn't allow for full URLs within url()
That is the trap of regular expressions: their complexity is great though unless you can account for all conditions...and worse yet since standards are still evolving the older this answer gets the less valid it becomes. Great effort though this should have been written as a full function with easy-to-update if conditions.
@John, yes completely agree. The regex was meant as a starting point and because CSS standards are constantly evolving, the a better solution would be to incorporate this regex along with some some other regex matches for edge cases and wrapped up into a JS library of sorts. It would need to be constantly maintained, of course.
@BryanElliott using the changes to this by duality in his answer below, I also made some changes in a comment under his answer, I have one final issue to solve to be happy with my use case for this, any chance you know how to solve it please? Thanks
3

Adding to Bryan's answer. And adding a note

  • javascript support: there was an error with the (?2)
  • multiple classes: .class, .class2 {...}
  • class delimeters: .class-name, .class_name
  • empty class: .class {}
  • percentages: width: 100%;
  • quoted urls: background: url("/img.jpg");
const multi = /((?:^\s*)([\w#.@*,:\-.:>,*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,\/()\-!%]+;?)*)*\s*}(?:\s*))/mi

const example = `
div.css-class-10_9::hover, .active {
  width: 100%;
  background: rgba(1.0,0,1,1); 
  background-url: url("http://img.jpg");   
}

div.css-class-10_9::hover,
.active {
  width: 100%;
  background: rgba(1.0,0,1,1);
  background-url: url("http://img.jpg");
}

html {
  background: white;
}
`

let out = example.replace(multi, '')
// "
// div.css-class-... {...}
// html {...}
// "

out = out.replace(multi, '')
// "html {...}"

out = out.replace(multi, '')
// ""

You can also add global to replace all at once

const global_re = /((?:^\s*)([\w#.@*,:\-.:>,*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,\/()\-!%]+;?)*)*\s*}(?:\s*))/gmi


example.replace(global_re, '');
// ""


example.replace(global_re,'$1') // group 1 all css
//
// div.css-class-...{
//   width...
//   rest_css...
// }
//
// ...
//
// html {
//   ...
// }

Class Names

example.replace(global_re,'$2\n\n') // group 1 all class names
// "
// div.css-class-10_9::hover, .active 
// 
// div.css-class-10_9::hover,
// .active 
// 
// html  
// "

Class bodies (replace everything but class bodies)

example.replace(global_re,'$3\n')
// "
// width: 100%;
// background: rgba(1.0,0,1,1); 
// background-url: url("http://img.jpg");   
// 
// 
// width: 100%;
// background: rgba(1.0,0,1,1);
// background-url: url("http://img.jpg");
// 
// 
// background: white;
// 
// "

https://regex101.com/r/fK9mY3/55

(Disclaimer: this definitely doesn't validate css)

ex: '............a {}' comes out true

1 Comment

To "improve" on this, I added some more selector options (+ and ~) and removed the ^ for the start of the line before a selector, which allows any minified css, with no whitespace between, can still be selected. I'm not very knowledgeable with regex at all, so there may be problems with this, however I thought I would share. ((?:\s*)([\w#.@*,:\-.:>+~\[\]\"=(),*\s]+)\s*{(?:[\s]*)((?:[A-Za-z\- \s]+[:]\s*['"0-9\w .,\/\()\-!#%]+;?)*)*\s*}(?:\s*)) The only issue I have now is with base64 data inside url's. It fails at ";" within the style value. After adding this character, it times out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.