I have these CSS variables to control the colors of my project so I can do theming.
html {
--main-background-image: url(../images/starsBackground.jpg);
--main-text-color: #4CAF50;
--main-background-color: rgba(0,0,0,.25);
--beta-background-color: rgba(0,0,0,.85);
}
However no matter how I try to change the attribute(the two commented lines tried separately), the closest I get is returning not a valid attribute.
function loadTheme() {
var htmlTag = document.getElementsByTagName("html");
var yourSelect = document.getElementById( "themeSelect" );
var selectedTheme = ( yourSelect.options[ yourSelect.selectedIndex ].value );
// htmlTag[0].setAttribute('--main-text-color', '#FFCF40');
// $("html").css("--main-text-color","#FFCF40");
}
Turns out changing CSS variables is possible using the el.style.cssText property, or el.style.setProperty or el.setAttribute methods. In your code snippets el.setAttribute is incorrectly used, which is causing the error you encountered. Here's the correct way:
document.documentElement.style.cssText = "--main-background-color: red";
or
document.documentElement.style.setProperty("--main-background-color", "green");
or
document.documentElement.setAttribute("style", "--main-background-color: green");
Demo
The following demo defines a background color using a CSS variable, then changes it using the JS snippet 2 seconds after loading.
window.onload = function() {
setTimeout(function() {
document.documentElement.style.cssText = "--main-background-color: red";
}, 2000);
};
html {
--main-background-image: url(../images/starsBackground.jpg);
--main-text-color: #4CAF50;
--main-background-color: rgba(0,0,0,.25);
--beta-background-color: rgba(0,0,0,.85);
}
body {
background-color: var(--main-background-color);
}
This will only work in browsers supporting CSS variables obviously.
If you are using :root:
:root {
--somevar: black;
}
It will be documentElement.
document.documentElement.style.setProperty('--somevar', 'green');
The native solution
The standard methods to get/set CSS3 variables are .setProperty() and .getPropertyValue().
If your Variables are Globals (declared in :root), you can use the following, for getting and setting their values.
// setter
document.documentElement.style.setProperty('--myVariable', 'blue');
// getter
document.documentElement.style.getPropertyValue('--myVariable');
However the getter will only return the value of a var, if has been set, using .setProperty().
If has been set through CSS declaration, will return undefined. Check it in this example:
let c = document.documentElement.style.getPropertyValue('--myVariable');
alert('The value of --myVariable is : ' + (c?c:'undefined'));
:root{ --myVariable : red; }
div{ background-color: var(--myVariable); }
<div>Red background set by --myVariable</div>
To avoid that unexpected behavior you have to make use of the getComputedStyle()method , before calling .getPropertyValue().
The getter will then , look lik this :
getComputedStyle(document.documentElement,null).getPropertyValue('--myVariable');
In my opinion, accessing CSS variables should be more simple, fast, intuitive and natural...
My personal approach
I've implemented CSSGlobalVariables a tiny (<3kb) javascript module wich automatically detects and packs into an Object, all the active CSS global variables in a document, for easier acces & manipulation.
import {CSSGlobalVariables} from './css-global-variables.js';
let cssVar = new CSSGlobalVariables();
// set the CSS global --myColor value to "green"
cssVar.myColor = "green";
Any change applied to the Object properties, is translated automatically to the CSS variables, and viceversa.
Available in : https://github.com/colxi/css-global-variables
You can simply use the standard way of setting arbitrary CSS properties: setProperty
document.body.style.setProperty('--background-color', 'blue');
body {
--background-color: red;
background-color: var(--background-color);
}
For anyone who is struggling with it, if your CSS variable is a sentence you need to wrap it in qoutes.
:root {
--my-css-var: 'Hello Person!';
}
.selector:after {
content: var(--my-css-var);
}
This does not work:
let myVar = 'Hi Person! (doesnt work)';
document.getElementsByTagName('html')[0].style.setProperty('--my-css-var', myVar);
But this does:
let myVar = 'Hi Person! (works)';
document.getElementsByTagName('html')[0].style.setProperty('--my-css-var', '"' + myVar + '"');
You could add something like below (without using class variables)
function loadTheme() {
var htmlTag = document.getElementById("myDiv");
var yourSelect = document.getElementById("themeSelect");
var selectedTheme = (yourSelect.options[yourSelect.selectedIndex].value);
console.log("selected theme: " + selectedTheme);
// reset class names
htmlTag.className = '';
// add selected theme
htmlTag.className = 'theme' + selectedTheme;
}
.theme1 {
color: blue;
}
.theme2 {
color: red;
}
<div id="myDiv">
test
</div>
<select id="themeSelect" onChange="loadTheme()">
<option value="1">Theme 1</option>
<option value="2">Theme 2</option>
</select>
It would probably be easier to define classes in your CSS that contain the various theme styles (.theme1 {...}, .theme2 {...}, etc) and then change the class with JS based on the selected value.
Related
I have these CSS variables to control the colors of my project so I can do theming.
html {
--main-background-image: url(../images/starsBackground.jpg);
--main-text-color: #4CAF50;
--main-background-color: rgba(0,0,0,.25);
--beta-background-color: rgba(0,0,0,.85);
}
However no matter how I try to change the attribute(the two commented lines tried separately), the closest I get is returning not a valid attribute.
function loadTheme() {
var htmlTag = document.getElementsByTagName("html");
var yourSelect = document.getElementById( "themeSelect" );
var selectedTheme = ( yourSelect.options[ yourSelect.selectedIndex ].value );
// htmlTag[0].setAttribute('--main-text-color', '#FFCF40');
// $("html").css("--main-text-color","#FFCF40");
}
Turns out changing CSS variables is possible using the el.style.cssText property, or el.style.setProperty or el.setAttribute methods. In your code snippets el.setAttribute is incorrectly used, which is causing the error you encountered. Here's the correct way:
document.documentElement.style.cssText = "--main-background-color: red";
or
document.documentElement.style.setProperty("--main-background-color", "green");
or
document.documentElement.setAttribute("style", "--main-background-color: green");
Demo
The following demo defines a background color using a CSS variable, then changes it using the JS snippet 2 seconds after loading.
window.onload = function() {
setTimeout(function() {
document.documentElement.style.cssText = "--main-background-color: red";
}, 2000);
};
html {
--main-background-image: url(../images/starsBackground.jpg);
--main-text-color: #4CAF50;
--main-background-color: rgba(0,0,0,.25);
--beta-background-color: rgba(0,0,0,.85);
}
body {
background-color: var(--main-background-color);
}
This will only work in browsers supporting CSS variables obviously.
If you are using :root:
:root {
--somevar: black;
}
It will be documentElement.
document.documentElement.style.setProperty('--somevar', 'green');
The native solution
The standard methods to get/set CSS3 variables are .setProperty() and .getPropertyValue().
If your Variables are Globals (declared in :root), you can use the following, for getting and setting their values.
// setter
document.documentElement.style.setProperty('--myVariable', 'blue');
// getter
document.documentElement.style.getPropertyValue('--myVariable');
However the getter will only return the value of a var, if has been set, using .setProperty().
If has been set through CSS declaration, will return undefined. Check it in this example:
let c = document.documentElement.style.getPropertyValue('--myVariable');
alert('The value of --myVariable is : ' + (c?c:'undefined'));
:root{ --myVariable : red; }
div{ background-color: var(--myVariable); }
<div>Red background set by --myVariable</div>
To avoid that unexpected behavior you have to make use of the getComputedStyle()method , before calling .getPropertyValue().
The getter will then , look lik this :
getComputedStyle(document.documentElement,null).getPropertyValue('--myVariable');
In my opinion, accessing CSS variables should be more simple, fast, intuitive and natural...
My personal approach
I've implemented CSSGlobalVariables a tiny (<3kb) javascript module wich automatically detects and packs into an Object, all the active CSS global variables in a document, for easier acces & manipulation.
import {CSSGlobalVariables} from './css-global-variables.js';
let cssVar = new CSSGlobalVariables();
// set the CSS global --myColor value to "green"
cssVar.myColor = "green";
Any change applied to the Object properties, is translated automatically to the CSS variables, and viceversa.
Available in : https://github.com/colxi/css-global-variables
You can simply use the standard way of setting arbitrary CSS properties: setProperty
document.body.style.setProperty('--background-color', 'blue');
body {
--background-color: red;
background-color: var(--background-color);
}
For anyone who is struggling with it, if your CSS variable is a sentence you need to wrap it in qoutes.
:root {
--my-css-var: 'Hello Person!';
}
.selector:after {
content: var(--my-css-var);
}
This does not work:
let myVar = 'Hi Person! (doesnt work)';
document.getElementsByTagName('html')[0].style.setProperty('--my-css-var', myVar);
But this does:
let myVar = 'Hi Person! (works)';
document.getElementsByTagName('html')[0].style.setProperty('--my-css-var', '"' + myVar + '"');
You could add something like below (without using class variables)
function loadTheme() {
var htmlTag = document.getElementById("myDiv");
var yourSelect = document.getElementById("themeSelect");
var selectedTheme = (yourSelect.options[yourSelect.selectedIndex].value);
console.log("selected theme: " + selectedTheme);
// reset class names
htmlTag.className = '';
// add selected theme
htmlTag.className = 'theme' + selectedTheme;
}
.theme1 {
color: blue;
}
.theme2 {
color: red;
}
<div id="myDiv">
test
</div>
<select id="themeSelect" onChange="loadTheme()">
<option value="1">Theme 1</option>
<option value="2">Theme 2</option>
</select>
It would probably be easier to define classes in your CSS that contain the various theme styles (.theme1 {...}, .theme2 {...}, etc) and then change the class with JS based on the selected value.
I want to generate css dynamically at run time.
Initially I had used sass and defined some variables and was using those variables. But css has to be generated first from the scss. Sass had given me flexibility to use variables and functions but still I was not able to changes them at run time via javascript.
One way was to change the inline styles via javascript but that approach was not completly flexible.
document.getElementById("myDiv").style.color = "red";
I don't want to do above, neither I want to attach any <style> attribute via javascript.
I want to use javascript but not for chaniging each and every style properties. I want to achieve scss like effect using css and javascript but at run time i.e dynamically.
E.g. suppose I got the color information from the ajax call now I want to change the whole theme of website based on that color received immediately without restarting or re-deploying my application.
e.g
as done in scss
.myClass {
background:$color;
// Update color value dynamically at run-time
}
Is it even possible or I am thinking in wrong direction!
Wound up playing with this and CSS variables. I'm adding a second answer because it's very different method from my first answer and it better aligns with your original question (updating CSS variables with JS).
BUT... don't do this. :) Browser support in IE < Edge doesn't exist and it is almost certainly slower than updating an on-page <style> element though I haven't tested it. This jsperf tests various style update methods. It doesn't include innerHTML on a single style element (likely the fastest) but you can see that the following CSS DOM methods are slower than the rest.
// get the stylesheet
// array position depends on how many style sheets you're loading.
// adjust as needed.
var sheet = document.styleSheets[0];
// simplest method: insertRule()
// setTimeout only for demo so you can see the change
window.setTimeout(function(){
// #media all {} is a trick to insert more than one
// selector and/or properties at once. Otherwise it's:
// sheet.insertRule(":root", "--header-color: green"); ...repeat...
sheet.insertRule("#media all { :root { --header-color: green; --main-color: orange; } }", 1);
}, 1200);
// SAFER method via addCSSRule.
// button and getAjaxStyles are just placeholders, obviously
var btn = document.querySelector('button');
btn.addEventListener("click", getAjaxStyles);
function getAjaxStyles() {
// success callback... break apart the json and update the CSS variables
addCSSRule(sheet, ":root", "--header-color: orange");
addCSSRule(sheet, ":root", "--main-color: blue");
addCSSRule(sheet, ":root", "--alt-color: red");
addCSSRule(sheet, ":root", "--borderColorA: lavender");
// or go with a single big string. definitely faster:
// addCSSRule(sheet, ":root", "--alt-color: red; --borderColorA: #0ff; ")
}
// Credit for addCSSRule() goes to Diego Flórez in a comment on
// https://davidwalsh.name/add-rules-stylesheets
var addCSSRule = function(sheet, selector, rules) {
//Backward searching of the selector matching cssRules
var index = sheet.cssRules.length - 1;
for (var i = index; i > 0; i--) {
var current_style = sheet.cssRules[i];
if (current_style.selectorText === selector) {
//Append the new rules to the current content of the cssRule;
rules = current_style.style.cssText + rules;
sheet.deleteRule(i);
index = i;
}
}
if (sheet.insertRule) {
sheet.insertRule(selector + "{" + rules + "}", index);
} else {
sheet.addRule(selector, rules, index);
}
return sheet.cssRules[index].cssText;
}
/* Set initial CSS variables */
:root {
--header-color: #333;
--main-color: #888;
--alt-color: #bbb;
--borderColorA: #ccc;
}
h1 {
color: var(--header-color);
}
p {
border-bottom: 1px solid var(--borderColorA);
color: var(--main-color);
}
p+p {
color: var(--alt-color);
}
<h1>header</h1>
<p>paragraph 1</p>
<p>paragraph 2</p>
<button>Update CSS Variables</button>
To expand on the information that is provided in the linked "possible duplicate" question, you could easily set up a "default" set of styles in your page CSS file and then create a inline <style> ekement containing any overrides based on the response from your AJAX call. As long as the element/class/id definitions are the same in the two locations (i.e., CSS file and inline style section), specificity will cause the inline definitions to override the CSS ones.
So, using your example, your static CSS file would contain:
.myClass {
background: #FFFFFF;
}
. . . so that there is a default value if the AJAX call were to fail, and then your dynamically created <style> section would contain:
.myClass {
background: THE_AJAX_RESPONSE_VALUE;
}
. . . which would override the default value.
UPDATE #1:
Based on your sample JSON, this would be REALLY easy . . . you would loop through each top-level property of the JSON and create this:
KEY_NAME {
. . .
}
Then, within that block, loop through each property within that property and add the keys and values to create the style definitions:
KEY_NAME {
key1: value1,
key2: value2,
. . .
keyN: valueN
}
UPDATE #2:
You can also use StyleSheet and CSSStyleSheet interfaces to access the rules that are in the existing stylesheets, but, given that it uses an array-like structure, that means looping through all of the CSS definitions to find the one that you want and alter it. An example of how to do that can be found in this answer to another SO question: Is it possible to alter a CSS stylesheet using JavaScript? (NOT the style of an object, but the stylesheet itself)
Between the two approaches, though, creating an overriding <style> section seems like the easier approach.
Since the JSON has both the element names and the related styles, refreshing an on page stylesheet (vs inline element styles) would probably be the fastest since it uses innerHTML and only requires a single DOM lookup.
You'll need to loop through your JSON to create CSS compatible strings and then just dump it into the onpage style element. You can append CSS by concatenating the existing innerHTML with the new CSS string. I added an ID to the stylesheet for simplicity but you could also generate the style element when needed.
var StringifiedAjaxStyleObject = "h1 {background-color: #ecc; color: #633}";
var styleSheet = document.getElementById("style-update");
// some additional fake test style returns...
var testStyle1 = "h1 {background-color: #ccc; color: #333}";
var testStyle2 = "h1 {background-color: #667; color: #bbc}";
var testStyle3 = "h1 {background-color: #fee; color: #b00}";
// some fake ajax returns...
window.setTimeout(function() {
styleSheet.innerHTML = StringifiedAjaxStyleObject;
}, 1000);
window.setTimeout(function() {
styleSheet.innerHTML = testStyle1;
}, 2000);
window.setTimeout(function() {
styleSheet.innerHTML = testStyle2;
}, 3000);
window.setTimeout(function() {
styleSheet.innerHTML = testStyle3;
}, 4000);
/* base styles ... */
h1 {
padding: 5px;
background-color: #eef;
color: #007
}
<!-- empty stylesheet -->
<style id="style-update" type="text/css" rel="stylesheet"></style>
<h1>Hi, mom</h1>
<button>Update Styles<button>
EDIT:
Here's a slightly more real-world version based on the JSON object in your comment. Trigger it via the button.
var styleSheet = document.getElementById("style-update");
var btn = document.querySelector('button');
btn.addEventListener("click", updateStyles);
function updateStyles() {
var StringifiedAjaxStyleObject
, newCSS
, ajaxReturn
;
// ...your ajax method to get the new styles...
// on success...
ajaxReturn = {
".base": {
"background-color": "#b83605",
"border-color": "#543927",
"color": "gray",
"text-shadow": "0 -1px 0 rgba(0, 0, 0, 0.15)"
},
".overlay": {
"background": "rgba(76, 65, 80, 0.2)",
"color" : "#ddd"
}
};
// Convert the object to a string
newCSS = cssStringFromJson(ajaxReturn);
// Update the stylesheet
styleSheet.innerHTML = newCSS;
}
function cssStringFromJson(cssJSON) {
var styleStr = "",
i, j;
for (i in cssJSON) {
styleStr += i + " {\n"
for (j in cssJSON[i]) {
styleStr += "\t" + j + ": " + cssJSON[i][j] + ";\n"
}
styleStr += "}\n"
}
return styleStr;
}
/* base styles ... */
.base {
border: 1px solid #ccf;
background-color: #eef;
color: #000;
padding: 15px;
}
.overlay {
padding: 5px 15px;
background: rgba(96, 95, 180, 0.2);
}
body {
font-family: sans-serif;
}
button {
margin-top: 1em;
font-size: 1em;
}
<!-- empty stylesheet -->
<style id="style-update" type="text/css" rel="stylesheet"></style>
<div class="base">
<p>.base</p>
<div class="overlay">
<p>.overlay</p>
</div>
</div>
<button>Update Styles</button>
You can try angular templates.
It is going to break your previous sass, but it will work out later.
It's easy to set inline CSS values with javascript. If I want to change the width and I have html like this:
<div style="width: 10px"></div>
All I need to do is:
document.getElementById('id').style.width = value;
It will change the inline stylesheet values. Normally this isn't a problem, because the inline style overrides the stylesheet. Example:
<style>
#tId {
width: 50%;
}
</style>
<div id="tId"></div>
Using this Javascript:
document.getElementById('tId').style.width = "30%";
I get the following:
<style>
#tId {
width: 50%;
}
</style>
<div id="tId" style="width: 30%";></div>
This is a problem, because not only do I not want to change inline values, If I look for the width before I set it, when I have:
<div id="tId"></div>
The value returned is Null, so if I have Javascript that needs to know the width of something to do some logic (I increase the width by 1%, not to a specific value), getting back Null when I expect the string "50%" doesn't really work.
So my question: I have values in a CSS style that are not located inline, how can I get these values? How can I modify the style instead of the inline values, given an id?
Ok, it sounds like you want to change the global CSS so which will effictively change all elements of a peticular style at once. I've recently learned how to do this myself from a Shawn Olson tutorial. You can directly reference his code here.
Here is the summary:
You can retrieve the stylesheets via document.styleSheets. This will actually return an array of all the stylesheets in your page, but you can tell which one you are on via the document.styleSheets[styleIndex].href property. Once you have found the stylesheet you want to edit, you need to get the array of rules. This is called "rules" in IE and "cssRules" in most other browsers. The way to tell what CSSRule you are on is by the selectorText property. The working code looks something like this:
var cssRuleCode = document.all ? 'rules' : 'cssRules'; //account for IE and FF
var rule = document.styleSheets[styleIndex][cssRuleCode][ruleIndex];
var selector = rule.selectorText; //maybe '#tId'
var value = rule.value; //both selectorText and value are settable.
Let me know how this works for ya, and please comment if you see any errors.
Please! Just ask w3 (http://www.quirksmode.org/dom/w3c_css.html)!
Or actually, it took me five hours... but here it is!
function css(selector, property, value) {
for (var i=0; i<document.styleSheets.length;i++) {//Loop through all styles
//Try add rule
try { document.styleSheets[i].insertRule(selector+ ' {'+property+':'+value+'}', document.styleSheets[i].cssRules.length);
} catch(err) {try { document.styleSheets[i].addRule(selector, property+':'+value);} catch(err) {}}//IE
}
}
The function is really easy to use.. example:
<div id="box" class="boxes" onclick="css('#box', 'color', 'red')">Click Me!</div>
Or:
<div class="boxes" onmouseover="css('.boxes', 'color', 'green')">Mouseover Me!</div>
Or:
<div class="boxes" onclick="css('body', 'border', '1px solid #3cc')">Click Me!</div>
Oh..
EDIT: as #user21820 described in its answer, it might be a bit unnecessary to change all stylesheets on the page. The following script works with IE5.5 as well as latest Google Chrome, and adds only the above described css() function.
(function (scope) {
// Create a new stylesheet in the bottom
// of <head>, where the css rules will go
var style = document.createElement('style');
document.head.appendChild(style);
var stylesheet = style.sheet;
scope.css = function (selector, property, value) {
// Append the rule (Major browsers)
try { stylesheet.insertRule(selector+' {'+property+':'+value+'}', stylesheet.cssRules.length);
} catch(err) {try { stylesheet.addRule(selector, property+':'+value); // (pre IE9)
} catch(err) {console.log("Couldn't add style");}} // (alien browsers)
}
})(window);
Gathering the code in the answers, I wrote this function that seems running well on my FF 25.
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
/* returns the value of the element style of the rule in the stylesheet
* If no value is given, reads the value
* If value is given, the value is changed and returned
* If '' (empty string) is given, erases the value.
* The browser will apply the default one
*
* string stylesheet: part of the .css name to be recognized, e.g. 'default'
* string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td'
* string style: camelCase element style, e.g. 'fontSize'
* string value optionnal : the new value
*/
var CCSstyle = undefined, rules;
for(var m in document.styleSheets){
if(document.styleSheets[m].href.indexOf(stylesheet) != -1){
rules = document.styleSheets[m][document.all ? 'rules' : 'cssRules'];
for(var n in rules){
if(rules[n].selectorText == selectorText){
CCSstyle = rules[n].style;
break;
}
}
break;
}
}
if(value == undefined)
return CCSstyle[style]
else
return CCSstyle[style] = value
}
This is a way to put values in the css that will be used in JS even if not understood by the browser. e.g. maxHeight for a tbody in a scrolled table.
Call :
CCSStylesheetRuleStyle('default', "#mydiv", "height");
CCSStylesheetRuleStyle('default', "#mydiv", "color", "#EEE");
I don't know why the other solutions go through the whole list of stylesheets for the document. Doing so creates a new entry in each stylesheet, which is inefficient. Instead, we can simply append a new stylesheet and simply add our desired CSS rules there.
style=document.createElement('style');
document.head.appendChild(style);
stylesheet=style.sheet;
function css(selector,property,value)
{
try{ stylesheet.insertRule(selector+' {'+property+':'+value+'}',stylesheet.cssRules.length); }
catch(err){}
}
Note that we can override even inline styles set directly on elements by adding " !important" to the value of the property, unless there already exist more specific "!important" style declarations for that property.
I don't have rep enough to comment so I'll format an answer, yet it is only a demonstration of the issue in question.
It seems, when element styles are defined in stylesheets they are not visible to getElementById("someElement").style
This code illustrates the issue... Code from below on jsFiddle.
In Test 2, on the first call, the items left value is undefined, and so, what should be a simple toggle gets messed up. For my use I will define my important style values inline, but it does seem to partially defeat the purpose of the stylesheet.
Here's the page code...
<html>
<head>
<style type="text/css">
#test2a{
position: absolute;
left: 0px;
width: 50px;
height: 50px;
background-color: green;
border: 4px solid black;
}
#test2b{
position: absolute;
left: 55px;
width: 50px;
height: 50px;
background-color: yellow;
margin: 4px;
}
</style>
</head>
<body>
<!-- test1 -->
Swap left positions function with styles defined inline.
Test 1<br>
<div class="container">
<div id="test1a" style="position: absolute;left: 0px;width: 50px; height: 50px;background-color: green;border: 4px solid black;"></div>
<div id="test1b" style="position: absolute;left: 55px;width: 50px; height: 50px;background-color: yellow;margin: 4px;"></div>
</div>
<script type="text/javascript">
function test1(){
var a = document.getElementById("test1a");
var b = document.getElementById("test1b");
alert(a.style.left + " - " + b.style.left);
a.style.left = (a.style.left == "0px")? "55px" : "0px";
b.style.left = (b.style.left == "0px")? "55px" : "0px";
}
</script>
<!-- end test 1 -->
<!-- test2 -->
<div id="moveDownThePage" style="position: relative;top: 70px;">
Identical function with styles defined in stylesheet.
Test 2<br>
<div class="container">
<div id="test2a"></div>
<div id="test2b"></div>
</div>
</div>
<script type="text/javascript">
function test2(){
var a = document.getElementById("test2a");
var b = document.getElementById("test2b");
alert(a.style.left + " - " + b.style.left);
a.style.left = (a.style.left == "0px")? "55px" : "0px";
b.style.left = (b.style.left == "0px")? "55px" : "0px";
}
</script>
<!-- end test 2 -->
</body>
</html>
I hope this helps to illuminate the issue.
Skip
You can get the "computed" styles of any element.
IE uses something called "currentStyle", Firefox (and I assume other "standard compliant" browsers) uses "defaultView.getComputedStyle".
You'll need to write a cross browser function to do this, or use a good Javascript framework like prototype or jQuery (search for "getStyle" in the prototype javascript file, and "curCss" in the jquery javascript file).
That said if you need the height or width you should probably use element.offsetHeight and element.offsetWidth.
The value returned is Null, so if I have Javascript that needs to know the width of something to do some logic (I increase the width by 1%, not to a specific value)
Mind, if you add an inline style to the element in question, it can act as the "default" value and will be readable by Javascript on page load, since it is the element's inline style property:
<div style="width:50%">....</div>
This simple 32 lines gist lets you identify a given stylesheet and change its styles very easily:
var styleSheet = StyleChanger("my_custom_identifier");
styleSheet.change("darkolivegreen", "blue");
I've never seen any practical use of this, but you should probably consider DOM stylesheets. However, I honestly think that's overkill.
If you simply want to get the width and height of an element, irrespective of where the dimensions are being applied from, just use element.offsetWidth and element.offsetHeight.
Perhaps try this:
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
var CCSstyle = undefined, rules;
for(var m in document.styleSheets){
if(document.styleSheets[m].href.indexOf(stylesheet) != -1){
rules = document.styleSheets[m][document.all ? 'rules' : 'cssRules'];
for(var n in rules){
if(rules[n].selectorText == selectorText){
CCSstyle = rules[n].style;
break;
}
}
break;
}
}
if(value == undefined)
return CCSstyle[style]
else
return CCSstyle[style] = value
}
How would one return a class computed CSS property/property array?
Like, if I have a class defined in CSS:
.global {
background-color: red;
color: white;
text-shadow: 0px 1px 1px black;
}
It's applied on the go with javascript to an element. Now I want to change this elements childrens' color to parents' (.global) element background-color.
And is there a way to read CSS properties from a previously defined class in a style tag or externally included *.css?
Something like, getCSSData([span|.global|div > h1]); (where the passed variable is a CSS selector, that gets data for exactly matching element) that would return an object with each property in it's own accessible variable?
Something like:
cssdata = {
selector : '.global',
properties : {
backgroundColor : 'red',
color : 'white',
textShadow : '0px 1px 1px black'
// plus inherited, default ones (the ones specified by W3..)
}
}
And the usage for my previously explained example would be:
// just an example to include both, jQuery usage and/or native javascript
var elements = $('.global').children() || document.getElementsByClassName('.global')[0].children;
var data = $('.global').getCSSData() || document.getCSSData('.global');
return elements.css('color', data.properties.backgroundColor) || elements.style.backgroundColor = data.properties.backgroundColor;
Is there a function built in already in javascript/jquery and I've overlooked it?
If not, what should I look for to make one?
P.S. Can be DOM Level 3 too.. (HTML5'ish..)
If you want to grab the background color of the parent element and then apply that color to the font of all of it's children you could use the following code.
$(document).ready(function(){
var global = $('.global');
var bgColor = global.css('background-color');
global.children().css('color', bgColor);
};
Here's an example on jsFiddle.net
You can access the computedStyle of an element which includes all inherited style values, here is a example that outputs the computed style of a div element in the console.
<script type="text/javascript">
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", listComputedStyles, false);
}
function listComputedStyles() {
var element = document.getElementById("myDiv");
var properties = window.getComputedStyle(element, null);
for (var i = 0; i < properties.length; i++)
{
var value = window.getComputedStyle(element, null).getPropertyValue(properties[i]);
console.log(properties[i], value);
}
}
</script>
<div id="myDiv" style="background-color: blue; height: 500px;"></div>
You can find more information here: http://help.dottoro.com/ljscsoax.php
If I understand your question correctly, you'd like to find a general approach to modifying a class; and to have that modifcation affect all of the instantiations of that class. This was the subject of another detailed discussion on SO over here.
There turned out to be an extremely interesting and useful treatment of classes that works in almost all browsers, notably excepting IE8 and below.
It's easy to set inline CSS values with javascript. If I want to change the width and I have html like this:
<div style="width: 10px"></div>
All I need to do is:
document.getElementById('id').style.width = value;
It will change the inline stylesheet values. Normally this isn't a problem, because the inline style overrides the stylesheet. Example:
<style>
#tId {
width: 50%;
}
</style>
<div id="tId"></div>
Using this Javascript:
document.getElementById('tId').style.width = "30%";
I get the following:
<style>
#tId {
width: 50%;
}
</style>
<div id="tId" style="width: 30%";></div>
This is a problem, because not only do I not want to change inline values, If I look for the width before I set it, when I have:
<div id="tId"></div>
The value returned is Null, so if I have Javascript that needs to know the width of something to do some logic (I increase the width by 1%, not to a specific value), getting back Null when I expect the string "50%" doesn't really work.
So my question: I have values in a CSS style that are not located inline, how can I get these values? How can I modify the style instead of the inline values, given an id?
Ok, it sounds like you want to change the global CSS so which will effictively change all elements of a peticular style at once. I've recently learned how to do this myself from a Shawn Olson tutorial. You can directly reference his code here.
Here is the summary:
You can retrieve the stylesheets via document.styleSheets. This will actually return an array of all the stylesheets in your page, but you can tell which one you are on via the document.styleSheets[styleIndex].href property. Once you have found the stylesheet you want to edit, you need to get the array of rules. This is called "rules" in IE and "cssRules" in most other browsers. The way to tell what CSSRule you are on is by the selectorText property. The working code looks something like this:
var cssRuleCode = document.all ? 'rules' : 'cssRules'; //account for IE and FF
var rule = document.styleSheets[styleIndex][cssRuleCode][ruleIndex];
var selector = rule.selectorText; //maybe '#tId'
var value = rule.value; //both selectorText and value are settable.
Let me know how this works for ya, and please comment if you see any errors.
Please! Just ask w3 (http://www.quirksmode.org/dom/w3c_css.html)!
Or actually, it took me five hours... but here it is!
function css(selector, property, value) {
for (var i=0; i<document.styleSheets.length;i++) {//Loop through all styles
//Try add rule
try { document.styleSheets[i].insertRule(selector+ ' {'+property+':'+value+'}', document.styleSheets[i].cssRules.length);
} catch(err) {try { document.styleSheets[i].addRule(selector, property+':'+value);} catch(err) {}}//IE
}
}
The function is really easy to use.. example:
<div id="box" class="boxes" onclick="css('#box', 'color', 'red')">Click Me!</div>
Or:
<div class="boxes" onmouseover="css('.boxes', 'color', 'green')">Mouseover Me!</div>
Or:
<div class="boxes" onclick="css('body', 'border', '1px solid #3cc')">Click Me!</div>
Oh..
EDIT: as #user21820 described in its answer, it might be a bit unnecessary to change all stylesheets on the page. The following script works with IE5.5 as well as latest Google Chrome, and adds only the above described css() function.
(function (scope) {
// Create a new stylesheet in the bottom
// of <head>, where the css rules will go
var style = document.createElement('style');
document.head.appendChild(style);
var stylesheet = style.sheet;
scope.css = function (selector, property, value) {
// Append the rule (Major browsers)
try { stylesheet.insertRule(selector+' {'+property+':'+value+'}', stylesheet.cssRules.length);
} catch(err) {try { stylesheet.addRule(selector, property+':'+value); // (pre IE9)
} catch(err) {console.log("Couldn't add style");}} // (alien browsers)
}
})(window);
Gathering the code in the answers, I wrote this function that seems running well on my FF 25.
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
/* returns the value of the element style of the rule in the stylesheet
* If no value is given, reads the value
* If value is given, the value is changed and returned
* If '' (empty string) is given, erases the value.
* The browser will apply the default one
*
* string stylesheet: part of the .css name to be recognized, e.g. 'default'
* string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td'
* string style: camelCase element style, e.g. 'fontSize'
* string value optionnal : the new value
*/
var CCSstyle = undefined, rules;
for(var m in document.styleSheets){
if(document.styleSheets[m].href.indexOf(stylesheet) != -1){
rules = document.styleSheets[m][document.all ? 'rules' : 'cssRules'];
for(var n in rules){
if(rules[n].selectorText == selectorText){
CCSstyle = rules[n].style;
break;
}
}
break;
}
}
if(value == undefined)
return CCSstyle[style]
else
return CCSstyle[style] = value
}
This is a way to put values in the css that will be used in JS even if not understood by the browser. e.g. maxHeight for a tbody in a scrolled table.
Call :
CCSStylesheetRuleStyle('default', "#mydiv", "height");
CCSStylesheetRuleStyle('default', "#mydiv", "color", "#EEE");
I don't know why the other solutions go through the whole list of stylesheets for the document. Doing so creates a new entry in each stylesheet, which is inefficient. Instead, we can simply append a new stylesheet and simply add our desired CSS rules there.
style=document.createElement('style');
document.head.appendChild(style);
stylesheet=style.sheet;
function css(selector,property,value)
{
try{ stylesheet.insertRule(selector+' {'+property+':'+value+'}',stylesheet.cssRules.length); }
catch(err){}
}
Note that we can override even inline styles set directly on elements by adding " !important" to the value of the property, unless there already exist more specific "!important" style declarations for that property.
I don't have rep enough to comment so I'll format an answer, yet it is only a demonstration of the issue in question.
It seems, when element styles are defined in stylesheets they are not visible to getElementById("someElement").style
This code illustrates the issue... Code from below on jsFiddle.
In Test 2, on the first call, the items left value is undefined, and so, what should be a simple toggle gets messed up. For my use I will define my important style values inline, but it does seem to partially defeat the purpose of the stylesheet.
Here's the page code...
<html>
<head>
<style type="text/css">
#test2a{
position: absolute;
left: 0px;
width: 50px;
height: 50px;
background-color: green;
border: 4px solid black;
}
#test2b{
position: absolute;
left: 55px;
width: 50px;
height: 50px;
background-color: yellow;
margin: 4px;
}
</style>
</head>
<body>
<!-- test1 -->
Swap left positions function with styles defined inline.
Test 1<br>
<div class="container">
<div id="test1a" style="position: absolute;left: 0px;width: 50px; height: 50px;background-color: green;border: 4px solid black;"></div>
<div id="test1b" style="position: absolute;left: 55px;width: 50px; height: 50px;background-color: yellow;margin: 4px;"></div>
</div>
<script type="text/javascript">
function test1(){
var a = document.getElementById("test1a");
var b = document.getElementById("test1b");
alert(a.style.left + " - " + b.style.left);
a.style.left = (a.style.left == "0px")? "55px" : "0px";
b.style.left = (b.style.left == "0px")? "55px" : "0px";
}
</script>
<!-- end test 1 -->
<!-- test2 -->
<div id="moveDownThePage" style="position: relative;top: 70px;">
Identical function with styles defined in stylesheet.
Test 2<br>
<div class="container">
<div id="test2a"></div>
<div id="test2b"></div>
</div>
</div>
<script type="text/javascript">
function test2(){
var a = document.getElementById("test2a");
var b = document.getElementById("test2b");
alert(a.style.left + " - " + b.style.left);
a.style.left = (a.style.left == "0px")? "55px" : "0px";
b.style.left = (b.style.left == "0px")? "55px" : "0px";
}
</script>
<!-- end test 2 -->
</body>
</html>
I hope this helps to illuminate the issue.
Skip
You can get the "computed" styles of any element.
IE uses something called "currentStyle", Firefox (and I assume other "standard compliant" browsers) uses "defaultView.getComputedStyle".
You'll need to write a cross browser function to do this, or use a good Javascript framework like prototype or jQuery (search for "getStyle" in the prototype javascript file, and "curCss" in the jquery javascript file).
That said if you need the height or width you should probably use element.offsetHeight and element.offsetWidth.
The value returned is Null, so if I have Javascript that needs to know the width of something to do some logic (I increase the width by 1%, not to a specific value)
Mind, if you add an inline style to the element in question, it can act as the "default" value and will be readable by Javascript on page load, since it is the element's inline style property:
<div style="width:50%">....</div>
This simple 32 lines gist lets you identify a given stylesheet and change its styles very easily:
var styleSheet = StyleChanger("my_custom_identifier");
styleSheet.change("darkolivegreen", "blue");
I've never seen any practical use of this, but you should probably consider DOM stylesheets. However, I honestly think that's overkill.
If you simply want to get the width and height of an element, irrespective of where the dimensions are being applied from, just use element.offsetWidth and element.offsetHeight.
Perhaps try this:
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
var CCSstyle = undefined, rules;
for(var m in document.styleSheets){
if(document.styleSheets[m].href.indexOf(stylesheet) != -1){
rules = document.styleSheets[m][document.all ? 'rules' : 'cssRules'];
for(var n in rules){
if(rules[n].selectorText == selectorText){
CCSstyle = rules[n].style;
break;
}
}
break;
}
}
if(value == undefined)
return CCSstyle[style]
else
return CCSstyle[style] = value
}