IE7 CSS problem: cannot get correct span width - javascript

I am having a problem getting the correct width of a span. It works in the following browsers and NOT in IE7:
Works in:
Firefox
Chrome
Safari
IE8
I need to get the correct width of the span so I can pass it as an argument to a jquery function.
Example code is identical to code with problem, but with generic class names substituted in to make the example easier to understand/refer to.
Related HTML:
...
<span class="outer-span">
<div class="inner-div">
<a href="http://www.google.com">
<span class="selected">
<c:out value="${somestring}" />
</span>
</a>
</div>
</span>
...
Related CSS:
.outer-span { width: 120px; }
When I alert($('.outer-span').width()) in all browsers EXCEPT IE7 I get 120.
In IE7, the alert shows me that the width of 'outer-span' is 700px, which is probably the width of one of its parents.
I know that to accurately reason about the problem, you probably have to see the html above the block that I've posted. What I'm looking for however, is some tips for debugging the problem, or a clue as to why IE7 acts this way or how IE7 handles things differently. I'm not looking for you to rewrite my code or come up with some CSS hack. Comment if you need more clarification on the problem.

You can't put a <div> (block element) inside a <span> (inline element). It's invalid and doesn't make sense.
Browsers may try to fix your mistake, for example by closing the <span> when it sees the opening <div>. This would cause the span to be empty and hence have no width. But this behaviour will vary across browsers.
Also, you can't put a width on an inline element. It will have no effect, unless you have IE in Quirks Mode... which may be the case if this is working for you. You really want to avoid Quirks Mode (use a proper <!DOCTYPE>!).
If you want a simple block wrapper to contain a <div>, it should probably also be <div>.

It's possible that IE7 is throwing a fit because you have a span surrounding a div, and inline elements cannot have block level children. Try applying:
.outer-span { display:block }
If that works, then I recommend changing the span in question to a div.

By default, spans are inline and divs are block elements. Having a div inside a span doesn't make a lot of sense without changing the default CSS display attribute. Try using nested divs with a CSS width on both of them, or changing the inner div into a span, or using display: inline on the inner div.

Related

Contenteditable divs hide content after reloading

For text editing purposes I use contenteditable divs in a website. When I edit some text the div height is growing dynamically and all other elements on the webiste below shift downwards. That's what I want. Finally I store the content via Ajax on a server. So far everything is working fine.
The problem is when I reload the content from the server the height of the contenteditable divs does not grow automatically to show all it's content. Instead its height stay in the initial size.
BTW, this is true for all browsers.
Does anyone have some hints to overcome this issue ?
EDIT
This is the html and javascript contendeditable relevant code
<div class="editable" contentEditable=true onkeyup="autoGrowSave(this)" onblur="update(this)" ></div>
function autoGrowSave (oField) {
if (oField.scrollHeight > oField.clientHeight) {
oField.style.height = oField.scrollHeight + "px";
}
}
I use above javascript function to auto grow the contenteditable. Actually I do not know if even I need it. The jsFiddle example from Abhitalks below does not need one. Hmm ... I have to try without...
To store content on a sever I use the onblur attribute, which works perfect.
I answer the question myself. Thanks to Abhitaks jsFiddle I found the problem which limited to auto adjust the height. For this I appreciate the answer of course ;-)
In a CSS declaration I gave the class editable an initial height of 20px. Because of this the contenteditable could not adjust its height automatically. In turn I needed the javascript function autoGrow() to compensate this issue. While this "crazy" approach worked when editing the content, it did not work when reloading the content.
So the solution is to eliminate the heightin the CSS declaration and get rid of the javascript function autoGrow(). Now it works perfect !

IE, and iframe.elementFromPoint not passing event

