Accessible way of hiding an element until jQuery's $(document).ready()? - javascript

I have a large survey that I have made more usable with jQuery by arranging it into sections and using an accordian menu to flip through each section.
The trouble is, there is a noticable snap when $(document).ready() fires and condenses everything into an accordian menu. That is to say that before $(document).ready(), you can see the whole survey.
I did consider setting #surveyForm to display: none; in css and #surveyForm.active to display: block; but that creates a new problem:
Browsers without javascript enabled will never get to see #surveyForm.active and so they won't be able to use the survey.
Any ideas?
Cheers
-Iain

It's not clean and unobtrusive like good Javascript should be, but you can just add a Javascript snippet directly after your accordian content to initialize the accordian and hide the pieces that need hiding. The net effect should completely eliminate the "snap" and keep the form accessable to non-JS clients.

If you want to easily manage non-javascript browsers/users without the snap when JS is enabled, try the following snippet inside the head node of your page:
document.documentElement.className = 'has-js'
// or any other class name, use += and append it if you already have a class on your *html* tag
In your CSS write for the non-js scenario first and then set display to none or hide it any other way that fits you by prefixing your js-relevant css selector with .has-js.
I'll probably get downvoted for putting javascript in the head but keep in mind that from a performance standpoint (Yahoo et al) only javascript files (external) need to be loaded as late as possible.
A javascript tag itself will not make your page load longer except for the fact that it will block render while it is being parsed and executed, but in this case we want that, since you need the .has-js class before rendering starts to avoid flickering.

I haven't tried this, but perhaps you could wrap the content in <noscript> tags. Those with Javascript disabled will always see the content. Those with Javascript will not see the content. Then use JQuery to remove the <noscript> tags, thus making the content visible to those with Javascript.
EDIT:
The following example almost works. What I intended was to delete the <noscript> tags, whilst keeping their content. However, the code ends up escaping the HTML. The idea works, but I'm not sure how to implement it properly—perhaps someone else can shed some light on it:
<noscript>
<p>Display me!</p>
</noscript>
<script type="text/javascript" language="javascript">
$(document).ready(function() {
$('noscript').contents().unwrap();
});
</script>
Here's what I wanted to get:
<p>Display me!</p>
Here's what I actually get:
<p>Display me!</p>
EDIT 2:
After a little more investigation, the unwrap() method works correctly for non <noscript> tags: it works, for example, for the contents of a <div>. I'm not sure what the solution is here. It is presumably something to do with the way browsers interpret <noscript>.

This is the progressive enhancement solution I use for situations like this.

I would stick with the css display:none solution. To fix the no javascript issue you might consider using this:
<script type="text/javascript">
$(document).ready(function(){
// fade in?
});
</script>
<noscript>
<div>foobar!</div>
</noscript>

Could you try hiding everything at the top of your jquery block, and then showing it again after you do all the condensing?
$(document).ready
(
function ()
{
$("#surveyForm").hide();
... MAGIC CONDENSING
$("#surveyForm").show();
}
);
That may reduce the impact of the "snap" you're seeing.

Ways that I can think of to deal with this are:
Use javascript to load the CSS file that does initial hiding.
Put CSS in a noscript block that sets visibility to true after you've set it to false everywhere.
Both should work I think though I've not had a chance to test them properly.

You can place an inline Javascript statement which will hide the element immediately after it is rendered.
Basically...
Scripts inside the <head> section are loaded
HTML is rendered
$(document).ready() fires
So to fix that, you can simply do this
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#survey").accordion();
}
</head>
<body>
<div id="survey">....</div>
<script type="text/javascript">
$("#survey").hide();
</script>
</body>

Related

Progressive enhancement - not hiding elements with CSS

I often find myself showing/hiding elements with jQuery, for example a simple tabbed content area where the first tab is visible and the others are not until they are displayed with the javascript. I know it's not good practice to hide the initially hidden ones using CSS (display: none) and then showing the correct ones with JS as non-JS users will never see a thing. So by default I show all and then hide the relevant ones with JS.
In doing this though, the hidden elements will load and then only hide when document is ready. How can I stop this happening? Is there a way of doing this in a way that will degrade gracefully but also not have elements appearing whilst loading, and then promptly disappearing as this looks a bit shoddy.
Unfortunately, the way that Javascript works, this doesn't seem to be possible. There will always be a fraction of a second between the first rendered frame and by the time the JavaScript to hide the element gets executed I was wrong about that, jQuery seems to be able to do that. So, CSS is the best means for this. Luckily, you can add an alternate CSS stylesheet within an infamous <noscript> tag:
<style type="text/css">
#jquery-thing {
display: none;
}
</style>
<noscript>
<style type="text/css">
#jquery-thing {
display: block !important;
}
</style>
</noscript>
Here's the JSFiddle link:
http://jsfiddle.net/kylewlacy/dbWuc/
a few thoughts...
If you don't mind jQuery being littered all over the page as opposed to being all in a separate file, you can call $('#divToHide').hide(); immediately after the element appears. Not very good practice though. Although it depends on the use case, if you are largely a designer/themer creating a 5 page brochure site, you should choose what is right for you!
Or if you're a bit more of a techie, you might like to mess around with .live()/.livequery() and catch the element's insertion with JS and hide is straight away. See this post Is there a jquery event that fires when a new node is inserted into the dom?

