How to get the inherited values of element from JavaScript - javascript

Okay, so I've a script that gets the CSS property value of a clicked element. For this, I avoided window.getComputedStyle() because it basically converts rem values to px and so on...
Instead, I've used CSSStyleSheet.cssRules just to keep the originality of the actual given units and not converting them.
And this does works fine! but it fails to capture CSSRules that are inherited from the parent element since the styles are not directly applied to the element.
For example:
<style>
#new {
font-size: 2rem;
}
</style>
<div id="new">
<h1 class="h1">This is a heading</h1>
<!––Here h1 is inheriting font-size from div that can't be catched by CSSRules––>
</div>
For this case, getComputedStyle() works the best as CSSRules failed to catch the inherited properties but again, the problem of units arises so I cannot use that.
Or maybe something to get the metric unit of an element? 🤷‍♀️ That would do the job too!
Although Chrome seems to have figured this out perfectly:
It's 2022 and I've checked other answers too but seems like nobody has figured this out yet. What's the current solution to this? Or the best hack?
Edit1:
I want the same string as defined in the CSS by the user. Like: calc(2rem + 1vh) And with CSSRules it is working but it doesn't works with inheritance because it's not even catching the property! ComputedStyle does that but in px I'm kinda stuck here.
Edit2:
I've chosen Lajos Arpads answer as the accepted one because of the help I recieved in the comments (not the actual answer itself). The solution is going to be labor intensive so it's something I've to do.

You can simply implement a pixel-to-rem converter and use that:
function convertPixelsToRem(pixels) {
return ((pixels.replace("px", "") / getComputedStyle(document.documentElement).fontSize.replace("px", "")) + "rem");
}
console.log(convertPixelsToRem(window.getDefaultComputedStyle(document.getElementById("new").querySelector(".h1"))["font-size"]));
<style>
#new {
font-size: 2rem;
}
</style>
<div id="new">
<h1 class="h1">This is a heading</h1>
<!–– Here h1 is inheriting font-size from div ––>
</div>
EDIT
You could do something like this:
getOriginalRule(ruleName, ruleValue, item) {
while (hasSameRule(item.parentNode, ruleName, ruleValue)) item = item.parentNode;
//return the rule value based on the item via CSSStyleSheet.cssRules
}
EDIT2
As per the ideas discussed in the comment section, with the goal being to be able to gather the raw rules applied either directly or by inheritance to nodes, there are two main solutions:
one can loop through the rules, find the elements they apply to and then loop the DOM tree to descend the raw rules where they were not overriden
one can loop the DOM tree from top to bottom and find all nodes, compare each node's rules with its parent's rules and if they differ, descend the parent's rules
The main difference between the two is that the first is starting with all the CSS rules, while the latter only uses the values.

Related

Maintaining Vertical Rhythm on arbitrary images

I would like to be able to maintain vertical rhythm on a page that contains images of unknown heights. I found this but am using vanilla-js rather than jquery so a jquery plugin is out of the question. The other answer requires that the baseline be set in javascript. I already have it set in my SCSS files! I'm a very lazy programmer and don't want to type it twice. Wait, I didn't say that. I meant I'm concerned about the maintainability of duplicating hard-coded values all over the place.
here is another solution that I have to reject because I don't like all that extra markup over style concerns. It reminds me of the days when you had to nest <div> tags four deep just to get rounded corners.
It occurred to me to use generated content to pass JSON to the javascript. I thought I was a genius but then found this example using the exact same method.
Is there a better way of doing this?
All I really want is a way to specify that the height of an element needs to be a multiple of some given value. Is there really no way to do this with just CSS? The answers I've seen say there isn't. I feel like calc could almost do the job but am not smrt enough to figure it out. Is there a better way of getting the value to the javascript?
Thanks in advance.
It occurred to me that it is better to use CSS variables and then read those values from javascript as documented here.
This has the advantages of
using the cascade to allow multiple regions of the page to each have their own vertical rhythm.
not requiring parsing the content of the ::after psuedo-element as JSON.
The browsers are apparently inconsistent regarding how the escape embedding quotes in the content attribute.
One downside is that custom attributes are not as widely supported as pseudo elements. This way will break on more browsers. Because it's only cosmetic, I find that acceptable.
const foo = document.getElementsByClassName('foo')[0];
const bar = document.getElementsByClassName('bar')[0];
const fooStyles = window.getComputedStyle(foo);
const barStyles = window.getComputedStyle(bar);
const fooVR = fooStyles.getPropertyValue('--vertical-rhythm');
const barVR = barStyles.getPropertyValue('--vertical-rhythm');
foo.innerHTML = '--vertical-rhythm: ' + fooVR;
bar.innerHTML = '--vertical-rhythm: ' + barVR;
:root {
line-height: 1.5rem;
/* $line-height */
--vertical-rhythm: 3rem;
/* 2 * $line-height */
}
.foo {
--vertical-rhythm: 6rem;
/* 4 * $line-height */
}
<div class="foo"></div>
<div class="bar"></div>

