Javascript, CSS: Get Element by Style Attribute

Javascript, CSS: Get element by style attribute

My suggestion is avoid doing this if at all remotely possible. Instead, use a class to assign the color value, and then you can look up the elements using the class, rather than the color value.

As far as I'm aware, there's no selector (not even in CSS3) that you can use to query a specific style value, which means looping through all elements (or it looks like you can restrict it to all elements with a style attribute) and looking at the element.style.color property. Now, the thing is, even though you write color: #333; in your style attribute, different browsers will echo it back to you in different ways. It might be #333, it might be #333333, it might be rgb(51, 51, 51), it might even be rgba(51, 51, 51, 0).

So on the whole, a very awkward exercise indeed.


Since you've said this is for a Chrome extension, you probably don't have to worry as much about multiple formats, although I'd throw in the ones that we've seen in the wild in case Chrome changes the format (perhaps to be consistent with some other browser, which has been known to happen).

But for instance:

(function() {

// Get all elements that have a style attribute
var elms = document.querySelectorAll("*[style]");

// Loop through them
Array.prototype.forEach.call(elms, function(elm) {
// Get the color value
var clr = elm.style.color || "";

// Remove all whitespace, make it all lower case
clr = clr.replace(/\s/g, "").toLowerCase();

// Switch on the possible values we know of
switch (clr) {
case "#333":
case "#333333":
case "rgb(51,51,51)": // <=== This is the one Chrome seems to use
case "rgba(51,51,51,0)":
elm.style.color = "#444";
break;
}
});
})();

Live example using red for clarity | source - Note that the example relies on ES5 features and querySelectorAll, but as this is Chrome, I know they're there.

Note that the above assumes inline style, because you talked about the style attribute. If you mean computed style, then there's nothing for it but to loop through all elements on the page calling getComputedStyle. Other than that, the above applies.

Final note: If you really meant a style attribute with precisely the value color: #333 and not the value color:#333 or color:#333333; or color: #333; font-weight: bold or any other string, your querySelectorAll could handle that: querySelectorAll('*[style="color: #333"]'). But it would be very fragile.


From your comment below, it sounds like you're having to go through every element. If so, I wouldn't use querySelectorAll at all, I'd use recursive descent:

function walk(elm) {
var node;

// ...handle this element's `style` or `getComputedStyle`...

// Handle child elements
for (node = elm.firstChild; node; node = node.nextSibling) {
if (node.nodeType === 1) { // 1 == Element
walk(node);
}
}
}

// Kick it off starting with the `body` element
walk(document.body);

That way you don't build up large, unnecessary temporary structures. This is probably the most efficient way to walk the entire DOM of a document.

How to get an HTML element's style values in JavaScript?

The element.style property lets you know only the CSS properties that were defined as inline in that element (programmatically, or defined in the style attribute of the element), you should get the computed style.

Is not so easy to do it in a cross-browser way, IE has its own way, through the element.currentStyle property, and the DOM Level 2 standard way, implemented by other browsers is through the document.defaultView.getComputedStyle method.

The two ways have differences, for example, the IE element.currentStyle property expect that you access the CCS property names composed of two or more words in camelCase (e.g. maxHeight, fontSize, backgroundColor, etc), the standard way expects the properties with the words separated with dashes (e.g. max-height, font-size, background-color, etc).

Also, the IE element.currentStyle will return all the sizes in the unit that they were specified, (e.g. 12pt, 50%, 5em), the standard way will compute the actual size in pixels always.

I made some time ago a cross-browser function that allows you to get the computed styles in a cross-browser way:

function getStyle(el, styleProp) {
var value, defaultView = (el.ownerDocument || document).defaultView;
// W3C standard way:
if (defaultView && defaultView.getComputedStyle) {
// sanitize property name to css notation
// (hypen separated words eg. font-Size)
styleProp = styleProp.replace(/([A-Z])/g, "-$1").toLowerCase();
return defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
} else if (el.currentStyle) { // IE
// sanitize property name to camelCase
styleProp = styleProp.replace(/\-(\w)/g, function(str, letter) {
return letter.toUpperCase();
});
value = el.currentStyle[styleProp];
// convert other units to pixels on IE
if (/^\d+(em|pt|%|ex)?$/i.test(value)) {
return (function(value) {
var oldLeft = el.style.left, oldRsLeft = el.runtimeStyle.left;
el.runtimeStyle.left = el.currentStyle.left;
el.style.left = value || 0;
value = el.style.pixelLeft + "px";
el.style.left = oldLeft;
el.runtimeStyle.left = oldRsLeft;
return value;
})(value);
}
return value;
}
}