Update: Fiddle Demonstration -- http://jsfiddle.net/7tfbtso6/2/ -- Most of the settings work in chrome and firefox, but the only one that works in IE is Left-align: 105px. I do have overflow set to hidden on html and body, but this makes no difference. IE will not work if the element is not visible on screen. And overflow: visible on html and body give the effect of auto and no effect on the problem here.
My site uses two contentEditable divs.
#rInput is part of the document.
#rSyntax is part of an iframe under (z-index) #rInput.
In every browser I've tried so far, except IE (I'll get to that in a moment.), I'm able to determine what element is contained within the iframe using elementFromPoint().
In IE's case, this is only possible if they're not overlapping which isn't possible because a secondary purpose, as the name implies, is to provide syntax-highlighting.
The IE IFrame has to be visible, on screen, not obstructed by any objects. I've tried display: none;, visibility: hidden, and pushing it down in a div with overflow: hidden, but all of these attempts cause it not to work. I've also tried setting the height and width to small proportions.
If any of these could work, I could use two copies of rSyntax, one on top (z-index), hidden somehow, for mouse events and one for syntax highlighting.
Most of these solutions work in every browser but IE. The IE box simply demands that it be on top.
"Flickering" it with css (display, visibility, pointer-events) seems awfully hacky (and just plain awful). I haven't really tried to implement it because it seems like a last resort.
The problem is further complicated because I'm trying to capture clicks and mouseovers, for different purposes (clicks for finding content, mouseovers for tooltips--created with a div mimicking attr("title").
I've briefly tried placing the iframe on top (z-index) of the div, but there's no way to intercept the clicks and pass to the lower object because it runs in to the same problem.
Here's the script I'm using to get the objects, partly in case it's useful to anyone.
$(document).on("mousemove", "#rInput", function (e) {
$element = $(document.getElementById('frSyntax').contentDocument.elementFromPoint(e.pageX+$("#rInputContainer").scrollLeft()-10,e.pageY+$("#rInputContainer").scrollTop()-12));
if ($element.is("span") && $element.attr("title") && $element.attr("title").length) {
$("#syntip").text($element.attr("title"));
$("#syntip").css({"top": e.pageY+10, "left": e.pageX, "display": "inline-block"});
} else {
$("#syntip").hide();
}
});
I have considered transparency, and that works for this element, because it's small, but I use a similar setup with a large element that takes up more than 50% of the screen, there would be problems.
After many frustrating efforts, I concluded that pushing the top (z-index-wise) element offscreen was the only solution for IE/Edge. Flickering it with display: none causes some properties I needed, like width, to not be accurate.
Just make sure you push it farther than the element will ever be. My application is sidescrolling so I merely needed to place the css top to something like 2000.

Change paragraph content when height of a div reaches a certain percentage

