How can I read the applied CSS-counter value? - javascript

Say you have a CSS 2.1 counter like
ol {
counter-reset: section;
list-style-type: none;
}
li:before {
counter-increment: section;
content: counters(section, ".") " ";
}
<ol>
<li>itemA</li> <!-- 1 -->
<li>itemB <!-- 2 -->
<ol>
<li>itemC</li> <!-- 2.1 -->
<li id="foo">itemD</li> <!-- 2.2 -->
(see https://developer.mozilla.org/en/CSS_Counters "nesting counters")
Is there a way to read/get the :before.content ("2.2" in this case) for <li id="foo"> in JavaScript?
Edit: In my case a Mozilla-only solution would suffice. But there really seems to be no way to access this information. At least I didn't find any at https://developer.mozilla.org/en/CSS_Counters ff.

None that I can think of, no. :before pseudo-elements are not part of the DOM so there is no way to address their content.
You could make a function that scanned the stylesheet's DOM for the :before rules and worked out which rules the browser had applied where, but it would be incredibly messy.

I thought about a workaround trying to get the .content value but even that doesn't work because its not been set. Thats really quite shocking. I don't think there actually is any easy way to get this value!
You could calculate it with some disgusting Javascript, but that would blow the whole point of this automatic css styling out the water.

I agree with the others: there is no way of doing that currently. Therefore I suggest you replace CSS-based counters with javascript based ones. It shouldn't be too difficult to write a script in jQuery to perform the same kind of labeling of list items, and then you know what values you inserted. Perhaps you could keep the CSS-based numbering as a fallback in case javascript is disabled in the browser.

var x = document.getElementById("foo");
var y = document.defaultView.getComputedStyle(x, "::before").getPropertyValue(
"counter-increment");
":before" works for backward compatibility if this doesn't, I don't know current support for "::before".
Clarification: : is pseudo-class & elements in CSS2.1, :: is pseudo-element in CSS3.
You'll probably have to parse out the number with parseInt.
Unfortunately getComputedStyle is a Standards function, which means MSIE does not support this, but FF, Chrome & Safari, and Opera do.

Related

Why doesn't `style.webKitTransition` and `style.webkitTransform` work anymore in Chrome?

These lines:
numberElement.style.webkitTransition=".1s ease-in-out";
numberElement.style.webkitTransform="scale(2.0)";
100% worked no more than a year ago. I pulled down the very stale repo to add another feature to it, but when I viewed the page, the scale wasn't working anymore. I changed my HEAD to be right at the commit where I am positive it was working, and the scale still doesn't work.
Checking out the elements at runtime, this is what I see
<span id="minute-number" style="transition: 0.1s ease-in-out; transform: scale(2.0);">TEST</span>
But visually, nothing is happening to the TEST text
Did something change with how I need to use webkitTransition or webkitTransform?
I have this question too.
In my situation, sometime I want to scale a element according to devicePixelRatio.So here is my code:
var ele = document.getElementById('my-id');
ele.style.transform = 'scale(xxx)';
ele.style.webkitTransform = 'scale(xxx)';
It didn't work.
So I console ele.style in terminal. As we known, it will console a CSSStyleDeclaration object. However, the property webkitTransform doesn't show in CSSStyleDeclaration object.
In fact, when you code ele.style.webkitTransform = xxxx which not work because of CSSStyleDeclaration object have no property webkitTransform.
I find the explanation from official document, CSS Declaration Blocks. Please attention parse a CSS declaration block step3, it looks like the lodash function _.extend({}, {...}).
I have another solution, like this:
ele.setAttribute('style', ele.style.cssText + '-webkit-transform:scale(1);')
Maybe it looks a little ugly, but it work.
Hope it will help you.
Solved it (sort of)
The elements that I was transforming were <span> elements, which apparently can't take transforms.
So I changed the css:
span {
display: inline-block;
}
and the transforms were applied. The issue now is that inline-block modifies the dimensions of my elements, which I have asked about here: Why does applying `inline-block` force dimensions onto my span element?
Something must have changed in Chrome, though, because the transforms definitely worked on the <span> elements a year ago

javascript, change class but only when it meets certain criteria

I have a class that is used ~~120 times on a page. I would like to change the margin-bottom only if other things affecting that class meet a certain criteria. The problem with the below code is that it changes everything associated with that class...not just the ones that meet the criteria.
if (actualCharacters > charactersCanFitInContainer) {
$("#Full .t16").each(function () {
$(this).css('margin-bottom', '1.25em');
});
$("#Full .t8").each(function () {
$(this).css('margin-bottom', '4.4175em');
});
}
I want to help you with your problem, but the premise is wrong. You shouldn't be trying to do this in jQuery. Maybe there is something wrong with your CSS, and it would be better to try to resolve it using CSS.
Having said that let's go over some of the problems with your code:
(1) Don't use $( selector ).each()
When you do a call to jQuery
$( selector );
This little guy returns an array of all elements that match the css of the selector.
There may be 200 elements, or even a thousand, but never, ever, do an .each() call unless you tend to explicitly change every individual element in a unique way.
$( selector ).each() runs a for loop on the array of matched selectors, which will give you performance problems if your matched set is too large.
To change all matched elements you need only to do this:
$( selector ).css('margin-bottom', '1.25em');
Read more about .each()
(2) Do not use Javascript (or jQuery), to do CSS's job
From your question it seems like you're having a problem with spacing. CSS has a number of ways to resolve this using rules like overflow, white-space, text-overflow that you should explore before resorting to scripting.
(3) Avoid using .css()
You should avoid using the $( selector ).css() function since it also introduces performance problems, especially on large sets. Instead, you should create a class that you can apply to the set and use:
$( selector ).toggleClass( 'myclass' );
//or
$( selector ).addClass( 'myclass' ); //and
$( selector ).removeClass( 'myclass' );
since these functions are more performant.
To take it a step further, do not apply a class to every set of matching elements, rather, add the class to a parent element and let the children inherit their styles from the updated parent class.
Read more about toggleClass()
(5) Stick to conventions
While it's perfectly OK to use capital letters in naming your CSS rules, you should probably avoid that since it's not standard practice. The whole point of having a standard practice is so that everyone can look at your code and know exactly what is going on, which makes your code easier to debug and share.
(6) Don't try to compensate for bad design with over-engineered solutions
Also consider that, sometimes, the requirements need to be changed if your only solution is to script the styles.
I've run into situations where what a project manager wanted to accomplish was not technically feasible. If they want a large body of text to display in a limited area, they need to allow for things like scrollbars or consider keeping a standard size limitation on blocks of text.
Go back to the stakeholder for this project and tell them that what they want to do is not reasonable, and make decisions together to design this widget better.
As a developer, you should not allow for unreasonable requirements, some things simply need to be redesigned instead of making you come up with a messy way to resolve bad design.
Conclusion
In terms of your problem, play around with the CSS rules that specifically address the spacing problem you're having (overflow, text-overflow, etc). You may need to look deeper into the styles to find a better way to do this.
In case anyone stumbles across this question and answer, I wanted to post what I ended up doing - special thanks to Qodeninja for setting me straight.
Rather than change CSS via javascript, I went with simple #media queries to handle the various font and spacing changes below. There are a variety of differing methods to do responsive design. This worked best for my requirements
#media all and (max-width: 1500px)
{
body
{
font-size:1.1em;
}
#Full
{
width:1200px;
background-color:Blue;
}
.theTeams
{
width:8.925em;
padding-left:.238em;
padding-right:.238em;
}
.t8{margin-bottom:4.75em;}
.t4{margin-bottom:11.75em;}
.t2{margin-bottom:26.5em;}
.tend{margin-bottom:0em;}
.rtR{margin-left:19em;}
#media all and (max-width: 1200px)
{
body
{
font-size:0.9em;
}
#Full
{
width:900px;
background-color:Orange;
}
.theTeams
{
width:7.75em;
padding-left:.14em;
padding-right:.14em;
height:2.1em;
}
.t8{margin-bottom:4.95em;}
.t4{margin-bottom:12.25em;}
.t2{margin-bottom:27.75em;}
.tend{margin-bottom:0em;}
.rtL{margin-left:16em;}
}

Text Wrap with CSS

I have a much longer string of numbers randomly generated. I am displaying it in one div block. As it is much longer single string. It is being written in one single line.
For example:
String str="13,7,5,1,10,7,18,11,17,10,9,16,17,9,6,19,6,13,2,18,6,9,8,5,15,4,17,16,12,8,19,16,5,9,6,16,16,5,16,12,0,14,7,11,12,11,12,16,8,3,16,3,1,10,4,14,5,9,4,3,8,3,0,19,5,7,8,7,13,14,4,3,12,6,5,19,17,3,3,19,0,4,14,8,15,17,14,5,9,3,9,19,18,8,10,0,6,1,18,16,3,16,10,9,15,10,4,7,1,7,11,6,11,16,4,11,10,1,0,15,16,19,6,15,18,14,16,16,5,17,9,19,12,7,14,14,11,19,18,10,9,5,11,2,9,0,3,15,14,1,7,14,12,17,1,10,14,5,17,16,19,10,12,6,19,16,5,19,10,9,18,14,11,9,1,18,0,10,0,19,7,17,2,4,14,2,1,3,9,17,11,7,12,4,7,5,17,2,1,6,19,14,5,3,2,6";
<div id='row' style='width:100px;height:500px;'>
</div>
I have set the fixed width to div block. I want to display this longer string in multiple rows,rather than displaying in one line.
I tried css 'text-wrap:normal'. It doesn't work. Actually, this property doesn't work in all browsers.
use the word-wrap:break-word; css style:
<div id='row' style='word-wrap:break-word;'>
13,7,5,1,10,7,18,11,17,10,9,16,17,9,6,19,6,13,2,18,6,9,8,5,15,4,17,16,12,8,19,16,5,9,6,16,16,5,16,12,0,14,7,11,12,11,12,16,8,3,16,3,1,10,4,14,5,9,4,3,8,3,0,19,5,7,8,7,13,14,4,3,12,6,5,19,17,3,3,19,0,4,14,8,15,17,14,5,9,3,9,19,18,8,10,0,6,1,18,16,3,16,10,9,15,10,4,7,1,7,11,6,11,16,4,11,10,1,0,15,16,19,6,15,18,14,16,16,5,17,9,19,12,7,14,14,11,19,18,10,9,5,11,2,9,0,3,15,14,1,7,14,12,17,1,10,14,5,17,16,19,10,12,6,19,16,5,19,10,9,18,14,11,9,1,18,0,10,0,19,7,17,2,4,14,2,1,3,9,17,11,7,12,4,7,5,17,2,1,6,19,14,5,3,2,6
</div>​
LIVE Demo
MDN docs:
The word-wrap CSS property is used to to specify whether or not the browser is allowed to break lines within words in order to prevent overflow when an otherwise unbreakable string is too long to fit.
About the text-wrap that you tried: I could not find it in MDN!, but found this in w3school:
"The text-wrap property is not supported in any of the major browsers."
Write word-wrap:break-word in .row DIV css. Write like this:
#row{
word-wrap:break-word;
}
Check this http://jsfiddle.net/Rfc2j/1/
Just use word-wrap: break-word
example fiddle : http://jsfiddle.net/Rfc2j/
Use word-wrap:break-word; property instead of text-wrap:normal
Generate a space after each comma. Such presentation is normal in human languages, and it improves readability of numeric sequences too (though I wonder what it is generated for—why would it be needed?). You can tune the amount of spacing by setting word-spacing to a negative value.
If you do not want any spaces for some reason, generate the <wbr> tag after each comma. Frowned by standards-writers (except HTML5) but virtually universally supported by browsers. However, to cover some modern oddities (in IE and Opera), add the following to your stylesheet: wbr:after { content: "\00200B"; }.
Note that if you use word-wrap:break-word, which is supported by many browsers but not all, browsers will feel free to break between digits and before a comma, too, e.g. breaking “42” to “4” at the end of a line and “2” at the start of the next line.

How can I get the font size of text in elements within a webpage

edit:
The problem seems to be that the font size isnt explicitly set and is set by the css class only. so style.fontSize always returns an empty string
if there another way to return the font size?
var allMainFrameElems = parent.main.document.getElementsByTagName('*');
for (i=0; i < allMainFrameElems.length; i++){
if(allMainFrameElems[i].style.fontSize != null){
alert(llMainFrameElems[i].style.fontSize);
}
}
If the fontSize style in not explicitly set on an element (e.g. <p style="font-size:12pt;">...</p>), you won't be able to get it from anywhere. Font-sizes are most often set in your CSS classes, which are not reachable from your element's properties, and the elements do not have any font-size related properties.
In order to even come close to doing this you will need to do some tricks and will not be able to definatively determine font size. Basically you will have to manipulate the page a great deal on every element (not good) just to determine this.
See this fiddle page, especially the pixelPerEm function I tossed together very quickly. http://jsfiddle.net/MarkSchultheiss/vc8Zy/
It is not very clean at the moment and IF I get time I might try to make it better but it might give you something to start with even if it is NOT very pretty.
EDIT: basic explanation is to utilize the em css, inject an element with a known setting, calculate the pixel offset on the injection and then remove the injected element. None of that is pretty and all of it is error/bug prone or has potential for issues.

When does IE7 recompute styles? Doesn't work reliably when a class is added to the body

I have an interesting problem here. I'm using a class on the element as a switch to drive a fair amount of layout behavior on my site.
If the class is applied, certain things happen, and if the class isn't applied, they don't happen. Javascript is used to apply and remove the class. The relevant CSS is roughly like this:
.rightSide { display:none; }
.showCommentsRight .rightSide { display:block; width:50%; }
.showCommentsRight .leftSide { display:block; width:50%; }
And the HTML:
<body class="showCommentsRight">
<div class="container"></div>
<div class="leftSide"></div>
<div class="rightSide"></div>
</div>
<div class="container"></div>
<div class="leftSide"></div>
<div class="rightSide"></div>
</div>
<div class="container"></div>
<div class="leftSide"></div>
<div class="rightSide"></div>
</div>
</body>
I've simplified things but this is essentially the method. The whole page changes layout (hiding the right side in three different areas) when the flag is set on the body. This works in Firefox and IE8. It does not work in IE8 in compatibility mode. What is fascinating is that if you sit there and refresh the page, the results can vary. It will pick a different section's right side to show. Sometimes it will show only the top section's right side, sometimes it will show the middle.
I have tried:
- a validator (to look for malformed html)
- double checked my css formatting, and...
- making sure my IE7 hack sheet wasn't having an effect.
- putting the flag class on a different, non-body wrapper element (still has the same odd behavior)
So my question is:
- Is there a way that this behavior can be made reliable?
- When does IE7 decide to re-do styling?
Thanks everyone.
Sounds a bit like a problem I've had with ie7, where the DOM is updated but the pixels on screen is not (sometimes hovering the mouse over it triggers redraw). I found a dirty hack that worked in my case (spesudo-javascript):
//Just after changing the css class:
if(isIe7()){
addAnEmptyDivAboveTheChangedElement();
removeTheEmptyDivFromTheDom();
}
For some reason this brutal hack of adding and removing an element (it might even work if you add and remove it anywhere) causes ie7 to repaint the document. It may cause a flicker though and it's an expensive hack since it forces a full repaint in an already slow browser, that's why i only does so if I'm sure it's ie7 (to not slow every other browser just because ie7 is stupid).
Can't promise it will work, though... When I tried to find a solution to my problem I found lots of different hacks that didn't work. Fixing ie7's inconsistencies with javascript is pretty much trial and error woodoo. :)
PS:
I see toggling display is allready suggested, it might work, or as in my case, it did not. I had to actually remove the element from the dom tree to make it work..
Try this:
.showCommentsRight .rightSide { display:block !important; width:50%; }
.showCommentsRight .leftSide { display:block !important; width:50%; }
Close to a solution here, maybe someone else can bring it the last bit of the way.
The page behaves as expected if:
- If the style is assigned to the body by hand instead of using javascript.
(not an acceptable solution, but worth noting)
- If the elements that IE7 isn't updating (the .rightSide's) are manually pants-kicked with something like $(".rightSide").hide().show();
That second solution is darn close to workable, except that I actually am looking for show hide behavior out of my flag, so I'd want a less intrusive thing to change that will make IE refresh the styles.
It seems like you're running into either an IE6/IE7 reflow/repaint issue or IE6/IE7 layout issue.
See http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/ for a detailed and informative analysis of what triggers reflow, repaint, etc. Also see http://www.satzansatz.de/cssd/onhavinglayout.html to find out what causes an element in IE to "have layout".
You could trigger both "having layout" and a reflow by setting height: 1%;. This is known as the Holly hack, named after the first person to document it, Holly Bergevin.
Here is my two cents. An issue with expando object was happening, so the following worked for me with a settimout delay. My issue was the background image wasn't appearing when I inserted some HTML.
app.viewModel.modules.updateSpeech = function (element) {
if ($('html').hasClass('IE7')) {
var cssClass = $(element).attr('class') || element['class'];
if (cssClass)
setTimeout(function() { $(element).removeClass(cssClass).addClass(cssClass); }, 0);
}
};

Categories