Javascript/AngularJS: Check if an element has the style overflow-y applied to it

I am trying to check inside my code if a has applied to its css styling the attribute overflow-y: auto. For example if my has a class "abcd", and "abcd" has for its css overflow-y: auto, then the passes. While I've already found a method for jquery, which I am not using, I want to find a method for pure javascript (or Angular JS) to find if the element has a given css attribute. How can I do this without jquery?
You can check with pure javascript by using this code : document.getElementById('myElement').style['overflow-y'].
The issue is that this code will works only for inline css style, as in <div style="overflow-y: visible">...</div>. If the css style comes from a class, you can't find it like this.
The jQuery css method will find the computed style (so it can detect the real value of overflow-y even if it comes from a class). But the css code is very huge. You can find it here : https://github.com/jquery/jquery/blob/master/src/css.js
I want to add that checking if an element has a specific css style is a very bad smell.
Instead of this, you should really consider to check if the element has a specific class. Or if you have using angularjs, a simple boolean in the model will do the trick.
If you really want to check if an element has the overflow-y: auto; style applied, according to the jQuery code, they use window.getComputedStyle(element). They also have a lot of code with a temporary div with a weird position (position:absolute;left:-11111px;width:60px;) but it is mostly to support old browsers like IE8 and IE9.
In your case, something like this could works : window.getComputedStyle(document.getElementById('myElement'))['overflow-y'] === 'auto'.
You can use the getComputedStyle method available on the window object.
var myElement = document.getElementById('myElement');
var overflowValue = getComputedStyle(MyElement).overflowY;
if (overflowValue == 'auto') {
// your code here
}
This method will get values of css properties applied in the moment.
For more info, you can refer here.
hope that helps.

Use jQuery to get css properties of a class/id that that doesn't exist in the page

As it said in the title. I want this javascript...
$("#mrNotAppearing").css("background-color");
to return "red" based on this css...
#mrNotAppearing {
background-color: red;
}
given that there are no elements in the document that actually have the id mrNotAppearing
I'm using media query checks with jQuery to get window widths as seen here and I thought it might be nice to use some "dummy" css that definitely won't get in the way of anything.
I'm also open to other suggestions that achieve the same result.
Plan B, I'll just go with actual css or add some dummy property to body?
Updating for clarity:
It can be difficult to sync javascript that requires particular window widths with media query widths in the css, which can cause layout problems.
Instead, you can query the status of the css itself. As so:
body {
background-color: blue;
}
#media (min-width: 42em) {
body {
background-color: red;
}
}
Then, in the javascript:
if($(body).css("background-color")==="red"){
// we know down to the pixel that it's safe to trigger the javascript
// because the media query went off.
}
All I'm trying to do is add a dummy entry in the css that will be used solely for triggering the javascript. I could use an existing property--and may have to--but I'd like to make it explicit what I'm doing. Or I'm at least toying with the idea.
I apologize for the confusion. I was going for brevity.
P.S. the whole point of the question is to use a style that will 100% not be appearing in the document. And will never change, even if the layout does.
EDIT: Ha, okay, final answer. em does indeed return as px. So...
I'm going to answer my own question because I'm pretty sure it isn't making sense to anyone. Also, I don't know if this is a good idea, but it seems to work for my purposes. So, my solution:
Style the <style> tag. It's in the DOM, it's not structural, and jQuery can get css properties from it. Like so...
style {
width: 672px;
}
and then...
$("style").css("width");
will return 672px
I'm probably over-thinking this. And still probably not making sense. And I have no idea if this works on any browser but Chrome or if it's a terrible idea for some reason, but I think it's kind of appealing, semantically.
Any other thoughts?
You have access to all css rules through document.styleSheets, there is no need to apply to an element.
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet
Here is another answer on how to get the style based on a class name:
How do you read CSS rule values with JavaScript?
EDIT
Although, it would be a lot easier to render the element off canvas for a brief moment:
var $dummy = $('<div>').addClass('class1 class2 class3').css({position: fixed, left: 100%}).appendTo('body');
// collect all info you need here;
$dummy.remove();

Javascript style issue

