How to know if element height or width was set in javascript/css? - css

Is there any way to know if an element height or width was set (not auto) in javascript/css ?
elm.style.height will only return a value if the height is defined inside the element attribute list : <div style='height:200px' .... ></div>, otherwise it will always return an empty string even if you define the height inside a style tag or a css file : .myElmCss{height:200px}.
On the other hand, using window.getComputedStyle() or elm.currentStyle will always return a value even if no height was defined neither inside the element attribute list nor in a css file/style tag.
Thanks.

Check this post How do you read CSS rule values with JavaScript?
To do what you're looking for it appears to be a matter of iterating over the stylesheets to find declared properties. You would probably also cross reference with inline styles like you mentioned in your question.
from #InsDel's post:
function getStyle(className) {
var classes = document.styleSheets[0].rules || document.styleSheets[0].cssRules
for(var x=0;x<classes.length;x++) {
if(classes[x].selectorText==className) {
(classes[x].cssText) ? alert(classes[x].cssText) : alert(classes[x].style.cssText);
}
}
}

Related

Does CSS change the DOM?

I was wondering if CSS changes the DOM.
The reason I am asking, is that whenever I change an Element with CSS, I don't see it's value changed in the "element".style properties.
No, CSS does not change the DOM.
No. CSS does not change the DOM.
Nor content injected using :after or :before alter the DOM.
Actually... there are a few cases where CSS can change the DOM, but it's a bit far-stretched, as it won't change the DOM-tree structure, except in one yet even more far stretched case...
There is a being rendered definition in the HTML specs that does impact the behavior of the DOM in some cases, based on CSS computed styles.
For instance,
an HTMLImageElement can have its width and height IDL attributes value change whether it is being rendered or not:
onload = (evt) => {
console.log( 'rendered', document.getElementById( 'disp' ).width );
console.log( 'not rendered', document.getElementById( 'no-disp' ).width );
}
img { width: 100px; }
#no-disp { display: none; }
<img id="disp" src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png">
<img id="no-disp" src="https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png">
Elements that are not being rendered can not be focusable elements:
document.getElementById( 'rendered' ).focus();
console.log( document.activeElement ); // <input id="rendered">
document.getElementById( 'rendered' ).blur();
document.getElementById( 'not-rendered' ).focus();
console.log( document.activeElement ); // <body>
#not-rendered {
display: none;
}
<input id="rendered">
<input id="not-rendered">
And the one case where the DOM tree is modified, concerns the DOM tree of an inner Document: When an <object> or an <embed> element has its style set to display:none, per specs, its inner Document should be reloaded:
Whenever one of the following conditions occur
[...]
the element changes from being rendered to not being rendered, or vice versa,
...the user agent must queue an element task on the DOM manipulation task source given the object element to run the following steps to (re)determine what the object element represents.
So this means that simply switching the being rendered state of such an <object> or <embed> element is supposed to reload entirely its inner Document, which means also its DOM tree.
Now, only Safari behaves like that, Firefox never implemented that behavior, and Chrome did recently change their to match FF's one, against the specs.
For Safari users, here is a fiddle demonstrating it.

Testing contents of after CSS selector in protractor

In my HTML I have element such as below
HTML:
<hmtl>
<head>
<style>
label::after {
content: " *"
}
</style>
</head>
<body>
<label> I'm mandatory</label>
</body>
</hmtl>
So what gets displayed on browser is:
I'm mandatory *
Query Selector
>getComputedStyle(document.querySelector('label')).content
<"normal"
So I see normal instead of *.
I can't see where is normal coming from. Is this the correct way to test content of ::after CSS selector?
I want to test that there's a "*" after the label, but can't seem to be able to get the value of "content" property correctly. Once I'm able to find it in using browser DOM API, I'd eventually want to test it in protractor.
Update
I found the answer at - Selenium WebDriver get text from CSS property "content" on a ::before pseudo element.
Now the question remains how I would test this on protractor.
Window.getComputedStyle()
The Window.getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic computation those values may contain. Individual CSS property values are accessed through APIs provided by the object, or by indexing with CSS property names.
Syntax:
var style = window.getComputedStyle(element [, pseudoElt]);
element
The Element for which to get the computed style.
pseudoElt (Optional)
A string specifying the pseudo-element to match. Omitted (or null) for real elements.
The returned style is a live CSSStyleDeclaration object, which updates automatically when the element's styles are changed.
You can find a related discussion in WebDriver select element that has ::before
Usage with pseudo-elements
getComputedStyle() can pull style info from pseudo-elements (such as ::after, ::before, ::marker, ::line-marker.
As per the HTML, the <style> is as follows:
<style>
label::after {
content: " *"
}
</style>
Implemented as:
<label> I'm mandatory</label>
To retrieve you need to:
var label = document.querySelector('label');
var result = getComputedStyle(label, ':after').content;
console.log('the generated content is: ', result); // returns ' *'
Reference
CSS Pseudo-Elements Module Level 4
const label = document.querySelector('label'); // "normal";
console.log(label);
const labelAfter = getComputedStyle(label, ':after').content;
console.log(labelAfter == "normal");
label::after {
content: " *"
}
<label> I'm mandatory</label>
Since my question was specifically w.r.t protractor I'm posting the solution that I got working. Coming to the part I was stuck initially - why do I get "normal" instead of " *"
>getComputedStyle(document.querySelector('label')).content
<"normal"
So earlier I was unaware that ::after creates a pseudo child element inside the label element.
Inspecting <label> element in Chrome shows the below HTML
<label>
I'm mandatory
::after
</label>
If I click<label> element and checked the Computed tab, I could see that the value for content property is normal.
However, if I click on ::after pseudo-element, I can see in the Computed tab the value for content property is " *".
As mentioned in the other answers getComputedStyle() with the pseudo element as second parameter, is the only way to get value of CSS property for "::after". The crux of the problem is that protractor does not have an equivalent for getComputedStyle(), so we have to rely upon browser.executeScript() as shown below:
let labelHeader = 'I'm mandatory *';
// Passing label element separately as in the real test case, it would be extracted from parent
// enclosing element and need to be able to pass it as a parameter to browser.executeScript().
let label = element(by.css('label'));
browser.executeScript("return window.getComputedStyle(arguments[0], ':after').content",
label)
.then ((suffixData: string) => {
// suffixData comes out to be '" *"', double quotes as part of the string.
// So get rid of the first and last double quote character
suffixData = suffixData.slice(1, suffixData.length - 1);
labelText += suffixData;
expect(labelText).toBe(labelHeader);
});

SASS: Conditional values of CSS property based on that if an element with certain value of the same property has been present already in the page

I want to have different values of a css property (I am using SASS), based on that whether a element with a certain property's value '$additionalNavHeight' is present on the page. In some pages there is no such element, in other - there is. I wrote a SASS mixin:
#mixin top-position($navHeight, $additionalNavHeight)
{
#if $additionalNavHeight == true {
.loadingAnimation {
top: $navHeight + $additionalNavHeight;
}
}
#else {
.loadingAnimation {
top: $navHeight;
}
}
}
And I included the mixin in the selector:
#include top-position($navHeight, $additionalNavHeight);
I thought this should change the value of the property 'top' of the element with the class 'loadingAnimation', based on that if in the page already is present the element with the value of its 'top' property '$additionalNavHeight'. The compiler doesn't show any error, but the code doesn't change anything. What am I doing wrong? Any help would be very appreciated.
Тhe simplest solution. You must check with JavaScript if element exists or not
and to apply the second class to element. In the second case (element existing)
you must add adittionnal height. In this case the mixin is redundant.
.loadingAnimation {
top: $navHeight;
}
.loadingAnimation.additinnalHeight {
top: $navHeight + $additionalNavHeight;
}
Here is example jsfiffle:
https://jsfiddle.net/ra9r8rk8/
In this case element will receive class newClass when the first div exists. (the element)
Edit: This is second improved solution. In fact there is no need for regular expression. We can just use classList:
https://jsfiddle.net/ra9r8rk8/1/