asp.net 2.0 site and location of <script/> tags causing problems/conflicting

I have no idea how to describe this accurately/intelligently because it seems to be completely impossible, yet there must some reason for it.
I am trying to leverage jquery, jquery-ui, qtip (tooltip for jquery) and highcharts (javascript charting), but for purpose of post I could just as easily been only using jQuery and jQuery-UI.
If I include my <script/> tags at the bottom of my <head/> element I get an error trying to call the .slider() extension to configure my sliders. But if I put the <script/> tags right before the closing of my <body/> element then everything works. To illustrate, the following will not work (obviously some pseudo code below):
<head>
<script jquery.js/>
<script jquery-ui.js/>
</head>
<body>
... html ...
<script type="text/javascript">
$(document).ready(function () {
$(".slider").slider( { .. options .. } );
} )
</script>
... more html *including* the .slider elements
</body>
However, if I move the two jQuery script tags to be right above the </body> closing element things work. When the script tags are in the head element and I debug my application, basically the page does appear to have completely loaded and Visual Studio highlights the line calling the .slider() function saying it doesn't know what slider() is. Looking at the call stack, it appears to be correctly calling it from the document ready function...the mark up all appears to be there as well, making me believe the document truly is ready.
Now I didn't include things that are required by asp.net 1.1/2.0 site in my pseudo code, namely a <form/> element with runat="server' and the use of a <asp:ScriptManager/> tag (we needed that for parsing monetary values from different cultures leveraging Microsoft Ajax). I can't believe they would be causing the problem, but maybe they are. Additionally, asp.net injects several of its own script sections (i.e. for validation, post back, etc.)
Regarding the form tag...all the html and document.ready markup would be inside the form tag, while the script tags are always outside of the form tag (either above it, in the head or below it at the bottom of the body).
Obviously I could leave the script tags at the bottom, and I very well may end up doing that, but I am trying to get a clean 'template site' of which to use when creating new client sites and it just feels wrong that I have a restriction forcing me to put those tags at the bottom of the html. I'm sure our framework code (or maybe asp.net's) is simply inserting something that is causing problems/conflicts with jQuery, but I don't really know how to go about debugging/diagnosing what that problem is. So if anyone has any suggestions I'd greatly appreciate it.
It looks like jQuery 1.3.2 is being loaded by ASP.NET (see your second WebResource.axd). The two library versions are overwriting each other. Thus the reason it works when you load 1.6.2 at the end of the page.

Are <script>'s not in <head> ok?

I have had this question niggling at the curious bit of my mind for a while now and I thought I'd ask your collective expertise for an answer to this question.
To elaborate on the title, say I have this:
alert("Some JS outside ");
Outside the <head></head> tags of my HTML file. My question is whether it's ok to do this or not, and how much it is used like this.
My instincts tell me it's ok - I reckon browsers look through all HTML for <script> tags and interpret it when they see it, so it should be ok, but I'm not all that great with how browsers work.
I'm looking for a definitive (or as close as possible to definitive) answer here - is it fine to do, or not?
EDIT: To save me posting this a bunch of times, I'll say it once here. Thanks very much for all your input people. Up votes to you all! I will have to re-train myself to put JS at the bottom of pages - now that I think about it it's blindingly obvious that scripts at the bottom of the page is way better than the top. Thanks for your help everyone.
Best place for your script tags is before your closing body tag.
<html>
<head>
<title>Example</title>
</head>
<body>
Your Content
<script type="text/javascript" src="yourScriptHere.js"></script>
<script type="text/javascript">//Inline scripts etc.</script>
</body>
</html>
That said they can be other places without a problem however the reason you want them at the end is that you want to ensure the page has loaded before execution and you also do not want to stall client download progress making them wait on large scripts.
Yes, <script> blocks outside the <head> are fine.
In fact many encourage placing them at the end of the <body>. Placing them just before </body>, defers fetching/loading until after the page content...to speed up the render.
From the W3C HTML4 spec:
The SCRIPT element places a script within a document. This element may appear any number of times in the HEAD or BODY of an HTML document.
Yes. Its OK. Infact, very often it is necessary. In many cases, you may have some long-loading (read: large download) javascript that is not critical to the page, so you want the rest of your page content to load first, so you put the <script> for that javascript at the bottom of the <body> section.
A script in the body of your document will be executed when it is encountered. If it's a function, then "executing it" simply means defining the function, i.e. adding it to the list of known functions. But if it's not a function, if it's a block of stand-alone statements, they will be executed where encountered.
For example, if you wrote:
<html><head>... whatever ...</head>
<p>Foo
<script>
document.write("bar")
</script>
<p>Plugh
</html>
The browser will display:
Foobar
Plugh
This may or may not be what you want.

