I want to work with CSS styles, so I get the needed info about this HTML
<img src="imagelink" id="IMG" style="margin: 5px 4em 3% 2%;">
by this code
if(window.getComputedStyle){
style = window.getComputedStyle(dom, null);
for(var i = 0, l = style.length; i < l; i++){
var prop = style[i];
var val = style.getPropertyValue(prop);
returns[prop] = val;
}
return returns;
}
Until now, I only work with "px", so all works fine.
Now I try to work with the other units and just I get trouble.
Instead of 5px, 4em, 3%, 2%, I receive from the computedStyle recalculate absolute values for "px".
"margin-inline-start": "21.3667px"
"margin-left": "21.3667px"
"margin-right": "48px"
"margin-top": "5px"
Why is it so and how I can prevent that? I want to work with the kind of unit which is defined in the inline CSS.
Recalculate this won't work, because I cannot see any info in the computedStyle that the original kind was not "px".
Thanks a lot for helping to understand and solving that.
UPDATE
I look around to find a way to get all matching rules for a element (css class, inline-style, #import and #media). But all what i find & read are half-workes or to old and wont work now)...i'm frustrated at this point
Related
I have attached code for three objects in html. Please have a look at the SO code playground or here: http://jsfiddle.net/kr34643L/
The first one (id1) is a div and I can rotate it via css3.
The second one (id2) is a span and it is not possible to rotate it in the same way.
But it is possible to rotate a span (id3) while doing the transition. Only it doesn't stay in that position.
I have seen answers about setting display to block or inline-block, but I honestly don't understand why I have to change the display style. Especially when the transition works well but only doesn't keep the position at the end.
var id1 = document.getElementById('id1');
var id2 = document.getElementById('id2');
var id3 = document.getElementById('id3');
var rotate1 = 0;
var rotate2 = 0;
var rotate3 = 0;
id1.addEventListener("click", function(){
rotate1 = rotate1 ? 0 : 45;
id1.style.transform = "rotate("+rotate1+"deg)";
});
id2.addEventListener("click", function(){
rotate2 = rotate2 ? 0 : 45;
id2.style.transform = "rotate(" + rotate2 + "deg)";
});
id3.addEventListener("click", function(){
rotate3 = rotate3 ? 0 : 45;
id3.style.transform = "rotate(" + rotate3 + "deg)";
id3.style.transition = "transform 2s";
});
#id1, #id2, #id3 {
width: 100px;
height: 15px;
border: 2px solid;
}
<div class="centerbox">
<div id="id1" style="cursor:pointer">div can rotate</div>
<span id="id2" style="cursor:pointer">span doesn't</span><br>
<span id="id3" style="cursor:pointer">span can transform though</span>
</div>
UPDATE
The description above is only valid for Chrome
on FireFox id2 and id3 don't rotate and the transition of id3 doesn't work
on IE11 all rotations and id3's transition works
Actually the CSS transform styles are not applied for the inline elements, since they are not considered as a block elements.
For the official answer check from the W3 standard.
As per the W3 standard of transformable element:
an element whose layout is governed by the CSS box model which is either a block-level or atomic inline-level element, or whose display property computes to table-row, table-row-group, table-header-group, table-footer-group, table-cell, or table-caption [CSS21]
an element in the SVG namespace and not governed by the CSS box model which has the attributes transform, ‘patternTransform‘ or gradientTransform [SVG11].
So you can't apply the transformation styles to <span> element.
As per the DOM, the block examples are structural elements while the inline elements are text-based (non structural).
To see this visually, refer the below screenshot:
From this you can see the block and inline-block elements having a clear structure (like a square or rectangle). But the inline elements are not having a proper structure (which having the break off blocks).
And we can't properly (generically) apply the transformation for these unstructured blocks, so that the <span> elements didn't support the transformation.
I have a loop:
var takediv = document.getElementById('eye');
for(var i=0; i<categories.length; i++){
takediv.innerHTML +=^
'<img alt="'+(categories.length-i)+'" '+
'onclick="changef(this.alt)" '+
'src="mobile/img/pic/'+loc+"/mini/"+categories[categories.length-i-1][0]+'" '+
'style="cursor: pointer;"/>';
}
All images are having this css:
height: 80px;
width: auto;
And finally after loop I need to give the div this css
document.getElementById('eye').style.width
which will be sum of all inner img widhts
It is my first post here so sorry for mistakes.
Please help, and thanks!
You can use several approaches, for example getBoundingClientRect() which returns absolute values for position and width/height:
var width = document.getElementById('eye').getBoundingClientRect().width;
Just note it does not include border or padding, only the inner box.
Then there is getComputedStyle() - this will return a string suffixed with "px" so we also need to parse it using parseInt():
var width = parseInt(getComputedStyle(document
.getElementById('eye'))
.getPropertyValue("width"), 10);
Both returns size in pixels.
And as in #Rudi's answer, there is offsetWidth, and also clientWidth. This won't include margin.
Maybe you're looking for this:
var width = document.getElementById('eye').offsetWidth;
How can we use JavaScript to get the value of the declared CSS value (like the value that shows up when inspecting an element using Chrome's inspector? Everything I try and search for on the web seems to only want to give the computed value.
For my specific use case I want to know what the width will be at the end of a CSS transition, which is set in the stylesheet, not inline. When I check for the width using JavaScript, I get the computed width, which at the time of retrieval in the script is at the beginning of the transition, so shows me 0 even though in 300ms it will be a declared width like 320px.
Take a look at transitionend event. Can it be used for your use case?
EDIT
Since this answer got upvoted i'm pasting some code below.
element.addEventListener("transitionend", function() {
// get CSS property here
}, false);
I think this is what you're after:
$('#widen').on('click', function(e){
$('.example').addClass('wider');
$('#prefetch').text('The div will be: ' + getWidth('wider'));
});
function getWidth(className){
for (var s = 0; s < document.styleSheets.length; s++){
var rules = document.styleSheets[s].rules || document.styleSheets[s].cssRules; console.log(rules);
for (var r = 0; r < rules.length; r++){
var rule = rules[r]; console.log(rule);
if (rule.selectorText == '.'+className){
console.log('match!');
return rule.style.width;
}
}
}
return undefined;
}
.example {
width: 100px;
background-color: #ccc;
border: 1px solid black;
}
.wider {
width: 320px;
-webkit-transition: width 5s;
-moz-transition: width 5s;
-o-transition: width 5s;
transition: width 5s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="example">This is a simple container.</div>
<button id="widen" type="button">Widen</button>
<span id="prefetch"></span>
Keep in mind, I believe this still falls victim to cross-domain preventions (if the CSS is hosted on a CDN/other domain, you won't be able to retrieve the styleSheet, and, therefore, not be able to access then eventual width.
I selected the most helpful answer to my question, but it appears that the solution I was looking for does not exist. What I needed was to get what the width of an element would be in pixels BEFORE the transition actually was completed. This width is percent based and so the actual pixels width would vary based on a number of factors. What I ended up doing in reality was:
Making a jQuery clone of the item of which I needed the "end"
transition measurement.
Positioning the clone off screen
Adding inline styles to the clone, remove the CSS inherited transition properties so that it immediately gets the final/end width.
Using JS to save the ending width to a variable
Removing the clone with jQuery's .remove()
Doing this, I now know what the ending width in pixels would be at the moment the element begins to transition, rather than having to wait until the end of the transition to capture the ending width.
Here is a function that does what I described above.
var getTransitionEndWidth = function($el) {
$('body').append('<div id="CopyElWrap" style="position:absolute; top:-9999px; opacity:0;"></div>');
var copyEl = document.createElement('div');
var $copy = $(copyEl);
var copyElClasses = $el.attr('class');
$copy.attr('class', copyElClasses).css({
WebkitTransition: 'all 0 0',
MozTransition: 'all 0 0',
MsTransition: 'all 0 0',
OTransition: 'all 0 0',
transition: 'all 0 0'
}).appendTo($('#CopyElWrap'));
var postWidth = $copy.width();
$('#CopyElWrap').remove();
return postWidth;
};
I would like to make sub-navigation to measure its parents width and then set its own width accordingly. At the moment every sub-navigation (.primary-navigation ul ul) gets an individual class (customWidth-0 + i). Then using this class I measure its parent's width and set the width minus the padding. It's all working nice and fine, but I'm learning and I'd like to shorten the script. I was trying to loop this, use "this", but seem to get stuck at every point. It would be nice to learn to do this in a proper, robust way. Any help is very much appreciated. Thanks.
jQuery(document).ready(function( ) {
jQuery(".primary-navigation ul ul").each(function(i) {
i = i+1;
jQuery(this).addClass("customWidth-0" + i);
});
a = jQuery(".customWidth-01").prev().parent().width();
b = jQuery(".customWidth-02").prev().parent().width();
c = jQuery(".customWidth-03").prev().parent().width();
d = jQuery(".customWidth-04").prev().parent().width();
jQuery(".customWidth-01").css("width", a-31);
jQuery(".customWidth-02").css("width", b-31);
jQuery(".customWidth-03").css("width", c-31);
jQuery(".customWidth-04").css("width", d-31);
});
I took your look and added my code after commenting your sections out and got the same thing.
<script type="text/javascript">
jQuery(document).ready(function( ) {
jQuery(".primary-navigation ul ul").each(function(i) {
i = i+1;
var _this = jQuery(this), w = _this.parents('ul').width();
_this.css("width", (w-31)+"px");
//jQuery(this).addClass("customWidth-0" + i);
console.log(i);
});
/*
a = jQuery(".customWidth-01").prev().parent().width();
b = jQuery(".customWidth-02").prev().parent().width();
c = jQuery(".customWidth-03").prev().parent().width();
d = jQuery(".customWidth-04").prev().parent().width();
jQuery(".customWidth-01").css("width", a-31);
jQuery(".customWidth-02").css("width", b-31);
jQuery(".customWidth-03").css("width", c-31);
jQuery(".customWidth-04").css("width", d-31);
*/
});
</script>
It will find the div above given ul and take its width take off 31px and then apply it to given elements below. The LI elements inside of the UL will already have a 100% width and conform to that standard. If you wanted to you could just apply a position: relative; on the LIs of the .primary-navigation and then position: absolute; left: 0; top: ~20px; (top is a little skewed according to your em size.. This will do the same thing except it won't wrap your children and make it look weird.
If you gave me an exact image of what you wanted your menu to look like (not using javascript or anything maybe a designed version??) I could probably do a better job as this is still kinda hard to answer. Hopefully the code I provided helps you if not leave another comment and let me know if you have questions.
Below line is old answer.
Set a variable
var _this = jQuery(this), w = _this.parent().parent().width();
_this.css("width", (w-31)+"px");// just to be safe added px use w/e or leave blank it assumes it
This should work for you the same as you have it in the foreach.
you could also use .parents('ul')
w = _this.parents('ul').width();
function() {
$('.primary-navigation').children('li').each(
function(index) {
var parentWidth = $(this).width();
$(this).children('ul').width(parentWidth/2);
}
);
Is this what you are looking for? now all the sub menu is 1/2 of parent. you need to fix it to your specific need.
DEMO http://jsfiddle.net/La07pvf2/
I'm trying to determine if an element has a background explicitly set. I figured I could just check to see if .css('background')* was set, however, it's inconsistent between browsers. For example, chrome shows an element without a background set as
background: rgba(0, 0, 0, 0) none repeat scroll 0% 0% / auto padding-box border-box
background-color: rgba(0, 0, 0, 0)
background-image: none
whereas IE8 shows
background: undefined
background-color: transparent
background-image: none
(test case here)
*(shorthand properties of CSS aren't supported for getting rendered styles in jQuery)
Short of handling each separate case is there a better way to detect this?
temporary element approach
It's not ideal, but you could create a temporary element when your js initiates, insert it somewhere hidden in the document (because if you don't you get empty styles for webkit browsers) and then read the default background style set for that element. This would give you your baseline values. Then when you compare against your real element, if they differ you know that the background has been set. Obviously the downside to this method is it can not detect if you specifically set the background to the baseline state.
var baseline = $('<div />').hide().appendTo('body').css('background');
var isBackgroundSet = ( element.css('background') != baseline );
If you wanted to avoid possible global styles on elements, that would break the system i.e:
div { background: red; }
... you could use the following instead, but I doubt if it would work so well with older browsers:
var baseline = $('<fake />').hide().appendTo('body').css('background');
background
I spent some time with a similar issue - attempting to get the original width value from an element when set to a percentage. Which was much trickier than I had assumed, in the end I used a similar temporary element solution. I also expected, as Rene Koch does above, that the getComputedStyle method would work... really annoyingly it doesn't. Trying to detect the difference between the source CSS world and the runtime CSS world is a difficult thing.
This should work:
function isBGDefined(ele){
var img = $(ele).css('backgroundImage'),
col = $(ele).css('backgroundColor');
return img != 'none' || (col != 'rgba(0, 0, 0, 0)' && col != 'transparent');
};
DEMO
I didn't bother to test against the background property because in the end, it will change the computed styles of either backgroundImage and/or backgroundColor.
Here's the code run against your test case (with another added): http://jsfiddle.net/WG9MC/4/
this article explains how:
http://robertnyman.com/2006/04/24/get-the-rendered-style-of-an-element/
function getStyle(oElm, strCssRule){
var strValue = "";
if(document.defaultView && document.defaultView.getComputedStyle){
strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
}
else if(oElm.currentStyle){
strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
return p1.toUpperCase();
});
strValue = oElm.currentStyle[strCssRule];
}
return strValue;
}
Using the approach suggested by #pebbl I wrote a small jQuery function, hasBack(), to determine if an element has its background set.
$.fn.hasBack = function()
{
var me = $.fn.hasBack;
if(!me.cache)
{
// get the background color and image transparent/none values
// create a temporary element
var $tmpElem = $('<div />').hide().appendTo('body');
$.fn.hasBack.cache = {
color: $tmpElem.css('background-color'),
image: $tmpElem.css('background-image')
};
$tmpElem.remove();
}
var elem = this.eq(0);
return !(elem.css('background-color') === me.cache.color && elem.css('background-image') === me.cache.image);
}
This was tested in Chrome v22, Firefox v15, Opera 12.1, IE9, IE9 set to browser modes 9 compat, 9, 8, 7 and quirks mode.
Test case here.