The question is simple; using jQuery's css
function, the computed style of a CSS attribute may be returned, but what if there are more than one style for that attribute being rendered? For example :
<div id="foo" style="text-decoration:underline;">Some underline text</div>
The instruction $('#foo').css('text-decoration');
will return underline
. Now if I change it to
<div id="foo" style="text-decoration:underline;">Some underline <span id="bar" style="text-decoration:line-through;">text</span></div>
The instruction $('#bar').css('text-decoration');
will return line-through
, alright.
But the actual text is also underline
! How can I return both? Do I need to search all ancestors if I want to know if some text is both underline
and line-through
? Sounds a bit painful, no?
** Edit **
Another problem arises whith this HTML
<span style="text-decoration:underline;">some <span id="e1" style开发者_开发问答="font-weight:bold;">text</span></span>
where $('#e1').css('text-decoration');
returns none
for some reason, while the text is clearly rendered with an underline.
** Disclaimer **
This question is not to debate how the UA renders an element, but if an element hierarchy applies a CSS or not. If one wants to understand text-decoration
better, I suggest one would read about it. The question tries to focus on a more generalize matter. For example, it can also apply to this HTML
<div style="display:none;">Some <span id="keyword" style="text-decoration:underline;">hidden</span> text</div>
where one could want to know if the element keyword
is visible or not. With the code below, this is simply done with
cssLookup($('#keyword'), 'display', 'none'); // -> true
** UPDATE **
After all the answers and comments, here is, based on Brock Adams solution :
/**
* Lookup the given node and node's parents for the given style value. Returns boolean
*
* @param e element (jQuery object)
* @param style the style name
* @param value the value to look for
* @return boolean
*/
function cssLookup(e, style, value) {
var result = (e.css(style) == value);
if (!result) {
e.parents().each(function() {
if ($(this).css(style) == value) {
result = true;
return false;
}
});
}
return result;
}
Thank you, everyone, for your inputs.
I don't think any browser, or the W3C, provides a good way to do this.
A complicating factor is knowing which styles cancel preceding styles (underline versus no-underline, for example).
So, we would need multiple look-up tables or human judgement to know which style actually applied.
Finally, all these methods (3 answers so far) cannot distinguish between a blank, or missing, style setting and an explicitly set none
. Obviously the browser can render an explicitly set none
differently than a blank or missing setting.
For human use, this code should do the trick:
function cssTree (jNode, styleName, bShowBlanks) {
var styleArray = [jNode.css (styleName)];
jNode.parents ().map ( function () {
var style = $(this).css (styleName);
if (bShowBlanks || ! /^(none|\s*)$/i.test (style) )
styleArray.push (style);
} );
return styleArray;
}
alert ( cssTree ( $("#bar"), 'text-decoration') );
See it in action at jsFiddle.
Results:
bar: line-through,underline
el: none,underline
//-- With bShowBlanks = true.
bar: line-through,underline,none,none
el: none,underline,none,none
Ok, this is not the easy, elegant answer you're looking for, but I have a working option here: http://jsfiddle.net/nrabinowitz/Uu6p3/1/
It's similar to @Thor's in concept, but uses built-in jQuery functions to find all ancestors, map their text-decoration
styles into an array, filter for unique values not equal to "none"
, and return the array of styles:
/**
* Generic function to find all values for
* CSS settings that allow multiple values.
*
* @param {String} selector JQuery selector
* @param {String} attr CSS attribute to look for
* @param {String[]} ignore Values to ignore
*/
function findAllCssValues(selector, attr, ignore) {
var temp = {};
ignore = ignore || ['none'];
return $.grep(
// create the array of all values
$(selector)
// select element and all ancestors
.parents().andSelf()
// put all css attribute results into an array
.map(function() {
return $(this).css(attr)
})
// make it a regular Javascript array
.toArray(),
// now filter for unique values that aren't "none"
function(val) {
if (val in temp || $.inArray(val, ignore) >= 0) {
return false;
}
temp[val] = true;
return true;
}
);
}
findAllCssValues('#bar', 'text-decoration');
It works for all of your example snippets, as shown in the fiddle. I made it work for any CSS property, though I'm not sure this issue applies to anything but text-decoration
.
Here's a possible solution:
function getVisualCSS(tag, elem){
var styles = [];
var thisStyle = $(elem).css(tag);
if(thisStyle != 'none') styles.push(thisStyle);
while($(elem).parent()[0].tagName != 'BODY'){
styles.push($(elem).parent().css(tag));
elem = $(elem).parent();
}
styles.push($(elem).parent().css(tag));
return $.unique($.grep(styles, function(n){
return n != 'none';
}));
}
What it does is, that it checks all of an elements ancestors for a given CSS tag.
For the sake of an "cleaner" array, all none
values are removed and only unique values are returned.
Here's a fiddle: http://jsfiddle.net/nslr/bXx46/2/
If you try to set the inner span to text-decoration:none
you'll notice the underline is still rendered from the parent div. The issue is that text-decoration doesn't inherit, but it's rendered as if it does.
So any text element will render the combination of all of its parents' text-decorations, even if it or any of its parents have text-decoration set to none.
If you want to know all of the text-decorations that have been applied to the text, you need to walk the chain right up to the top and record the combination of all decorations you encounter, excluding "none". Here's an example:
http://jsfiddle.net/fSESn/4/
function findDecoration( elem ) {
var $elem = $(elem);
var found = new Array();
var dec = "";
var current = $elem.css('text-decoration');
if ( current != 'none' ) {
found[ current ] = 1;
dec = current;
}
var p = $elem.parent();
while ( p != null && p.get(0).nodeName.toLowerCase() != 'body' ) {
current = p.css('text-decoration');
if ( current != 'none' && found[ current ] == null ) {
found[ current ] = 1;
dec = current + " " + dec;
}
p = p.parent();
}
return dec;
}
精彩评论