I'm making a loader for a website. The HTML is as follows:
<div class="loadingContainer">
<div class="greyContainer">
<img class="eggGrey" src="img/egg-grey.png">
<p id="bluePercent">50%</p>
</div>
<div class="blueContainer">
<img class="eggBlue" src="img/egg-blue.png">
<p class="greyPercent">50%</p>
</div>
</div>
When element blueContainer has a height of 2%, I want the text in both paragraphs to be 2%. I want the paragraph text to always show the height in percentage of blueContainer. Height values are applied through an external CSS file, I am not very well versed in the language of Javascript, and I've tried some ways but I cannot figure out how I should do this.
EDIT: Some of the things I've tried (and probably miserably failed at):
function percentages(){
document.getElementByClassName("greyPercent, bluePercent"){
if (document.getElementByClassName("greyContainer, blueContainer"){
}
}
}
This is where I'm stuck at too, because I have no idea how I could tell the javascript to run the function when the element has a certain height.
EDIT: Here is a jsfiddle to illustrate what I'm doing. I gave the containers a background colour because of a lack of images.
https://jsfiddle.net/1s5tw6es/
from https://stackoverflow.com/a/9628472/2818869.
First, There is no such css-changes event out of the box, but you can
create one by your own, as onchange is for :input elements only.
not for css changes.
There are two ways to track css changes.
Examine the DOM element for css changes every x time(500 milliseconds in the example).
Trigger an event when you change the element css.
Use the DOMAttrModified mutation event. But it's deprecated, so I'll skip on it.
Nowadays, there are more solutions.
MutationObserver (If you can drop old IEs)
CSS Element Queries
But in this case, I would create function like setProgress which change both the element height and the paragraph.
Example: http://jsfiddle.net/e59u3p4j/1/
This should work:
$("document").ready(function(){ //In case you didn't use this
$(window).resize(function(){
$('#bluePercent').html($('.blueContainer').css('height')/16.0*100); //Converting height into percentage and adding it to the p tag
});
});

Detecting when styles disabled

What's the best way to detect, with JS, if the user has disabled your stylesheets? Is there a reliable way even?
How about asking them?
<div style="display:none">This site relies on CSS, please go to our CSS free version of this site</div>
Something easy would be to check the body background color for instance.
However, how likely is it someone disables CSS and not Javascript? (dunno what you use it for obviously)
I would have a small, empty div sit on the screen. When the page loads, use JS to check the 'display' property of that div. If it's 'none', then your css has successfully been loaded. If not, they may have to turned off / changed your styles.
If you're in control of the stylesheet you can have a "calibration" style.
Have a classname that applies some CSS property to an element. A good cross-browser safe property can be background-color.
When loading your JS try to dinamically create an element and apply the classname to it. Check if the properties match (the one on the element with the one you're expecting).
BoltClock's comment comes close. You can use window.getComputedStyles(calibrationElement, null) but that will fail in older IE browser versions.
See documentation for getComputedStyles
Feel free to remove the "calibration" node after you've checked it.
Assuming your primary external or inline stylesheet is loaded before the script, you can use this:
if (document.styleSheets.length){} // stylesheets are disabled
https://developer.mozilla.org/en-US/docs/DOM/document.styleSheets
It's IE5+ compatible too as per: http://www.jr.pl/www.quirksmode.org/dom/w3c_css.html
The caveat is that, if styles are turned off after the window has loaded (which only causes a browser repaint), the document.styleSheets object won't change on the fly. Additionally, as noted in the comments below, this will not work for Firefox when using the View -> Page Style -> No Style feature, for which styles are still loaded, just not applied to the view.
To detect the initial state across browsers, or changes on window.onresize, it can be done with a style reset on the body, with the following code placed after <body> or in a DOMContentLoaded event:
if (document.body.clientWidth !== document.documentElement.clientWidth) {
// Styles are disabled or not applied
}
This works if you use body { margin: 0; } in your stylesheets (with no particular custom width), because it makes the body element the same width as documentElement (a.k.a. the <hmtl> element) while styles are active.
When styles are turned off or disabled, the body.clientWidth will revert to the browser's default body width, which always has a margin (8px by default in CSS 2.1 major browsers ) and therefore different from documentElement.clientWidth.
Should your site design use a specific margin other than 8px for the body, here is an alternative option:
if (document.body.clientWidth === document.documentElement.clientWidth-16) {
// user styles are disabled or not applied (IE8+ default browser style applies)
}
At least in Safari, part of the difficulty is that with CSS off the elements still report CSS attributes. But if you test on the actual rendering of a property then you can tell. Width is probably the simplest (and most common) property you can test on.
Below is a sample script (it uses jQuery, but could easily be un-jQueryfied) that will test for CSS. We just load an empty div on the page, give it a width of 3px using CSS, and then test that div's width. If the width is not 3 then CSS is disabled. Obviously you have to make sure that this doesn't colide with any other styles you might have that could cause the width to be other than 3. But it gives the general idea.
<html>
<head>
<title>Test</title>
<style type="text/css">
#testCSS {width: 3px;}
</style>
</head>
<body>
<div id="testCSS"></div>
<div id="message"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript">
jQuery(document).ready(function(){
if (jQuery("#testCSS").width() != 3) jQuery("#message").html("CSS Disabled");
});
</script>
</body>
</html>
Edit: sorry about the messy code example. It doesn't seem to like my code tags. Here's a JSfiddle with the code. Obviously you won't be able to disable CSS and test there, but you can pull the code from it: http://jsfiddle.net/3FvdL/1/

Quickly repaint array of unicode symbols in JavaScript

I want to change background/foreground color of many symbols with the same CSS class. Right now I'm doing it with jQuery — like $('back_COLORED').css('background-color', '#00FF00'), but this approach is slow when there are many elements with such class (>900).
Seems it's because jQuery don't change CSS rules itself, but finds all elements one-by-one and applies inline styles to them. At least, this is what I see in inspector. So, the question is:
How can I change the CSS rules itself?
Will it be much faster?
Can I make it cross-browser (IE6 doesn't count)?
UPD: I'm trying to make some kind of color scheme editor. The source is at http://github.com/kurokikaze/cinnabar/. Don't mind PHP things, editor is fully client-side (with just some libraries fetched from the net).
UPD2: Tried canvas approach, still slow. Canvas branch is at http://github.com/kurokikaze/cinnabar/tree/canvas.
The most cross-browser friendly way to override a class definition is to write a new rule and add it to the end of the last stylesheet in the document. You can edit an existing style rule, but even some recent browsers can make it difficult.
function newRule(selector, csstext){
var SS= document.styleSheets, S= SS[SS.length-1];
// this example assumes at least one style or link element
if(S.rules){
S.addRule(selector,csstext,S.rules.length);
}
else if(S.cssRules){
S.insertRule(selector+'{'+csstext+'}'),S.cssRules.length)
}
}
newRule('.someclass','background-color:#0f0');
You can add as many 'property:value;' bits in the csstext as you need.
Remember to prefix a '.' to a class name or a '#' to an id,
and the css must be written as a style rule (with-hyphens, not camelCase).
Of course, it will not override inline styles, and it is overkill for small, local changes.
It also may make the redrawing of the page more obvious than changing one element at a time,
but it may be just what you need here.
There are different ways depending on which browser you are dealing with. This is documented on Quirks Mode.
Some libraries provide an abstraction layer, such as YUI's StyleSheet utility.
There should be a significant performance boost since you aren't using JS/DOM to cycle through all the elements.
Another approach would be to predefine your styles:
body.foo .myElements { … }
And then edit document.body.className
If you can select the parent div by id, maybe you could select by tag inside it? Or are there elements of the same kind that should change color and that should not, inside the parent?
It would be nice to have an idea of what you're building here. 900+ objects seems to be a lot... maybe a completely different approach could be used? Canvas, SVG?
Try hiding the items you want to change before changing them, make the change and then display them again. This is common practice to speed up things as you minimize the repaint events in the viewport. In this case when you only setting one css property it might not be that of a benefit but it´s worth a try I say.
Try:
$('back_COLORED').hide();
$('back_COLORED').css('background-color', '#00FF00');
$('back_COLORED').show();
or
$('back_COLORED').hide().css('background-color', '#00FF00').show();
I would stick in trying changing a CSS property, instead of parsing the DOM.It is about the CSS engine vs. DOM+JS here, and the winner is clear.
It happens I just uploaded a tiny library that replaces CSS by Javascript: jstyle
This is may be an overkill, but you will find in the source code of jstyle.js all the code you need to update cross browser the CSS properties of your page.
I think a better solution would be to write a more specific CSS rule (that would override the normal colour) that can be activated by simply changing one element's css class.
So for example if you had the following structural markup:
<div id="container">
<span class="colored">Test 1</span>
<span class="colored">Test 2</span>
</div>
And CSS:-
.colored { background-color: red; }
.newcolor .colored { background-color: blue; }
Then in your jquery you add the .newcolor class to the container div:-
$('#container').addClass('.newcolor');
When you do that the second CSS rule will override the first because it is more specific.
Inject the css code into a style tag:
var style = $('style').attr({
type:"text/css",
media:"screen",
id:'changeStyle'
}).html('.tempClass { color:red } .tempClass p { background:blue }').prependTo('body');
and on every changes on your color with color picker you only rewrite the html inside of #changeStyle tag.
Have no idea if it works (didn't tested) but you should give a try.
This is jQuery pluggin for work with css rules: http://flesler.blogspot.com/2007/11/jqueryrule.html
not sure about its performance, but worth a try.

Categories

Resources