Dynamically Inserting <script> tags into HTML on Page Load

I'm trying to dynamically insert the Tweetmeme button using Javascript. I'm currently using jQuery throughout the site. Here's the script that I'm using. I basically want to cycle through all the blog entries with a class of journal-entry and append the following JavaScript to the end. This Javascript comes straight from tweetmeme.com. This doesn't work for me though and it has something to do with the code between append(). It doesn't like the second set of script tags.
<script type="text/javascript">
$(document).ready(function() {
$('.journal-entry').each(function(index) {
$(this).append('<script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"></script>');
});
});
</script>
Any help is appreciated.
Thanks.
Don't do this.
Inserting <script> HTML content into the DOM is unreliable: it works subtly differently in different browsers, and jQuery won't protect you from the differences.
In particularly, writing innerHTML never causes a <script> element's content to execute, but subsequently moving the <script> element from where it is to a new parent (which is part of jQuery's append process) may cause the script to execute, but not always (it depends on the browser).
In any case, it'll never work, because looking at button.js, it is calling document.write(). That function only makes sense to call at initial document parsing time; if you call it from an event afterwards, the call will simply replace the entire page content, destroying your existing page. A script that calls document.write() can only be run at document load time, from inside the execution path of a <script> element. You can't include the script in dynamically-created content at all, because it's not designed for it.
(If it makes you feel any better, it's barely designed at all; the button.js script is a badly broken load of old crap, including improper URL-escaping—using escape instead of the correct encodeURIComponent—and missing HTML-escaping. You may be better off well away from these total idiots.)
The closing </script> in the string in your append(...) call is closing the overall <script>
Try splitting it up into two strings. E.g:
$(this).append('<script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"></'+'script>');

Hiding a div using JQuery

I want to hide a div using Javascript, as soon as the page gets loaded in the browser. I am able to do that, if i use the following code :
document.getElementById("div_id").style.display='none';
But, when i try to do the same thing using JQuery,i notice that the div is visible for a couple of seconds after page loads,and then it becomes hidden. The JQuery code i use is
$(document).ready(function() {
$("#div_id").css('display','none');
});
The same thing happens, if i use $("#div_id").hide(); Is this because im using a library,which would slow down the process a bit,instead of directly using document.getElementById ? . Any way to fix this ?
Thank You.
There's an easy solution to this. Set up a CSS class as follows
.js #div_id { display: none; }
Then have the following jQuery
$('html').addClass('js');
$(document).ready(function() {
/* normal code to run when DOM has loaded here */
});
the <div> will be hidden immediately (no flashes) if users have JavaScript enabled and won't be if they don't (which circumvents possible graceful degradation problems as meder points out in his option c).
This works because when can immediately access the <html> element when the page starts to load.
The reason why document.getElementById("div_id").style.display='none'; is probably working is because you have it in the <body> after the element and therefore the script does not wait for the whole DOM to be loaded before executing.
You could either
a) insert a script element directly after the element to hide it with jQuery:
b) have inconsistent Javascript by directly using DOM methods like your first code snippet
c) hide it with CSS with the disadvantage that for CSS enabled non-JS users they wouldn't be able to see anything
I would choose between A and C, though I'm not sure exactly what you're hiding.
A:
<div id="foo"></div>
<script>$('#foo').hide()</script>
C:
div#foo { display:none; }
First, use $("#div_id").hide();. It's more idiomatic for jQuery.
Second, it's because you're using $(document).ready. Usually, that event doesn't fire until the DOM is available for use. However, because of the way bindReady() is implemented, it's possible on some browsers for this event to be equivalent to the onload event, which won't fire until everything is loaded. Unfortunately, the only way that I know of to get around this (that doesn't cause problems for disabled users who can't use JavaScript because of a screen reader) is to set a short timeout (say 50ms) and repeatedly check for the existence of $("#div_id") while the page is loading. This is a horrible hack, and I hesitate to recommend it, but it should work. That said, you're almost better off just accepting the flash of content, knowing that most users won't see it.
I think a better option would be to style the div so that it is hidden when the page is written, without any javascript.
Then, whenever you are ready to show it again, use javascript to unhide it:
$('#someId').show();
It might be cause by the way you include the scripts. The browser has to download them before they are run. So if you have a lot of js files this can cause this problem.
I think the reason is that the DOM loads progressively and the $(document).ready event is waiting for the DOM to be fully loaded before executing.
If you really want the element to be invisible when the page loads, can you define that style in your CSS instead?
I haven't tried this, but if you still want the div to be visible for non-Javascript users then I think you could do something like this:
<noscript>
<style type="text/css">
#elementid {display: block !important;}
</style>
</noscript>
More likely it's because you are waiting until the document is ready to hide it. This seems more like a job for server side script if you want it hidden by default.

Categories