The above function is not perfect for some cases, for example for colors, the standard method will return colors in the rgb(...) notation, on IE they will return them as they were defined.

I'm currently working on an article in the subject, you can follow the changes I make to this function here.

How to get elements with certain style

You're much better off doing this with CSS, not inline styles.

<head>
<style>
/* By default, elements with class="some-class" are blue */
.some-class {
color: blue;
}

/* But if body has the class "updated", they turn black */
body.updated .some-class {
color: black;
}
</style>
<h1>Hello world!</h1>
<h2 class="some-class">This is my webpage</h2>
<a class="some-class" onClick="changeElem();">Welcome!</a><br>
<h3>Goodbye</h3>
</body>

...where changeElem is:

function changeElem() {
document.body.className += " updated";
}

Live Example | Live Source


If you're dead set on using inline styles, which is not a good idea, you can still do it easily enough:

function changeElem() {
var div, colorValue, list, index, element;

// Figure out what this browser returns for `color: Blue`
// (it might be "Blue", "blue", "rgb(0, 0, 255)",
// "rgba(0, 0, 255, 0)", "#0000FF", "#0000ff",
// or possibly others)
div = document.createElement('div');
document.body.appendChild(div);
div.innerHTML = '<span style="color: Blue;"></span>';
colorValue = div.firstChild.style.color;
document.body.removeChild(div);

// Get list of all elements that have any `style` attribute at all
list = document.querySelectorAll('[style]');

// Loop through looking for our target color
for (index = 0; index < list.length; ++index) {
element = list[index];
if (element.style.color === colorValue) {
element.style.color = "black";
}
}
}

Live Example | Live Source

Get an elements style inherited from classes *not* style attribute

Well, I don't think you can get the style directly from the stylesheets. But I think you can use below code for a workaround:

if( typeof( $('#alice').attr('style') ) != 'undefined' ) { 
$('#alice').removeAttr('style');
var aliceSheets = $('.alice').css('color');
console.log(aliceSheets);
}

If you want to get the style only without changing the style of the element then you can add the style attribute back after reading the color.

how to get style values with js

i have no idea why it says style is null.do you?

It doesnt.
It says document.getElementById('square') returns null so youre reading the property style on null which results in the error.

That happens because your script is loaded (and executed) in the head. At this point the element with the ID "square" isnt existent in the DOM yet.

Move your script to below your element (see snippet) or mark it with async defer like this: <script src="index.js" async defer></script> to make it load and execute after DOM parsing is done.

Also accessing style will only show inline styles from the style attribute so that wont get you values from your stylesheet file (or inline stylesheets).

Use computedStyleMap() (see https://developer.mozilla.org/en-US/docs/Web/API/Element/computedStyleMap) to get the actual computed styles including all stylesheets.

body {
margin: 0;
}

#square {
width: 100px;
height: 100px;
border: 1px solid #095057;
background-color: #20979e;
position: absolute;
left: 200px;
top: 200px;
}
<html>

<head>
<title>Simple Movement</title>
<meta charset="UTF-8">
</head>

<body>
<div id="square"></div>

<script>
console.log(document.getElementById('square').computedStyleMap().get('top').value);
</script>
</body>

</html>

CSS selector by inline style attribute

The inline style attribute is no different to any other HTML attribute and can be matched with a substring attribute selector:

div[style*="display:block"]

It is for this very reason however that it's extremely fragile. As attribute selectors don't support regular expressions, you can only perform exact substring matches of the attribute value. For instance, if you have a space somewhere in the attribute value, like this:

<div style='display: block'>...</div>

It won't match until you change your selector to accommodate the space. And then it will stop matching values that don't contain the space, unless you include all the permutations, ad nauseam. But if you're working with a document in which the inline style declarations themselves are unlikely to change at all, you should be fine.

Note also that this is not at all selecting elements by their actual specified, computed or used values as reflected in the DOM. That is not possible with CSS selectors.

How to find an element by style attribute?

Two problems:

  1. In your HTML there is a space between "display:" and "list-item".
  2. Your selector needs to be wrapped with quotations "".

Simply change your selector to include this space and wrap it in quotes:

$('li[style*="display: list-item"]')

JSFiddle demo.



Related Topics



Leave a reply



Submit