Can't diagnose: Background position different on page open - javascript

I am using parallax.js on my web page.
http://www.edizarca.com/karpaz/ (page has been now updated, parallax is remove until a feaseable solution found)
But open the page and keep refreshing. Sometimes the background image starts eerie(off position). Ive tested both in chrome and firefox and I can't figure out why its doing this.
Do you have any idea?
Thanks

The following is what I've discovered by inspection.
parallax.js stores the initial top offset of the element to which it is applied. This value is stored in a variable called firstTop. The background-position will be placed based on the value of firstTop and the current scroll position, in such way that background-position will only be able to reach 0 if firstTop is 0 [for example if firstTop is 96 background-position will not be less of 67].
Note: more about 96 later.
That's right, firstTop is not always 0, form time to time I manage to get to a non-zero value. I suspect it has something to do with browser cache.
So, from where does the value firstTop come from? Here is the code:
//get the starting position of each element to have parallax applied to it
$this.each(function(){
firstTop = $this.offset().top;
});
Where offset is a function defined in JQuery. In the particular case of querying an element it will fall back to getBoundingClientRect. So, if the problem where there, it would be a bug of the browser...
So, to look in another direction... the value I've got is 96 and it is just [sometimes] after a cache clean. At the break point there is nothing rendered yet except for a gray background an a scroll bar... but if I have not cleared the cache at the break point the layout of the page is visible.
About 96, it is the height of the div with id "header". By the moment I hit the break point the height differs, depending of if I have cleaned the cache. If I have cleared cache it is [sometimes] 96, if have not it is 150 (but now the div with id "wrapper" has position: relative and it's top offset is 0).
So.... how do we explain this behaviour?
The file style.css of course. If the cache is invalidated the browser has to download it again, meanwhile it will go to execute javascript. If it reads the position of the div with id "wrapped" before the css is applied then the offset is wrong. Of course when the style is loaded from cache it is applied right away leaving no chance for javascript to misbehave.
Note: I also got a firstTop of 233 and a height of the div with id "header" of 195.875.
The solution? I don't know. I suspect parallax.js could allow some way to set a fixed initial offset. (there is no way to set the initial offset as the code stands).
You could look for a library that allows to check for the styles. (Note: reading the styles with javascript doesn't work, because they may be loaded but not applied).
If I were you, I would modify parallax.js (or try another version). There is no need to modify parallax.js.
EDIT 1:
You should try to:
Run your code with the defer attribute.
try to use setTimeout
the idea is to make the browser execute the initialization of parallax "a bit later" so that it will apply css but not "too late" that the user will start interacting with the page.
EDIT 2:
Place the styles before any javascript (or put javascript at the end of the document).
Use $(document).load rather than $(document).ready to run parallax.js

Related

Get reliably the height of an hidden element

The problem context
I need to resolve the height of the content of an iframe after loading it (in order to adapt the height of the iframe element itself). The problem is that the iframe could be in a hidden state (one of its containers/parents set to display:none), when the loading is done.
I can't find a way to get the correct height of the iframe content as long as I don't display it. Using jQuery.height() returns 0 on Firefox.
An example demo here:
https://codepen.io/anon/pen/gKBQeP?editors=1111
(you'll notice how the height is reported differently in case you immediately click on the Tab3, where the iframe is, making that visible, or if you wait a couple of seconds after loading and then click on the Tab3)
Cannot write height on the element, right after displaying it.
Moreover, after making it visible again I still cannot get the real height of the content; it still returns 0 like it is hidden. I assume because the iframe-content is still in the process of getting rendered, even if the DOM tree of the iframe has been shown already.
If I setTimeout few milliseconds after making it visible then I can get the correct height (that doesn't make much sense to me....🤔).
I really don't like to set a timeout in order to read the content height.
What is a reliable, cross-browser, way to get the height of a hidden element, even when this is hidden (or in the process of becoming visible)?
My solution
At the moment I:
trigger the read/write of the height right after I know the element is visible again.
use setTimeout() to wait half-second (feels sluggish 😒) before reading/writing the height of the element.
Note (the actual question)
I am trying to find less hacky as possible solutions; so I want to avoid:
displaying (or cloning) the element quickly (taking care saving+restoring css properties, making them persistent and inline; or taking care of avoiding flickering in the page), to read the dimensions and quickly set it back to hidden (😖).
using setTimeout to wait the element dimensions being restored (and readable/writeable correctly) in order to work on them immediately after showing the element itself.
It's a bit hacky but rather than display:none (I assume that's how it's being hidden) you could set something like:
top: -10000px;
left: -10000px;
position: absolute;
It's "hidden" since it won't be visible, but you will still be able to get its height. Then after you get the height you can remove these styles to make it visible.

How to change css file for this aim?

We are making this template in our language, Persian, that is right-to-left (RTL). Template address
Now, all parts are RTL, except that the submenu that opens to the right side,
Question: What changes should be made to this css file of the template, so that submenu width will be the same as its menu width? Or: How can the submenu be made to open on the left side?
Be aware that am not talking about the text in the submenu (text is rtl now as you see in picture)
Just a thought off the top of my head ...
I suspect you would adjust this line:
width: 140px; /*width of sub menus*/
to reflect a narrower width for your needs.
If you need to do this dynamically, you may have to do some work with Javascript to check the text being applied, then adjust the class reference to a custom class reference ... OR ... apply the new width to the element directly ... once the drop down entries have been filled.
Ah, ok, I see now. The problem here is that with the particular component you are using, you cannot adjust it with only CSS. The reason why is that the Javascript completely rewrites your CSS for that portion of the menu every time a user hovers their mouse over it. You're going to have to do some adjustment inside the Javascript to solve this.
There are several ways to go about this, I'm only going to get into one of them.
One way to solve this is adjust how the menu is rewriting it's CSS on the fly for the submenu. In this case, you can have the Javascript write a negative value in for the "left:" CSS element attribute to have the submenu position itself to open as you're wanting. Note: With this solution, this may not work in older Internet Explorer browsers - I'm not sure if that's a concern here. However, it will work just fine in the modern browsers (at least the ones I've been poking about with).
Open up your copy of the ddsmoothmenu.js file, that's the little bugger that is causing all the problems here.
The change needs to be done in the
$curobj.hover(function(e){..})
function. Stay with me, I'll explain...
That function is calculating the starting left position of your submenu once the user positions their mouse over the main menu choice. Namely, this line here is the culprit:
var menuleft=header.istopheader && setting.orientation!='v'? 0 : header._dimensions.w
As you can see, it is returning a '0' for you, which means it will anchor the left side of the submenu, forcing it to spill out to the right like it does now.
However, fear not!
Since you need the submenu to anchor on the right side and spill out to the left instead, we simply need to change this from assuming '0' to a formula with a little intelligence behind it.
What we need, is for the Javascript to find the correct position to anchor the submenu on the right. We do this by helping the routing understand what the "right side" of the "header" element is.
To find this, we simply take the width of the header, remove from that the left offset of the a-href tag that actually contains the header text (this is in case of any margins that exist - which this has some set in the CSS) and then remove the actual width of the submenu UL tag itself. Now as a sidenote, I wish I didn't have to use something so imprecise as assuming the header is the first child, but... eh... sometimes you work with what you got.
So comment out the line I mentioned above, and put this line in instead:
var menuleft=((header._dimensions.w-header.childNodes[0].offsetLeft)-header._dimensions.subulw);
And from what I see, it should open out towards the left as you were needing it to do in the first place.
Hope this answer helps more than my previous one.

What actions and events cause a browser to repaint its entire viewport?

I'm trying to implement the wmd-editor from the google code repository (like the one used on stackoverflow right here) and I'm running into an issue.
As you type into the textarea, it kicks off two paint operations in the browser. One to repaint the textarea itself, and one to repaint the preview panel. You can watch this happening on stackoverflow by opening the chrome inspector and using the timeline tab while typing some text into a question field.
But on my page, the browser repaints the entire viewport when it has to do these paint operations. And that takes much longer... about 100ms for each paint operation on my page versus about 1ms on stackoverflow.
In my testing this seems to be css related... I can recreate this behavior in the wmd-new example page by stripping all styles.
My page isn't public yet, but hopefully I can ask in a generic way... what will cause the browser to repaint the entire viewport on a dom change instead of just repainting that portion of the dom?
A view of what I'm talking about here.
AHA! Ah-effing-ha! (forgive the enthusiasm)
The issue is that I was using the box-shadow css property to frame my page. It takes longer to reflow/repaint content when the browser needs to calculate that shadow on each change (~100ms vs ~1ms). And when using wmd-editor, you're updating the dom on each keypress, so that difference adds up. And the effect is most exaggerated when the browser is maximized, as it recalculates the entire viewport.
So maybe that's one of the reasons stackoverflow doesn't have any frames or shadows on the page... just clean edges.
You can see what I mean at this example page. Open it up in firefox, maximized the page, and start typing away. Now use firebug to remove the box-shadow property on the body element, close firebug back up and try again. Big difference.
Thanks to Balpha for his comment, which was spot on.
Check this presentation, around slide 70 and the next ones. They explain a bit what can cause reflow and repaint.
http://www.slideshare.net/nzakas/high-performance-javascript-webdirections-usa-2010
Without the specific code / CSS is hard to answer but I can say something general like, if the fragment DOM that was changed influences other elements in the page :)
Also note that in stackoverflow WMD, when you enter a newline it also causes a whole viewport repaint. So maybe it has something to do with your WYSIWYG area not having width and height well defined? I'm guessing that if you give them width and height they won't affect other elements in the page

expanding drop down area above instead of below with javascript

Ok so the story is my users need a multi-select dropdownlist, which doesn't exist in ASP.NET, so the simple solution I'm going with is I'm using listboxes with multiselect on and I start them off at size 1, and onmouseover I change the size to say 10, onmouseout sets it back to one. Simple enough and the users don't know the difference.
Now, my issue comes from the fact that since I have any number of controls on my web app, I've set these listboxes to higher z-index numbers than the other controls, which creates a problem: on my listboxes closer to the bottom of the page the list expands below and not above, and part of the listbox goes under the bottom of the page but since onmouseout resets the size of the listbox I can't scroll the page down.
Does anybody know what I need to set to make it expand up instead of down?
edit Also, some may ask "why don't you just rearrange the listbox to a higher position in the page," the reason this isn't a viable option is I have well over 40 controls on the page and it they're grouped cohesively, I didn't just randomly place them where they are.(ie. investment info in one section, account in another, suitability in another)
EDIT: It's worth noting that the jQuery version of the below will be more compact and, in my opinion, more easily understood.
Glo, the code you have currently would be helpful here, especially since it seems you will have difficulty changing anything we give, or implementing what we might describe. Anyway, this works as intended in IE7, Firefox, and Opera; Safari and Chrome go quirky with it: http://jsfiddle.net/bUFzq/35/ (modified from http://www.plus2net.com/html_tutorial/html_frmddl.php).
The CSS just makes the select position-able relative to its default placement. Elements can only be positioned relative to other positioned elements. `position: relative;' leaves the element where it was until you move it, unlike absolute and fixed. It also positions relative to the edges of its nearest positioned ancestor. (The IT industry has the unfortunate convention of increasing Y downward rather than upward; just a heads up - or down.)
element.offsetHeight is the computed height of the element - how big it appears on the screen. element.style.bottom (like its cousins top, left, and right) sets the element's offset from the corresponding edge, in the direction of the element's center. setAttribute is fairly self-explanatory; it acts as if you were actually editing the HTML. Most properties of element.style (that aren't on all other objects) represent and modify similarly named CSS properties. For example, element.style.backgroundColor sets the background-color property.
addEvent is a function copied from Dustin Diaz's Rock Solid addEvent() because the browsers don't agree very well on how to do events. However, I would have put his script in a separate file and mine in yet another if I weren't working within a single script area. I did the `var addEvent = init();' thing just so you wouldn't have to scroll through his source, even though it is a good example of good code.
mouseover & mouseout are the actual listeners, explicitly called using apply 1) because I needed that height value for later and 2) because for some reason (at least within jsFiddle) it doesn't start out in the correct position, and only if the listeners are called in that order will it get there.

innerHTML manipulation in JavaScript

I am developing a web page code, which fetches dynamically the content from the server and then places this content to container nodes using something like
container.innerHTML = content;
Sometimes I have to overwrite some previous content in this node. This works fine, until it happens that previous content occupied more vertical space then a new one would occupy AND a user scrolled the page down -- scrolled more than new content would allow, provided its height.
In this case the page redraws incorrectly -- some artifacts of the old content remain. It works fine, and it is even possible to get rid of artifacts, by minimizing and restoring the browser (or force the window to be redrawn in an other way), however this does not seem very convenient.
I am testing this only under Safari (this is a iPhone-optimized website).
Does anybody have the idea how to deal with this?
The easiest solution that I have found would be to place an anchor tag <a> at the top of the div you are editing:
<a name="ajax-div"></a>
Then when you change the content of the div, you can do this to have the browser jump to your anchor tag:
location.hash = 'ajax-div';
Use this to make sure the user isn't scrolled down too far when you update the content and you shouldn't get the issue in the first place.
(tested in the latest FF beta and latest safari)
It sounds like the webkit rendering engine of Safari is not at first recognizing the content change, at least not fully enough to remove the previous html content. Minimizing and then restoring the windows initiates a redraw event in the browser's rendering engine.
I think I would explore 2 avenues: first could I use an iframe instead of the current 'content' node? Browsers expect IFrames to change, however as you're seeing they're not always so good at changing content of DIV or other elements.
Secondly, perhaps by modifying the scroll position as suggested earlier. You could simply move the scroll back to 0 as suggested or if that is to obtrusive you could try to restore the scroll after the content change. Subtract the height of the old content node from the current scroll position (reseting the browser's scroll to the content node's 0), change the node content, then add the new node's height to the scroll position.
Palehorse is right though (I can't vote his answer up at the moment - no points) an abstraction library like jQuery, Dojo, or even Prototype can often help with these matters. Especially if you see your page / site moving beyond simple DOM manipulation you'll find the tools and enhancements provided by libraries to be a huge help.
It sounds like you are having a problem with the browser itself. Does this problem only occur in one browser?
One thing you might try is using a lightweight library like jQuery. It handles browser differences fairly nicely. To set the inner HTML for a div with the ID of container you would simply write this:
$('#container').html( content );
That will work in most browsers. I do not know if it will fix your problem specifically or not but it may be worth a try.
Would it work to set the scroll position back to the top (element.scrollTop = 0; element.scrollLeft = 0; by heart) before replacing the content?
Set the element's CSS height to 'auto' every time you update innerHTML.
I would try doing container.innerHTML = ''; container.innerHTML = content;

Categories