Skip to content

Instantly share code, notes, and snippets.

@sehrgut
Last active August 29, 2015 14:03
Show Gist options
  • Save sehrgut/77233df47b17a3bc9257 to your computer and use it in GitHub Desktop.
Save sehrgut/77233df47b17a3bc9257 to your computer and use it in GitHub Desktop.
jQuery plugin to find elements based on computed CSS styles
/*
jquery.withStyles.js - jQuery plugin to find elements based on computed CSS styles
Copyright (C) 2014 Keith Beckman
Released under the GPLv3
## Usage
* Returns collection of all `a` tags with computed styles matching the CSS declaration
* `$('a:withStyles("font-style: bold; color: #FFFFFF;")')`
* `$('a').filter(':withStyles("font-style: bold; color: #FFFFFF;")')`
* `$('a').withStyles("font-style: bold; color: #FFFFFF;")`
* Returns a collection of all `a` tags with computed styles matching the provided map of CSS properties and values
* `$('a').withStyles({ fontStyle: "bold", color: "#FFFFFF" })`
* `$('a').withStyles({ "font-style": "bold", "color": "#FFFFFF" })`
* Returns `boolean` indicating if the selected element matches the provided styles
* `$('a').first().hasStyles("font-style: bold; color: #FFFFFF;")`
* `$('a').first().hasStyles({ fontStyle: "bold", color: "#FFFFFF" })`
* `$('a').first().hasStyles({ "font-style": "bold", "color": "#FFFFFF" })`
## Notes
This may not function in all older browsers. It depends on the existence of a
DOM Level 2-compliant implementation of `CSSStyleDeclaration` to walk explicit
CSS properties of a dummy DOM element.
Using the browser-native parser is necessary to permit matching of values which
have multiple semantically-equivalent representations, but which may be handled
differently by different browsers (such as colour literals).
## TODO
* Allow determination of style of text nodes (nodeType === 3) to avoid exceptions
when working on the results of jQuery.contents(). Probably take the direct
parent's style? (Or a setting: `ignoreTextNodes`, default to `false`.)
*/
(function ($) {
function isString (o) {
return (typeof o === 'string' || o instanceof String);
}
function getExplicitStyles (el) {
var out = {};
for (var i=0, n=el.style.length; i<n; i++) {
var prop = el.style[i];
out[prop] = el.style[prop];
}
return out;
}
var parseCssDeclaration = (function () {
var $span = $('<span />');
return function (css) {
return getExplicitStyles($span.attr('style', css)[0]);
};
})();
var compareStyle = (function () {
var jq = $([1]);
return function (el, props) {
jq[0] = el;
for (var prop in props)
if (jq.css(prop) !== props[prop])
return false;
return true;
};
})();
$.fn.hasStyles = function (styles) {
var props = isString(styles) ? parseCssDeclaration(styles) : styles;
return this.length === 1 && compareStyle(el, props);
};
$.fn.withStyles = function (styles) {
var props = isString(styles) ? parseCssDeclaration(styles) : styles;
return this.filter(function (i, el) {
return compareStyle(el, props);
});
};
var Sizzle = $.find;
Sizzle.selectors.pseudos['withStyles'] = Sizzle.selectors.createPseudo ?
Sizzle.selectors.createPseudo(function (css) {
var props = parseCssDeclaration(css);
return function (el) {
return compareStyle(el, props);
};
}) :
function (el, i, meta, stack) {
var props = parseCssDeclaration(meta[3]);
return compareStyle(el, props);
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment