I have this call to add HTML/CSS to an existing page:
let div = document.createElement('div');
div.style.zIndex = 9999999;
div.innerHTML = str; // some pre-defined HTML string
document.body.insertBefore(div, document.body.firstChild);
I am creating a Chrome Extension that helps developers. What's happening is that the above HTML is inheriting the existing CSS from developer's pages. I want the styling of the above HTML to be independent from the CSS/styling on the developer's page.
Is there a way to ignore all existing CSS on page? I'd like to basically create a "CSS sandbox".
I think one way to create such a sandbox, would be an iframe, but I am looking for a simpler way to do that.
Add a class to elements which you want to reset..and then apply all:unset to that class
The all CSS shorthand property sets all of an element's properties (apart from unicode-bidi and direction) to their initial or inherited values, or to the values specified in another style sheet origin.
...all:unset
Specifies that all the element's properties should be changed to their inherited values if they inherit by default, or to their initial values if not.(It will ignore all the user agent style too.)
Stack Snippet
let p = document.createElement('p');
p.style.color = "red";
p.innerHTML = "Hello"; // some pre-defined HTML string
p.classList.add("reset");
document.body.insertBefore(p, document.body.firstChild);
p {
background: black;
}
.reset {
all: unset;
}
Related
I am trying to create a very low specificity css property using javascript. Just like !unimportant (which doesn't exists)
I don't know whether this is possible or not.
My reason to look for something like !unimportant is that I am writing a small javascript plugin. In which I want to add a default style to a element which should be later easily overriden by the user.
But if I write:
element.style.backgroundColor = "green";
The user will not be able to override the above style easily without using !important. So, I added a dynamic style tag by using the following code:
var style = document.createElement('style');
// WebKit hack :(
style.appendChild(document.createTextNode(""));
document.head.appendChild(style);
and then to the above code, I added a dynamic stylesheet using the following code:
var element = document.getElementById('main');
// To use attribute names to apply the styles
element.setAttribute('custom-el', '1');
var sheet = style.sheet;
var properties = "background-color: green;";
var elName = "[custom-el]";
if (sheet.insertRule) {
sheet.insertRule(elName + "{" + properties + "}", 0);
} else if (sheet.addRule) {
sheet.addRule(elName, properties, 0);
}
Now the background-color: green can be overriden by using the following code:
div.main {
background-color: red;
}
But as you can see in css, I used higher specificity to override background-color: green i.e div + .green.
But I want the overriden to happen even when user writes the following css:
.main{ /* Could be simple class name or id name or even tag name */
background-color: red;
}
Fiddle
This might seems to be a small issue. but it is a big problem for me. Please help.
I would simply write like this:
element.style.backgroundColor = element.style.backgroundColor || "green";
Where, if backgroundColor is undefined then it uses green as backgroundColor else it would take the backgroundColor from stylesheet.
Finally I got the answer..
document.head.insertBefore(style, document.head.children[0]);
I should just insert the dynamic stylesheet above already present stylesheets in the head tag.
Working Fiddle
Unfortunately, this is not working in any IE version. I am still looking for answer.
I'm trying to develop a Firefox addon/Chrome extension. How to insert a new DOM node to arbitrary place of arbitrary page without being affected by its CSS?
Take a look at this demo: http://jsfiddle.net/za5cop0e/1/. If the web page modify the style of all div under certain node in some way (display: none as example), and I inserted my div to it without knowing that display is modified, my div will not behave as I expect.
One solution I can think of is to override all standard CSS styles with default value, which is unacceptable. Is there more elegant way to do this, for example, document.createElement('div', false), where the second argument indicates to the browser that this node does not inherit any CSS style from ancestors.
You can embed your own css to the DOM element that you are appending.
So for the DOM element you can add css for just that DOM that will override any other as inline CSS preceeds others
http://jsfiddle.net/za5cop0e/4/
var s = document.createElement('style')
s.textContent = 'div { display: none }'; // problematic CSS
document.head.appendChild(s);
// expect to show a black block, but will not show due to the CSS style above
var d = document.createElement('div');
d.style.backgroundColor = 'black';
d.style.width = '100px';
d.style.height = '100px';
d.style.display = 'block'; // here
document.body.appendChild(d);
I have a stylesheet which sets a css transition property like so (prefixed versions omitted for brevity):
transition: opacity 1s;
Then I have a number of elements on the page, and I wish to modify the transition-delay property of each element via JavaScript, to give a stagger effect. I am using jQuery like so:
$(element).css('transition-delay', delay + 's');
However, the above code does not add an inline transition-delay: Xs to the element. Instead, it results in:
<div style="transition: Xs;">
But that's fine, because it works as expected. Somehow, the browser knows that transition: Xs really means to just set the transition-delay to Xs and leave the rest intact.
However:
If I now get the inline style of that element via $(element).attr('style'), and then re-apply it to the element, $(element).attr('style', style), the HTML looks exactly the same, but now the transition has totally overwritten the other properties and essentially sets the element's transition value to all Xs ease 0s.
// HTML before - working
<div style="transition: Xs">
// then I do this
var style = $(el).attr('style');
$(el).attr('style', style);
// HTML after - broken!
<div style="transition: Xs">
Demo
A JSFiddle of exactly what I have described: http://jsfiddle.net/7vp8m/4/
What is going on?
I think just writing out the question and coding that demo really helped me to find the answer:
The HTML style attribute is not the actual style. We need to use the CSSStyleDeclaration object
Although it seems that the inline style is as simple as whatever is contained in the style="..." HTML attribute (as I had assumed), it turns out that this is not the case. Behind the scenes, inline styles (and all other styles) are actually defined by an object called CSSStyleDeclaration. The string contained in the style attribute only represents this object, but does not contain all the information needed to define a style.
This is why setting `el.style = "width: 100px;" does not work. From the MDN article on HTMLElement.style:
Except in Opera, styles can not be set by assigning a string to the (read only) style property, as in elt.style = "color: blue;". This is because the style attribute returns a CSSStyleDeclaration object. Instead, you can set style properties like this:
elt.style.color = "blue"; // Directly
var st = elt.style;
st.color = "blue"; // Indirectly
So this shows us why doing $(el).attr('style', 'transition: Xs'); will not work as expected - and this is exactly what I was running into. Doing so will modify the underlying CSSStyleDeclaration object, but not always in the way we want it to (hence my original question).
The solution is therefore to use the API provided by CSSStyleDeclaration. The following SO question proved crucial to me understanding this issue: JavaScript & copy style
Copying a CSSStyleDeclaration:
var originalStyle = el.cloneNode().style;
Here we are using the cloneNode() method because otherwise (if we just get el.style) the CSSStyleDeclaration object is copied by reference, which is not what I want since I will be changing the element's inline style and then I want to restore the original style later. Cloning the element first allows us to get a "fresh" copy of the CSSStleDeclaration that will not change when we alter the inline styles of our element el.
Replacing current inline style with the saved CSSStyleDeclaration
// first we need to delete all the style rules
// currently defined on the element
for (var i = el.style.length; i > 0; i--) {
var name = el.style[i];
el.style.removeProperty(name);
}
// now we loop through the original CSSStyleDeclaration
// object and set each property to its original value
for (var i = originalStyle.length; i > 0; i--) {
var name = originalStyle[i];
el.style.setProperty(name,
originalStyle.getPropertyValue(name),
priority = originalStyle.getPropertyPriority(name));
}
Demo
Here is an update of my original demo that implements the above methods: http://jsfiddle.net/7vp8m/11/
It breaks in chrome and the "new" opera but no in ff. In Maxthon it stops and restarts the animation the first time, then it works well.
As you said in http://jsfiddle.net/7vp8m/5 (fortunately you solved it) it is due to setting the transition delays through a inline style.
But if you force the engine to refresh the css it works somehow (stops the animation at first but then it continues, playing the animation slower): http://jsfiddle.net/7vp8m/7/
function tick() {
[...]
$.each($('.test'), function(i, e){
e.style.marginLeft = x + 'px'; // Trying with vanilla js but it is the same
e.offsetHeight; // force the refresh. It moves again but bad
});
[...]
}
This doesn't work too: http://jsfiddle.net/7vp8m/8/
$.each($('.test'), function (index, el) {
var style = $(el).attr('style');
style += '; transition-delay: '+delay + 's;'+
'-webkit-transition-delay'+delay + 's;'
$(el).attr('style', style);
delay += 0.2;
});
It seems to be a webkit bug related to transition-delay, but Maxthon stopped the animation in a similar way so it probably is a more generalized bug.
So, if it is a bug, the best option is to not use the property transition-delay through js.
I've been working with jQuery for a while, but now I want to write something in pure javascript and it's prooving to be challenging..
One of my biggest problems at the moment is that I haven't found a way to set/change styling for a class. This is not a problem for elements with id, but I want to change the styling for a group of elements with the same class and not just for one element with an id..
In jQuery I would just write:
$('.someClass').css('color','red')
Is there really no simple equivalence to this in pure js?
Try the following
var all = document.getElementsByClassName('someClass');
for (var i = 0; i < all.length; i++) {
all[i].style.color = 'red';
}
Note: As Cheery pointed out getElementsByClassName won't work in IE. The linked question has a nice way to work around this limitation
javascript document.getElementsByClassName compatibility with IE
I find it easier to use CSS variables. You can set the class to use a variable and then change that value in Javascript, thus changing the CSS.
If you style the class like:
:root {
--some-color: red;
}
.someClass {
color: var(--some-color);
}
Then you can change the variable's value in Javascript with
document.documentElement.style.setProperty('--some-color', '(random color)');
(random color) can then be anything that would be considered a valid CSS color (eg. blue, black, #626262, rgb(12, 93, 44))
Updating the value in JS automatically updates the page as well.
And of course, this can be done with any property, not just color. Here is an example that changes the padding of a class:
CSS
:root {
--some-padding: 12px;
}
.someClass {
padding: var(--some-padding);
}
Javascript
// Set padding to 15px
document.documentElement.style.setProperty('--some-padding', '15px');
// Set padding to 5rem
document.documentElement.style.setProperty('--some-padding', '5rem');
// Set padding to 25%
document.documentElement.style.setProperty('--some-padding', '25%');
Useful example: toggle dark / light mode:
(How to use css properties to dynamically set css properties)
// set to light mode:
document.documentElement.style.setProperty('--bg-color', getComputedStyle(document.documentElement).getPropertyValue('--bg-color-light'));
// set to dark mode:
document.documentElement.style.setProperty('--bg-color', getComputedStyle(document.documentElement).getPropertyValue('--bg-color-dark'));
With the respective css:
:root {
--bg-color: black;
--bg-color-light: white;
--bg-color-dark: black;
body {
background-color: var(--bg-color);
}
Sources
How to declare and use CSS variables: https://www.w3schools.com/css/css3_variables.asp
How to update a CSS variable in JS: https://css-tricks.com/updating-a-css-variable-with-javascript/
var sheet = document.createElement('style')
sheet.innerHTML = ".someClass {color: red;}";
document.body.appendChild(sheet);
What you want to change is the style sheet, I guess? Thats possible in Javascript, see
Quirksmode: Change CSS
Totally Pwn CSS with Javascript (in Internet Archive)
Is the only way to change a style to do it per-element in JavaScript? (possible duplicate)
I'm afraid there is no library for that, I really would like to see one...
var all = document.getElementsByClassName('someClass');
for (var i = 0; i < all.length; i++) {
all[i].className += " red";
}
For better coding style add another class to the elements with the code above and then use CSS to change the color of all elements like this:
.red {
color:red;
}
You can use selector library, for example Sizzle: http://sizzlejs.com/ but if you want pure JS that I guess you are stuck with getting all the elements, and then programatically "handpicking" the ones that have classes you are interested in using RegEx like this for example:
This is an equivalent of your JQuery oneliner:
for( i in document.all) document.all[i].className && /\bpost-text\b/g.test(document.all[i].className) && (document.all[i].style.color = "red")
:)
If you don't need it in one line you can make it faster (and much more readable):
var myClassName = "someClass";
var regexp = RegExp("\\b"+myClassName+"\\b/g");
var elements = document.all;
for( i in elements){
var this_element = elements[i];
if(regexp.test(this_element.className){
this_element.style.color = "red";
}
}
If "for( i in object)" doesn't work for you, just use classic for loop "for(var i = 0; i < elements.length; i++)".
It could be 'beautified' a bit with the use of some slightly more advanced JS concepts (array function mappings, folding and such), which JS version are you coding agains? I guess it's not ECMA Script 5, right?
Also, check out this question/answer Get All Elements in an HTML document with a specific CSS Class
I'm making a widget that will be added to external websites, and I have made a page that generates css for them to style it (text color, background color, font size, etc). I end up with a textarea filled with css for them to copy/paste to their website.
Is there a way to add this css to the current page in order to have a live preview?
If you want to add CSS as text
var style = document.createElement('style');
style.innerHTML = 'content';
document.head.appendChild(style);
If you want to add a CSS file
var link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'css/my.css');
document.head.appendChild(link);
I have traditionally appended a <style> block when doing elements.
var style_rules = [];
style_rules.push("#" + myElemId + " { /* Rules */ } ");
/* ... */
var style = '<style type="text/css">' + style_rules.join("\n") + "</style>";
$("head").append(style);
An important thing to note is that because you don't know what any of the existing styles is, or what id's might conflict on the page, it's very useful to keep track of your id's inside your JavaScript application, then using those to populate the injected <style> block. I also tend to run my names through a prefix function to ensure that the generic names of wrapper, and unit do not conflict (they are turned into something like myunique_wrapper and myunique_unit.
Incorporating a basic CSS reset like #myWrapper {margin: 0; padding: 0} can be a decent starting platform for building your own custom styles.
Addressing your unique case, a live preview so to speak, I would designate a div with standard elements. Then when they click "update" read in the rules and append them to the head. If you want to negate any residual effects from past rules you can remove the last <style> element or better yet give your <style> element an id. I'm not sure if that kind of selection would work, but it should.
var element = document.createElement('style');
element.setAttribute('type', 'text/css');
if ('textContent' in element) {
element.textContent = css;
} else {
element.styleSheet.cssText = css;
}
document.getElementsByTagName('head')[0].appendChild(element);
Can you add a style tag to the DOM, with the contents of the text-area in it? You may want to give it an id so you can change it later.
I recommend you start using a decent framework for your web/JavaScript development, personally I'd go with jQuery.
http://api.jquery.com/css/
There are some code snippets here that show you how to quickly set css properties for elements.