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;
}
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'm creating the DOM elements dynamically using JavaScript. I need to get height of one div to do the slide down animation. But when i use clientHeight its always returning a 0. offsetHeight also do the same. I'm getting the div when i tried console.log(). So its not because the element is not loaded in DOM. Initially i set style display:none for the div to hide it. Is this the reason for the problem? Please someone help me.
document.getElementsByClassName('myDiv')[0].parentNode.children[1].clientHeight;
I tried the below code to avoid the problem of display:none. Still clientHeight returns 0.
if(obj.style.display == "none"){ // if it's allready hidden we slide it down
obj.style.visibility = "hidden";
obj.style.display = "block";
height = obj.offsetHeight;
obj.style.visibility = "visible";
slideDown(obj,0,height,Math.ceil(height/timeToSlide));
}
Elements styled with display:none will register 0 for its dimensions. Try applying this instead:
div.myClass { position:absolute; left:-999em; }
Same effect, but your div will still have its dimensions.
You need to append in order to know the width... you can use the opacity to hide the content to your needs.
Example
CSS
.hidden {opacity: 0;}
or you can use Chis Hardie displacement solution.
If you are using jQuery you can get the height like this.
$(document.getElementsByClassName('myDiv')[0].parentNode.children[1]).height()
I need to get height of an element that is within a div that is hidden. Right now I show the div, get the height, and hide the parent div. This seems a bit silly. Is there a better way?
I'm using jQuery 1.4.2:
$select.show();
optionHeight = $firstOption.height(); //we can only get height if its visible
$select.hide();
You could do something like this, a bit hacky though, forget position if it's already absolute:
var previousCss = $("#myDiv").attr("style");
$("#myDiv").css({
position: 'absolute', // Optional if #myDiv is already absolute
visibility: 'hidden',
display: 'block'
});
optionHeight = $("#myDiv").height();
$("#myDiv").attr("style", previousCss ? previousCss : "");
I ran into the same problem with getting hidden element width, so I wrote this plugin call jQuery Actual to fix it. Instead of using
$('#some-element').height();
use
$('#some-element').actual('height');
will give you the right value for hidden element or element has a hidden parent.
Full documentation please see here. There is also a demo include in the page.
Hope this help :)
You are confuising two CSS styles, the display style and the visibility style.
If the element is hidden by setting the visibility css style, then you should be able to get the height regardless of whether or not the element is visible or not as the element still takes space on the page.
If the element is hidden by changing the display css style to "none", then the element doesn't take space on the page, and you will have to give it a display style which will cause the element to render in some space, at which point, you can get the height.
I've actually resorted to a bit of trickery to deal with this at times. I developed a jQuery scrollbar widget where I encountered the problem that I don't know ahead of time if the scrollable content is a part of a hidden piece of markup or not. Here's what I did:
// try to grab the height of the elem
if (this.element.height() > 0) {
var scroller_height = this.element.height();
var scroller_width = this.element.width();
// if height is zero, then we're dealing with a hidden element
} else {
var copied_elem = this.element.clone()
.attr("id", false)
.css({visibility:"hidden", display:"block",
position:"absolute"});
$("body").append(copied_elem);
var scroller_height = copied_elem.height();
var scroller_width = copied_elem.width();
copied_elem.remove();
}
This works for the most part, but there's an obvious problem that can potentially come up. If the content you are cloning is styled with CSS that includes references to parent markup in their rules, the cloned content will not contain the appropriate styling, and will likely have slightly different measurements. To get around this, you can make sure that the markup you are cloning has CSS rules applied to it that do not include references to parent markup.
Also, this didn't come up for me with my scroller widget, but to get the appropriate height of the cloned element, you'll need to set the width to the same width of the parent element. In my case, a CSS width was always applied to the actual element, so I didn't have to worry about this, however, if the element doesn't have a width applied to it, you may need to do some kind of recursive traversal of the element's DOM ancestry to find the appropriate parent element's width.
Building further on user Nick's answer and user hitautodestruct's plugin on JSBin, I've created a similar jQuery plugin which retrieves both width and height and returns an object containing these values.
It can be found here:
http://jsbin.com/ikogez/3/
Update
I've completely redesigned this tiny little plugin as it turned out that the previous version (mentioned above) wasn't really usable in real life environments where a lot of DOM manipulation was happening.
This is working perfectly:
/**
* getSize plugin
* This plugin can be used to get the width and height from hidden elements in the DOM.
* It can be used on a jQuery element and will retun an object containing the width
* and height of that element.
*
* Discussed at StackOverflow:
* http://stackoverflow.com/a/8839261/1146033
*
* #author Robin van Baalen <robin#neverwoods.com>
* #version 1.1
*
* CHANGELOG
* 1.0 - Initial release
* 1.1 - Completely revamped internal logic to be compatible with javascript-intense environments
*
* #return {object} The returned object is a native javascript object
* (not jQuery, and therefore not chainable!!) that
* contains the width and height of the given element.
*/
$.fn.getSize = function() {
var $wrap = $("<div />").appendTo($("body"));
$wrap.css({
"position": "absolute !important",
"visibility": "hidden !important",
"display": "block !important"
});
$clone = $(this).clone().appendTo($wrap);
sizes = {
"width": $clone.width(),
"height": $clone.height()
};
$wrap.remove();
return sizes;
};
Building further on Nick's answer:
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").css({'position':'static','visibility':'visible', 'display':'none'});
I found it's better to do this:
$("#myDiv").css({'position':'absolute','visibility':'hidden', 'display':'block'});
optionHeight = $("#myDiv").height();
$("#myDiv").removeAttr('style');
Setting CSS attributes will insert them inline, which will overwrite any other attributes you have in your CSS file. By removing the style attribute on the HTML element, everything is back to normal and still hidden, since it was hidden in the first place.
You could also position the hidden div off the screen with a negative margin rather than using display:none, much like a the text indent image replacement technique.
eg.
position:absolute;
left: -2000px;
top: 0;
This way the height() is still available.
I try to find working function for hidden element but I realize that CSS is much complex than everyone think. There are a lot of new layout techniques in CSS3 that might not work for all previous answers like flexible box, grid, column or even element inside complex parent element.
flexibox example
I think the only sustainable & simple solution is real-time rendering. At that time, browser should give you that correct element size.
Sadly, JavaScript does not provide any direct event to notify when element is showed or hidden. However, I create some function based on DOM Attribute Modified API that will execute callback function when visibility of element is changed.
$('[selector]').onVisibleChanged(function(e, isVisible)
{
var realWidth = $('[selector]').width();
var realHeight = $('[selector]').height();
// render or adjust something
});
For more information, Please visit at my project GitHub.
https://github.com/Soul-Master/visible.event.js
demo: http://jsbin.com/ETiGIre/7
Following Nick Craver's solution, setting the element's visibility allows it to get accurate dimensions. I've used this solution very very often. However, having to reset the styles manually, I've come to find this cumbersome, given that modifying the element's initial positioning/display in my css through development, I often forget to update the related javascript code. The following code doesn't reset the styles per say, but removes the inline styles added by javascript:
$("#myDiv")
.css({
position: 'absolute',
visibility: 'hidden',
display: 'block'
});
optionHeight = $("#myDiv").height();
optionWidth = $("#myDiv").width();
$("#myDiv").attr('style', '');
The only assumption here is that there can't be other inline styles or else they will be removed aswell. The benefit here, however, is that the element's styles are returned to what they were in the css stylesheet. As a consequence, you can write this up as a function where an element is passed through, and a height or width is returned.
Another issue I've found of setting the styles inline via js is that when dealing with transitions through css3, you become forced to adapt your style rules' weights to be stronger than an inline style, which can be frustrating sometimes.
By definition, an element only has height if it's visible.
Just curious: why do you need the height of a hidden element?
One alternative is to effectively hide an element by putting it behind (using z-index) an overlay of some kind).
In my circumstance I also had a hidden element stopping me from getting the height value, but it wasn't the element itself but rather one of it's parents... so I just put in a check for one of my plugins to see if it's hidden, else find the closest hidden element. Here's an example:
var $content = $('.content'),
contentHeight = $content.height(),
contentWidth = $content.width(),
$closestHidden,
styleAttrValue,
limit = 20; //failsafe
if (!contentHeight) {
$closestHidden = $content;
//if the main element itself isn't hidden then roll through the parents
if ($closestHidden.css('display') !== 'none') {
while ($closestHidden.css('display') !== 'none' && $closestHidden.size() && limit) {
$closestHidden = $closestHidden.parent().closest(':hidden');
limit--;
}
}
styleAttrValue = $closestHidden.attr('style');
$closestHidden.css({
position: 'absolute',
visibility: 'hidden',
display: 'block'
});
contentHeight = $content.height();
contentWidth = $content.width();
if (styleAttrValue) {
$closestHidden.attr('style',styleAttrValue);
} else {
$closestHidden.removeAttr('style');
}
}
In fact, this is an amalgamation of Nick, Gregory and Eyelidlessness's responses to give you the use of Gregory's improved method, but utilises both methods in case there is supposed to be something in the style attribute that you want to put back, and looks for a parent element.
My only gripe with my solution is that the loop through the parents isn't entirely efficient.
One workaround is to create a parent div outside the element you want to get the height of, apply a height of '0' and hide any overflow. Next, take the height of the child element and remove the overflow property of the parent.
var height = $("#child").height();
// Do something here
$("#parent").append(height).removeClass("overflow-y-hidden");
.overflow-y-hidden {
height: 0px;
overflow-y: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent" class="overflow-y-hidden">
<div id="child">
This is some content I would like to get the height of!
</div>
</div>
Here's a script I wrote to handle all of jQuery's dimension methods for hidden elements, even descendants of hidden parents. Note that, of course, there's a performance hit using this.
// Correctly calculate dimensions of hidden elements
(function($) {
var originals = {},
keys = [
'width',
'height',
'innerWidth',
'innerHeight',
'outerWidth',
'outerHeight',
'offset',
'scrollTop',
'scrollLeft'
],
isVisible = function(el) {
el = $(el);
el.data('hidden', []);
var visible = true,
parents = el.parents(),
hiddenData = el.data('hidden');
if(!el.is(':visible')) {
visible = false;
hiddenData[hiddenData.length] = el;
}
parents.each(function(i, parent) {
parent = $(parent);
if(!parent.is(':visible')) {
visible = false;
hiddenData[hiddenData.length] = parent;
}
});
return visible;
};
$.each(keys, function(i, dimension) {
originals[dimension] = $.fn[dimension];
$.fn[dimension] = function(size) {
var el = $(this[0]);
if(
(
size !== undefined &&
!(
(dimension == 'outerHeight' ||
dimension == 'outerWidth') &&
(size === true || size === false)
)
) ||
isVisible(el)
) {
return originals[dimension].call(this, size);
}
var hiddenData = el.data('hidden'),
topHidden = hiddenData[hiddenData.length - 1],
topHiddenClone = topHidden.clone(true),
topHiddenDescendants = topHidden.find('*').andSelf(),
topHiddenCloneDescendants = topHiddenClone.find('*').andSelf(),
elIndex = topHiddenDescendants.index(el[0]),
clone = topHiddenCloneDescendants[elIndex],
ret;
$.each(hiddenData, function(i, hidden) {
var index = topHiddenDescendants.index(hidden);
$(topHiddenCloneDescendants[index]).show();
});
topHidden.before(topHiddenClone);
if(dimension == 'outerHeight' || dimension == 'outerWidth') {
ret = $(clone)[dimension](size ? true : false);
} else {
ret = $(clone)[dimension]();
}
topHiddenClone.remove();
return ret;
};
});
})(jQuery);
If you've already displayed the element on the page previously, you can simply take the height directly from the DOM element (reachable in jQuery with .get(0)), since it is set even when the element is hidden:
$('.hidden-element').get(0).height;
same for the width:
$('.hidden-element').get(0).width;
(thanks to Skeets O'Reilly for correction)