<html>
<head>
<title>CSS Specificity Calculator</title>
<script type="text/javascript">
function show(data) {
window.document.getElementById('code').innerHTML = data;
}
function floatdetails() {
var posY = 0;
var netscape = (navigator.appName.indexOf("Netscape") != -1);
function move(id) {
var divpos = document.getElementById ? document.getElementById(id): document.all ? document.all[id] : document.layers[id];
divpos.sP = function(y) {
this.style.top = y + "px";
};
divpos.y = posY;
return divpos;
}
window.floatdiv = function() {
var pY = netscape ? pageYOffset : document.body.scrollTop;
pos.y += (pY + posY - pos.y) / 8;
pos.sP(pos.y);
setTimeout("floatdiv()");
}
pos = move("code");
floatdiv();
}
</script>
</head>
<body>
<div align="center">
<h1>CSS specificity calculator</h1>
<?php
/*
*
* CSS specificity calculator
* Written by Stephen Ball
*
http://www.rebelinblue.com * --------------------------
* If you improve on this script
* please do let me know
*
*/
function cleanup(&$data, $value) {
$data = trim($data);
}
// Pseudo classes
$classes = array(":link", ":visited", ":hover", ":active", ":focus", ":target", ":lang", ":enabled",
":disabled", ":checked", ":indeterminate", ":root", ":nth-child", ":nth-last-child",
":nth-of-type", ":nth-last-of-type", ":first-child", ":last-child", ":first-of-type",
":last-of-type", ":only-child", ":only-of-type", ":empty", ":contains", ":not");
// Pseudo elements
$elements = array(":before", ":after", ":first-line", ":first-letter", ":selection");
// HTML tags
$tags = array("a", "abbr", "acronym", "address", "applet", "area", "b", "base", "basefont", "bgsound",
"bdo", "big", "blink", "blockquote", "body", "br", "button", "caption", "center", "cite",
"code", "col", "colgroup", "comment", "dd", "del", "dfn", "dir", "div", "dl", "dt", "em",
"embed", "fieldset", "font", "form", "frame", "frameset", "h", "h1", "h2", "h3", "h4", "h5",
"h6", "head", "hr", "html", "i", "iframe", "img", "input", "ins", "isindex", "kbd", "label",
"legend", "li", "link", "listing", "map", "marquee", "menu", "meta", "multicol", "nextid",
"nobr", "noframes", "noscript", "object", "ol", "optgroup", "option", "p", "param", "plaintext",
"pre", "q", "s", "samp", "script", "select", "server", "small", "sound", "spacer", "span",
"strike", "strong", "style", "sub", "sup", "table", "tbody", "td", "textarea", "textflow",
"tfoot", "th", "thead", "title", "tr", "tt", "u", "ul", "var", "wbr", "xmp");
// Check if form has been submitted
if (isset($_POST["css"])) {
// Strip slashes
$_POST["css"] = get_magic_quotes_gpc() ? stripslashes($_POST["css"]) : $_POST["css"];
$data = preg_replace("/\/\\*[\\s\\S]*?\\*\//", "", $_POST["css"]); // Strip comments
$data = preg_replace("/\{(.*?)\}/s", ", ", $data); // Strip content and replace with delimiter
$data = str_replace(" ,", ",", $data); // Strip spaces after selectors
$tmp = explode(",", $data); // Get rid of selector groupings
array_walk($tmp, 'cleanup'); // Trim whitespace from end of selectors
?>
<table border="1" width="760" style="margin: auto;">
<tr>
<td>
<table>
<tr align="middle">
<th width="40%">Selector</th>
<th width="5%">Score</th>
<th width="5%">Properties</th>
</tr>
<?php
// Loop through the selector array
foreach ($tmp as $var) {
$score = 0; // Set the score to 0
if (!empty($var)) {
$score += substr_count($var, '#') * 100; // Count the IDs and multiple by 100 (i.e. #itemID)
$score += substr_count($var, '.') * 10; // Count the classes and multiple by 10 (i.e. .classname)
$score += substr_count($var, '[') * 10; // Count the attributes and multiple by 10 (i.e. input[type=text])
foreach ($classes as $test) { // Count the pseudo-classes and multiple by 10
$score += substr_count($var, $test) * 10;
}
foreach ($elements as $test) { // Count the pseudo-elements and multiple by 10
$score += substr_count($var, $test);
}
$cleaned = str_replace(":", " ", $var); // Remove the pseudo selector
$cleaned = str_replace("+", " ", $cleaned); // Remove the adjacent sibling selector
$cleaned = str_replace(">", " ", $cleaned); // Remove the child selector
$cleaned = str_replace("*", " ", $cleaned); // Remove the universal selector
$cleaned = str_replace(".", " ", $cleaned); // Remove the class selector
$cleaned = str_replace("#", " ", $cleaned); // Remove the ID selector
$cleaned = explode(" ", $cleaned); // Explode on space
foreach ($cleaned as $rubbish) { // Count the type selectors (i.e. HTML tags)
if (in_array(strtolower($rubbish), $tags)) {
$score++;
}
}
// Now to find the actually properties
$code = substr($_POST["css"], strpos($_POST["css"], $var)); // Find the position of the current selector
$first = strpos($code, "{") + 1; // Get the position of the first {
$last = strpos($code, "}"); // Get the position of the first }
$code = substr($code, $first, $last - $first); // Get the content between the { and }
$code = preg_replace("/\/\\*[\\s\\S]*?\\*\//", "", $code); // Strip any comments from the properties
// Now make the data safe for javascript
$code = trim($code); // Trim the properties
$code = str_replace("\\", "\\\\", $code); // Escape any slashes
$code = str_replace("'", "\\'", $code); // Escape any apostrophes
$code = str_replace("\r\n", "<br>", $code); // Convert new lines to HTML break (Can't use nl2br as it doesn't remove the newlines)
$code = str_replace("\n", "<br>", $code);
$code = str_replace("\r", "<br>", $code);
$score = str_pad($score, 3, '0', STR_PAD_LEFT); // Pad the final score to 3 characters
$defined = substr_count($code, ":"); // Count the number of properties the selector defines
?>
<tr>
<td onmouseover="show('<?=$code;?>');" onmouseout="show('');" style="cursor: pointer;"><?=$var;?></td>
<td align="center"><?=$score;?></td>
<td align="center"><?=$defined;?></td>
</tr>
<?php
}
}
?>
</table>
</td>
<td width='50%' valign='top' style="padding: 5px;">
<center><strong>Property data</strong></center>
<div id='code' style='position: relative;'></div>
<script type='text/javascript'>floatdetails();</script>
</td>
</tr>
</table>
<p>Note: Inline styles using the HTML "styles" attribute have a score of 1000.</p>
<p><a href="specificity.php">Start over</a></p>
<?php
}
else {
?>
<p>Paste your CSS into the field below, the specificity of your selectors will be calculated for you.</p>
<h2>Current limitations</h2>
<ul>
<li>Your CSS <b>must</b> <a href="http://jigsaw.w3.org/css-validator/" title="Ensure the file is valid CSS">be valid</a> in order for the calculator to work</li>
<li>Currently only HTML elements are counted in the score, custom tags such as XML are not</li>
</ul>
<form method="post" action="specificity.php">
<textarea name="css" rows="25" cols="90"></textarea>
<br /><input type="submit" value="Calculate" />
</form>
<?
}
?>
</div>
</body>
</html>