I am using javascript to display the height of my current div.
This is an example of the effected area
//css
.test
{
height:1px;
}
#test1
{
margin:1px;
}
//html
<div id="test1" class="test"></div>
//javascript
var a = document.getElementById('test1');
a.style.height //how I access the style
Firebug says that the length of style is 0 and height is empty.
How can I access the correct height?
You need to look at the computed style, not the specified style. See Quirks mode's getstyle page which answers the question
Sometimes you'll want to see what styles the default document view has. For instance, you gave a paragraph an width of 50%, but how do you see how many pixels that is in your users' browser?
and it explains how to derive and use the getstyle function, though it's easier to use a library like jquery which provides a simple css function.
Try a.offsetHeight instead of a.style.height
jsfiddle demo
div height is dependent on its children. If its empty, it'll be 0.
The code you have to get height is correct, btw.
Check out the getComputedStyle method. It should do what you are looking for. Kinda lame, really, I wish this was handled better in the DOM.

Quickly repaint array of unicode symbols in JavaScript

I want to change background/foreground color of many symbols with the same CSS class. Right now I'm doing it with jQuery — like $('back_COLORED').css('background-color', '#00FF00'), but this approach is slow when there are many elements with such class (>900).
Seems it's because jQuery don't change CSS rules itself, but finds all elements one-by-one and applies inline styles to them. At least, this is what I see in inspector. So, the question is:
How can I change the CSS rules itself?
Will it be much faster?
Can I make it cross-browser (IE6 doesn't count)?
UPD: I'm trying to make some kind of color scheme editor. The source is at http://github.com/kurokikaze/cinnabar/. Don't mind PHP things, editor is fully client-side (with just some libraries fetched from the net).
UPD2: Tried canvas approach, still slow. Canvas branch is at http://github.com/kurokikaze/cinnabar/tree/canvas.
The most cross-browser friendly way to override a class definition is to write a new rule and add it to the end of the last stylesheet in the document. You can edit an existing style rule, but even some recent browsers can make it difficult.
function newRule(selector, csstext){
var SS= document.styleSheets, S= SS[SS.length-1];
// this example assumes at least one style or link element
if(S.rules){
S.addRule(selector,csstext,S.rules.length);
}
else if(S.cssRules){
S.insertRule(selector+'{'+csstext+'}'),S.cssRules.length)
}
}
newRule('.someclass','background-color:#0f0');
You can add as many 'property:value;' bits in the csstext as you need.
Remember to prefix a '.' to a class name or a '#' to an id,
and the css must be written as a style rule (with-hyphens, not camelCase).
Of course, it will not override inline styles, and it is overkill for small, local changes.
It also may make the redrawing of the page more obvious than changing one element at a time,
but it may be just what you need here.
There are different ways depending on which browser you are dealing with. This is documented on Quirks Mode.
Some libraries provide an abstraction layer, such as YUI's StyleSheet utility.
There should be a significant performance boost since you aren't using JS/DOM to cycle through all the elements.
Another approach would be to predefine your styles:
body.foo .myElements { … }
And then edit document.body.className
If you can select the parent div by id, maybe you could select by tag inside it? Or are there elements of the same kind that should change color and that should not, inside the parent?
It would be nice to have an idea of what you're building here. 900+ objects seems to be a lot... maybe a completely different approach could be used? Canvas, SVG?
Try hiding the items you want to change before changing them, make the change and then display them again. This is common practice to speed up things as you minimize the repaint events in the viewport. In this case when you only setting one css property it might not be that of a benefit but it´s worth a try I say.
Try:
$('back_COLORED').hide();
$('back_COLORED').css('background-color', '#00FF00');
$('back_COLORED').show();
or
$('back_COLORED').hide().css('background-color', '#00FF00').show();
I would stick in trying changing a CSS property, instead of parsing the DOM.It is about the CSS engine vs. DOM+JS here, and the winner is clear.
It happens I just uploaded a tiny library that replaces CSS by Javascript: jstyle
This is may be an overkill, but you will find in the source code of jstyle.js all the code you need to update cross browser the CSS properties of your page.
I think a better solution would be to write a more specific CSS rule (that would override the normal colour) that can be activated by simply changing one element's css class.
So for example if you had the following structural markup:
<div id="container">
<span class="colored">Test 1</span>
<span class="colored">Test 2</span>
</div>
And CSS:-
.colored { background-color: red; }
.newcolor .colored { background-color: blue; }
Then in your jquery you add the .newcolor class to the container div:-
$('#container').addClass('.newcolor');
When you do that the second CSS rule will override the first because it is more specific.
Inject the css code into a style tag:
var style = $('style').attr({
type:"text/css",
media:"screen",
id:'changeStyle'
}).html('.tempClass { color:red } .tempClass p { background:blue }').prependTo('body');
and on every changes on your color with color picker you only rewrite the html inside of #changeStyle tag.
Have no idea if it works (didn't tested) but you should give a try.
This is jQuery pluggin for work with css rules: http://flesler.blogspot.com/2007/11/jqueryrule.html
not sure about its performance, but worth a try.

Categories

Resources