How to get list of custom CSS properties

I'm looking into custom CSS properties and have come up with the code below.
If I put the CSS inline using a STYLE attribute on the canvas tag (like this: style="--rgLinewidth: 3" ) then I can get the custom CSS values using the script shown below.
But using a tag, as below, then it doesn't show the custom CSS properties.
Is it possible to? And if so how?
<html>
<head>
<style>
canvas#cvs {
--rgLinewidth: 3;
background-color: red;
}
</style>
</head>
<body>
<canvas id="cvs" width="600" height="250">[No canvas support]</canvas>
<script>
canvas = document.getElementById("cvs");
styles = window.getComputedStyle(canvas);
alert(styles.getPropertyValue('background-color'));
alert(styles.getPropertyValue('--rgLinewidth'));
for (var i=0; i<styles.length; i++) {
if (canvas.style[i].indexOf('--rg') === 0) {
var value = styles.getPropertyValue(canvas.style[i]);
alert([canvas.style[i], value]);
}
}
</script>
</body>
</html>
It does not work because you query for computed style and then attempt to retrieve values of corresponding properties from the inline style, where they do not exist -- your canvas does not define an inline style. You need to query the values through the same styles object where you find the properties.
Consider the following function which when passed an element, will search through its computed style and return the value of the first CSS variable whose name starts with --rg:
function find_first_rg_value(el) {
var styles = getComputedStyle(el);
for (var i = 0; i < styles.length; i++) {
if (styles[i].startsWith('--rg')) {
return styles.getPropertyValue(styles[i]);
}
}
}
(Use like find_first_rg_value(canvas))
The difference between my approach and yours is, as I said, that you attempt to fetch the value from canvas.style[i], but canvas.style is effectively empty. Use styles instead.
Computed style (getComputedStyle), as the name implies, contains "summary" style computed per CSS cascading, inheriting, and so on, with inline style, if any, applied on top (overriding priority). Assigning inline style therefore affects the computed style, but querying inline style only gives you inline style you assigned, no more.
This means that in most cases like yours one would want to use getComputedStyle. Additionally, since CSS variables cannot be queried using style.fontName syntax, you need to use getPropertyValue function for these (all dashes intact in the passed property name), regardless if you are dealing with an inline or computed style object.

Is there a way to use two classes on one element or emulate this behavior?

I need to do:
<p id="un_but" class="blue_but" class="radius_right">SignUp</p>
but this does not work.
Obviously I could just combine the class properties but I was wondering if there is another way perhaps
<p id="un_but" class="blue_but radius_right" >SignUp</p>
dom element(p) can have only ONE attribute(class), but with multiple values separated by space
One of the lesser known tricks with CSS is the fact that you don't have to limit your elements to just one class. If you need to set multiple classes on an element, you add them simply by separating them with a space in your attribute. For example:
<p class="pullquote btmmargin left">...</p>
This sets the following three classes on that paragraph tag:
pullquote
btmmargin
left
You would assign these as generic classes in your CSS:
.pullquote { ... }
.btmmargin { ... }
p.left { ... }
If you set the class to a specific element, you can still use it as part of a list of classes, but be aware that it will only affect those elements that are specified in the CSS.
You can use the important keyword to set precedence over different classes.
For example:
.pullquote { width :15 px !important }
.btmmargin { width:20px }
p.left { ... }
In the example above 20px width attribute will have more precedence.

Resources