CSSLint.Util.forEach(this.ignore, function (range) {
if (range[0] <= line && line <= range[1]) {
type : this.ruleset[rule.id] === 2 ? "error" : "warning",
evidence: this.lines[line-1],
* Report some informational text.
* @param {String} message The message to store.
* @param {int} line The line number.
* @param {int} col The column number.
* @param {Object} rule The rule this message relates to.
info: function(message, line, col, rule) {
evidence: this.lines[line-1],
* Report some rollup error information.
* @param {String} message The message to store.
* @param {Object} rule The rule this message relates to.
rollupError: function(message, rule) {
* Report some rollup warning information.
* @param {String} message The message to store.
* @param {Object} rule The rule this message relates to.
rollupWarn: function(message, rule) {
* @param {String} name The name of the stat to store.
* @param {Variant} value The value of the stat.
stat: function(name, value) {
this.stats[name] = value;
// expose for testing purposes
CSSLint._Reporter = Reporter;
* Utility functions that make life easier.
* Adds all properties from supplier onto receiver,
* overwriting if the same name already exists on
* @param {Object} The object to receive the properties.
* @param {Object} The object to provide the properties.
* @return {Object} The receiver
mix: function(receiver, supplier) {
if (supplier.hasOwnProperty(prop)) {
receiver[prop] = supplier[prop];
* Polyfill for array indexOf() method.
* @param {Array} values The array to search.
* @param {Variant} value The value to search for.
* @return {int} The index of the value if found, -1 if not.
indexOf: function(values, value) {
return values.indexOf(value);
for (var i=0, len=values.length; i < len; i++) {
if (values[i] === value) {
* Polyfill for array forEach() method.
* @param {Array} values The array to operate on.
* @param {Function} func The function to call on each item.
forEach: function(values, func) {
return values.forEach(func);
for (var i=0, len=values.length; i < len; i++) {
func(values[i], i, values);
* Rule: Don't use adjoining classes (.foo.bar).
name: "Disallow adjoining classes",
desc: "Don't use adjoining classes.",
url: "https://github.com/CSSLint/csslint/wiki/Disallow-adjoining-classes",
init: function(parser, reporter) {
parser.addListener("startrule", function(event) {
var selectors = event.selectors,
for (i=0; i < selectors.length; i++) {
for (j=0; j < selector.parts.length; j++) {
part = selector.parts[j];
if (part.type === parser.SELECTOR_PART_TYPE) {
for (k=0; k < part.modifiers.length; k++) {
modifier = part.modifiers[k];
if (modifier.type === "class") {
reporter.report("Adjoining classes: "+selectors[i].text, part.line, part.col, rule);
* Rule: Don't use width or height when using padding or border.
name: "Beware of broken box size",
desc: "Don't use width or height when using padding or border.",
url: "https://github.com/CSSLint/csslint/wiki/Beware-of-box-model-size",
init: function(parser, reporter) {
for (prop in heightProperties) {
if (heightProperties.hasOwnProperty(prop) && properties[prop]) {
value = properties[prop].value;
// special case for padding
if (!(prop === "padding" && value.parts.length === 2 && value.parts[0].value === 0)) {
reporter.report("Using height with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
for (prop in widthProperties) {
if (widthProperties.hasOwnProperty(prop) && properties[prop]) {
value = properties[prop].value;
if (!(prop === "padding" && value.parts.length === 2 && value.parts[1].value === 0)) {
reporter.report("Using width with " + prop + " can sometimes make elements larger than you expect.", properties[prop].line, properties[prop].col, rule);
parser.addListener("startrule", startRule);
parser.addListener("startfontface", startRule);
parser.addListener("startpage", startRule);
parser.addListener("startpagemargin", startRule);
parser.addListener("startkeyframerule", startRule);
parser.addListener("startviewport", startRule);
parser.addListener("property", function(event) {
var name = event.property.text.toLowerCase();
if (heightProperties[name] || widthProperties[name]) {
if (!/^0\S*$/.test(event.value) && !(name === "border" && event.value.toString() === "none")) {
line: event.property.line,
if (/^(width|height)/i.test(name) && /^(length|percentage)/.test(event.value.parts[0].type)) {
} else if (name === "box-sizing") {
parser.addListener("endrule", endRule);
parser.addListener("endfontface", endRule);
parser.addListener("endpage", endRule);
parser.addListener("endpagemargin", endRule);
parser.addListener("endkeyframerule", endRule);
parser.addListener("endviewport", endRule);
* Rule: box-sizing doesn't work in IE6 and IE7.
name: "Disallow use of box-sizing",
desc: "The box-sizing properties isn't supported in IE6 and IE7.",
url: "https://github.com/CSSLint/csslint/wiki/Disallow-box-sizing",
init: function(parser, reporter) {
parser.addListener("property", function(event) {
var name = event.property.text.toLowerCase();
if (name === "box-sizing") {
reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
* Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE
* (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)
id: "bulletproof-font-face",
name: "Use the bulletproof @font-face syntax",
desc: "Use the bulletproof @font-face syntax to avoid 404's in old IE (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax).",
url: "https://github.com/CSSLint/csslint/wiki/Bulletproof-font-face",
init: function(parser, reporter) {
// Mark the start of a @font-face declaration so we only test properties inside it
parser.addListener("startfontface", function() {
parser.addListener("property", function(event) {
// If we aren't inside an @font-face declaration then just return
var propertyName = event.property.toString().toLowerCase(),
value = event.value.toString();
// Set the line and col numbers for use in the endfontface listener
// This is the property that we care about, we can ignore the rest
if (propertyName === "src") {
var regex = /^\s?url\(['"].+\.eot\?.*['"]\)\s*format\(['"]embedded-opentype['"]\).*$/i;
// We need to handle the advanced syntax with two src properties
if (!value.match(regex) && firstSrc) {
} else if (value.match(regex) && !firstSrc) {
// Back to normal rules that we don't need to test
parser.addListener("endfontface", function() {
reporter.report("@font-face declaration doesn't follow the fontspring bulletproof syntax.", line, col, rule);
* Rule: Include all compatible vendor prefixes to reach a wider
id: "compatible-vendor-prefixes",
name: "Require compatible vendor prefixes",
desc: "Include all compatible vendor prefixes to reach a wider range of users.",
url: "https://github.com/CSSLint/csslint/wiki/Require-compatible-vendor-prefixes",
init: function (parser, reporter) {
arrayPush = Array.prototype.push,
// See http://peter.sh/experiments/vendor-prefixed-css-property-overview/ for details
"animation-delay" : "webkit",
"animation-direction" : "webkit",
"animation-duration" : "webkit",
"animation-fill-mode" : "webkit",
"animation-iteration-count" : "webkit",
"animation-name" : "webkit",
"animation-play-state" : "webkit",
"animation-timing-function" : "webkit",
"appearance" : "webkit moz",
"border-end" : "webkit moz",
"border-end-color" : "webkit moz",
"border-end-style" : "webkit moz",
"border-end-width" : "webkit moz",
"border-image" : "webkit moz o",
"border-radius" : "webkit",
"border-start" : "webkit moz",
"border-start-color" : "webkit moz",
"border-start-style" : "webkit moz",
"border-start-width" : "webkit moz",
"box-align" : "webkit moz ms",
"box-direction" : "webkit moz ms",
"box-flex" : "webkit moz ms",
"box-lines" : "webkit ms",
"box-ordinal-group" : "webkit moz ms",
"box-orient" : "webkit moz ms",
"box-pack" : "webkit moz ms",
"column-count" : "webkit moz ms",
"column-gap" : "webkit moz ms",
"column-rule" : "webkit moz ms",
"column-rule-color" : "webkit moz ms",
"column-rule-style" : "webkit moz ms",
"column-rule-width" : "webkit moz ms",
"column-width" : "webkit moz ms",
"line-break" : "webkit ms",
"margin-end" : "webkit moz",
"margin-start" : "webkit moz",
"marquee-speed" : "webkit wap",
"marquee-style" : "webkit wap",
"padding-end" : "webkit moz",
"padding-start" : "webkit moz",
"text-size-adjust" : "webkit ms",
"transform" : "webkit ms",
"transform-origin" : "webkit ms",
"transition-duration" : "",
"transition-property" : "",
"transition-timing-function" : "",
"user-modify" : "webkit moz",
"user-select" : "webkit moz ms",
"word-break" : "epub ms",
"writing-mode" : "epub ms"
for (prop in compatiblePrefixes) {
if (compatiblePrefixes.hasOwnProperty(prop)) {
prefixed = compatiblePrefixes[prop].split(" ");
for (i = 0, len = prefixed.length; i < len; i++) {
variations.push("-" + prefixed[i] + "-" + prop);