Is there a JS way to determine the value in effect for an attribute of an element?
It is well understood that there is a precedence from referenced CSS files in order of declaration through embedded CSS and values defined in the style attribute of an element, with the most recent/most local taking effect.
Browser element inspection tools make it possible to determine the value in effect for an element styling attribute like (for example) background-color.
Is there a way to discover the value in effect programmatically?
I have used a canvas and js to creates what amounts to image maps with hover and click visual feedback, and I would love to make this respond to CSS styling on the canvas.
For example, if the canvas color is set to red then red should be the base color for hover highlights and selection marking.
At the moment this is all done by changing the values of "constants", but responding to CSS would be... elegant.
You can determine the current effective style by using window.getComputedStyle(). It returns an exotic array-like object that has all active style properties as well as some helper functions. To use:
var el = document.getElementById('el1');
var computedStyle = window.getComputedStyle(el);
document.getElementById('style').innerHTML = computedStyle.cssText;
#el1 {
background-color: blue;
}
div:first-of-type {
height: 50px;
}
<div id="el1"></div>
<hr>
<div id="style"></div>
Related
I am trying to create a Chrome extension with a floating widget. To do that, I have to isolate my element from the rest of the page. Shadow DOM looks like a perfect fit for that, but it isn't doing what I expected.
Here is my content script:
content.js
var lightDom = document.createElement('style');
lightDom.innerText = 'div { color: red }';
document.body.appendChild(lightDom);
var shadowDom = document.createElement('div');
document.body.appendChild(shadowDom);
var shadowRoot = shadowDom.attachShadow({'mode': 'open'});
shadowRoot.innerHTML = `
<style>
div {
background-color: blue;
}
</style>
<div>Shadow!</div>
`;
The div inside the shadow DOM should have black text, but it has red text instead. Am I doing something wrong?
Why is this happening?
CSS selectors in Light DOM are prevented from reaching elements inside shadow DOM. But when a CSS property has the value inherit, which is the default value of color, the shadow DOM will still inherit those from the light DOM.
From the CSS Scoping specification
3.3.2 Inheritance
The top-level elements of a shadow tree inherit from their host element.
The elements in a distribution list inherit from the parent of the content element they are ultimately distributed to, rather than from their normal parent.
How to prevent it from happening?
You can prevent the values of properties form being inherited by using the initial value.
From the CSS Cascading and Inheritance specification
7.3.1. Resetting a Property: the initial keyword
If the cascaded value is the initial keyword, the property’s initial value becomes its specified value.
The initial value of each property is documented in the specification it is defined in. color is documented in the CSS Color specification and its initial value is depends on user agent, for most user agents this will be black.
You can assign initial to each property you don't want to inherit its value. Or you can set the value of all to initial, like so:
.selector
{
all: initial;
}
The all property is defined as follows in the same spec as the initial keyword.
3.1. Resetting All Properties: the all property
The all property is a shorthand that resets all CSS properties except direction and unicode-bidi. It only accepts the CSS-wide keywords.
"CSS-wide keywords" is defined in CSS 3 values specification in section 3.1.1, but comes down to the values initial, inherit and unset.
I have this HTML page:
document.addEventListener("DOMContentLoaded", function (event) {
var inner_div = document.getElementById("innerDiv");
console.log(getComputedStyle(inner_div, null)["backgroundColor"]);
});
#outterDiv {
background-color: papayawhip;
}
<div id="outterDiv">
<div id="innerDiv">
I am an inner div
</div>
</div>
I want to find out the computed background color of the inner div without having to look into parent(s) element's computed style. Is that possible?
Solution
Here's some vanilla js that will get the effective background color for a given element:
function getInheritedBackgroundColor(el) {
// get default style for current browser
var defaultStyle = getDefaultBackground() // typically "rgba(0, 0, 0, 0)"
// get computed color for el
var backgroundColor = window.getComputedStyle(el).backgroundColor
// if we got a real value, return it
if (backgroundColor != defaultStyle) return backgroundColor
// if we've reached the top parent el without getting an explicit color, return default
if (!el.parentElement) return defaultStyle
// otherwise, recurse and try again on parent element
return getInheritedBackgroundColor(el.parentElement)
}
function getDefaultBackground() {
// have to add to the document in order to use getComputedStyle
var div = document.createElement("div")
document.head.appendChild(div)
var bg = window.getComputedStyle(div).backgroundColor
document.head.removeChild(div)
return bg
}
Then you can call it like this:
var myEl = document.getElementById("a")
var bgColor = getInheritedBackgroundColor(myEl)
Demo in jsFiddle
Explanation
The solution works by checking the resolved value for a particular element. If the background is transparent, it'll start over again with the element's parent until it finds a defined color or reaches the top.
There are two main concepts to be familiar with:
How background-color is set?
How resolved values work?
According to MDN, background-color has an initial value of transparent and is not an inherited property. Meaning even if a parent div has a color applied, any unstyled child div will have a background-color of transparent. Most browsers, will convert this to an rgb color space so will return the value of rgba(0,0,0,0) with the alpha channel / transparency set to 0%.
This distinction may seem trivial, but it's important to understand that most divs on a page are probably transparent. They do not paint any colors, they just don't mask parent elements. If background values were inherited, colors with transparency would stack and get stronger on child elements
According to MDN, resolved values are what is returned by the browser from .getComputedStyle() which includes computed values and used values. Using the resolved value helps handle special values like inherit, initial, etc. and coverts any relative values to absolute values. Plus also provides a consistent API for getting styling info from attributes vs those applied via stylesheets.
So window.getComputedStyle() isn't used to determine the color that appears in the background; it's just there to get the actual value for the div. And then we'll traverse up the DOM tree until we find an actual value.
Further Reading
MDN - Color Value
MDN - background-color
MDN - .getComputedStyle()
SO - How to get the background color of an HTML element?
SO - Getting the real background-color of an element?
SO - How do I detect the inherited background-color of an element using JS?
SO - getComputedStyle gives "transparent" instead of actual background color
SO - How do I get the element's background color in JavaScript?
You apparently mean to ask
How do I find the background color for some element which is used by virtue of that color being set as the background color of some ancestor which shows through because all intervening elements having transparent background color?
However, your question is confusing because you are using the word "inherited", which has a very specific meaning in CSS, which is not relevant here.
The background-color property is not inherited in the CSS sense. Every element has its own background color, which by default is transparent.
The reason that you inner div looks like it has a papayawhip background is that actually it has a transparent background, which lets the papayawhip background of the outer div show through. There is nothing about the inner div that knows or cares about papayawhip, or that can be queried to return papayawhip.
The only way to find that the inner div is going to have a papayawhip background is to traverse the DOM tree and find the closest parent that has a non-transparent background color. This is explained in the question proposed as a dup target.
By the way, what is your underlying problem here? Why are you trying to do this? There are probably better ways.
add background-color: inherit; to your #innerDiv
document.addEventListener("DOMContentLoaded", function (event) {
var inner_div = document.getElementById("innerDiv");
console.log(getComputedStyle(inner_div, null)["backgroundColor"]);
});
#outterDiv {
background-color: papayawhip;
}
#innerDiv {
background-color: inherit;
}
<div id="outterDiv">
<div id="innerDiv">
I am an inner div
</div>
</div>
I have a single page web app in development where based on xml I render items on screen ( add and manipulate DOM elements)
As part of this I have code that fires to amend visual properties such as color, background, text size all of which works in 99% of cases. The screen has a hierarchy within the 'scriptForm' div in the page where
scriptForm div
- windows div with id #win__
-- panels div with id #pnl__
--- children from here
The background color affects everything from panels down and items don't inherit unless explicitly set to.
the windows however show rgb values in DOM explorer but the background remains white.
the code I use to manipulate the background is shown below with a9 representing the element id value;
var a9 = '#' + name;
if (background.length === 7) {
$(a9).css("background", background);
}
Can anyone suggest why I'm not able to see the effects correctly?
Have you tried using:
$(a9).css("background-color", background);
instead of
$(a9).css("background", background);
?
Try :
$(a9).css("background-color", background);
Also, you should not use inline styles. So better soution would be to assign a class instead like:
$(a9).addClass("class_name");
And in your css file create class like(EX.) :
.class_name{
background-color: #ffffff;
}
The idea is making some border-radius effect in IE 7/8, so I've decided to use jquery.corner.js library. To make it more generic I want to write some script which applies corner() function to all elements within a page having border-radius property.
For example, for this element
.someElement
{
border-radius:10px;
}
function must do the following
$(".someElement").corner("10px");
The problem is that I want to apply rounded corners to all elements, including dynamically added elements and elements which are inheriting border-radius property among some action(hover, click, etc.). Is this possible?
You need to declare a function that applies you css on every change.
To detect css style changes, see here:
Event detect when css property changed using Jquery
Then you need call that function on style change and on dom tree change (every time you append something into the page)....
I would advise you use a specific class to apply border radius css. This way you can select the rounded elements via jQuery class selectors.
You should have a generic css class that is used on all elements that have rounded borders and then use that class in your selector.
You will have to do this in a document ready handler. This will of course only apply rounded borders to elements that currently exists. If you want to cover elements loaded with ajax you can do the following:
$(document).ajaxSuccess(function(e, xhr, settings)
{
$(xhr.responseText).find(".class-that-applies-rounded-borders").corner("10px");
});
I am using jQuery monthly calender, in which every day is a cell, onClick in the cell, I am able to print the alert, but I also want to change the background color of the cell, on which I clicked. But I am not getting the way to call CSS using Javascript. Please help me out.
In jQuery, you may use the css method to change the background-color of the cell:
// let's say this is in a loop
$(this).css('background-color', '#f00');
And in plain JavaScript:
var element = document.getElementById("myElement");
element.style.backgroundColor = "#fff";
Steve
Using JS to change the style property of any element creates a very high specificity rule which is hard to detect and remove, and less flexible when dealing with multiple style effects (say you wanted a border as well as a background, now you have twice as much work to do).
Almost invariably it is far better from a maintenance, flexibility, and separation-of-concerns point of view not to modify the style of an element directly, but to change it's class and let CSS do the work for you.
e.g I want to change to this border+background style, so I'll define a class in my CSS
.highlight
{
border: 1px solid black;
background: white;
}
and then I'll modify the element where I need to like so:
document.getElementById('myElementId').className += " highlight"; //note the space
Now in practice I'd actually wrap that class modifying code in a more general wrapper to protect myself from assigning the same class twice, and make removing it again easier, but in principle you can see that it would now be trivial to change the effect of "highlight" at just a single point, it allows for normal cascading, and it's much easier to detect the element has a highlight class than it is to check if it's got a background colour of FOO and a border of BAR.
It also, quite importantly adds semantic value. Self documenting code is a very good thing.
To set one css property:
$("#myCalender").css("background-color","SomeColor");
To set an entire class:
$("#myCalender").addClass("DifferentBGColorClass");
To change the background color you could use:
document.getElementById("").style.backgroundColor = "#ffffff";