I am building a website of which the desktop version displays 10 images all at once (5x2), which obviously doesn't look too good on a small smartphone display. In order to conquer this problem, I made 10 radio buttons (which only display on the mobile version of the website) and only show the image that accompanies the checked radio button. This was very easy to implement with HTML and CSS3 like this:
HTML:
<input type="radio" name='pdr' id="pdr1"><label for="pdr1"> Click here</label>
<div class="populardevice" id="populardevice1">stuff in this div</div>
CSS:
.populardevice {
display: none;
}
input#pdr1:checked ~ #populardevice1 {
display: inline;
}
The problem is that older browsers don't support the :checked selector. My idea was to use the CSS3 way of displaying the div if it's supported, and use JavaScript as a fallback if not. I already found this, which is basically what I want. The only problem is how do I detect if support for the :checked selector is present? I was thinking of Modernizr but it seems like all that would do is create an additional class in my CSS that says no-checked (right?), which would be of no use to me since I want to run a piecie of JS in that case. Or would Modernizr be fit for this case, utilizing it something like this (pseudo-code - I have no idea how to write this yet but if it's the solution, I will find out how):
if (Modernizr.:checked supported) {
use that and terminate this function;
} else {
Execute the JavaScript function from the link above;
}
Or do you guys advise me to implement something completely different?
Thanks in advance.
From the Modernizr website:
Using Modernizr with JavaScript
The Modernizr object
Modernizr keeps track of the results of all of it's feature detections
via the Modernizr object. That means that for each test, a
corresponding property will be added. You just have to test for
truthiness in your code to figure out what you want to do
if (Modernizr.awesomeNewFeature) {
showOffAwesomeNewFeature();
} else {
getTheOldLameExperience();
}
So your pseudo code was pretty close!
Related
Is there anyway to select the first instance of a tag on a page?
I'm using Drupal and the client is changing one field to another, but temporarily needs both fields (due to events created with the old field, and ongoingly, for new events), however they only want one to display.
I want to make it so that the first instance of the <label>content</label> and the <span class="date-display-single">content</span> are not visible.
CSS only (I don't know if this is suitable for you):
label:first-of-type, .date-display-single:first-of-type {
display: none;
}
If you must support older versions of browsers, which don't support the :first-of-type pseudo class, you can go with the vanilla JS solution proposed by KingKongFrog
document.getElementsByTagName("label")[0].style.display = 'none';
document.getElementsByClassName("date-display-single")[0].style.display = 'none';
In order to get CSS3 effects (border-radius, box-shadow...) on IE 6/7/8, I'm using css3pie.
However, css3pie generates some css3-container (v1) / css3pie (v2) tags in DOM, which disorders the expected architecture. Here is an example:
CSS
pre {
border: 1px solid #aaa;
border-radius: 5px;
behavior: url(pie.htc);
}
HTML
<div class="foo">bar</div>
<p class="getme">paragraph</p>
<pre>preformatted</pre>
jQuery
// undefined expected: getme
alert($("pre").prev().attr("class"));
// css3-container expected: p
alert($("pre").prev()[0].tagName);
// getme expected: foo
alert($("pre").prev().prev().attr("class"));
// 4 expected: 3
alert($("body").children().size());
// will not set expected: Impact
$("p+pre").css({fontFamily: "Impact"});
// it almost affects all such jQuery selctors
The actual generated source is like this:
<DIV class="foo">bar</DIV>
<P class="paragraph">paragraph</P>
<css3-container...>
<border...>
<shape...><stroke></stroke><stroke></stroke></shape>
</border>
</css3-container>
<PRE>preformatted</PRE>
Has anyone encountered this kind of problems? Any workaround? Is there an alternative to css3pie to get CSS3 working on IE 6/7/8?
I tried using CSS3PIE too, and faced similar problems (mostly with jquery and mediaqueries). I found no easy/practical solution for all the problems it causes, indeed.
My advice would be to use Modernizr's load to progressively enhance older IE's user experience. It requires an harder/longer process, as you've to setup a single polyfill for each and every CSS3 feature. As mario.tco already told you, there's a list of cross-browser polyfills on Modernizr's repo. And here's a list of feature detection snippets.
Also have a look at html5please and caniuse.
In regard to IE6 and 7, unless your site statistics indicate something different, usage rates are below 1% on average (with some exceptions, check ie6countdown), so you can almost ignore them. However, with conditional comments you can target each IE<10 version with specific fallbacks.
Keep in mind that you don't really need to have box-shadows and other visual decorations (unless they are needed for usability) on IE<9. Indeed, any fallback will probably cause a huge performance problem (think about what hardware an IE7 user could have). Websites don't need to look exactly the same in any browser.
CSS3PIE is a very useful and powerful way to simulate CSS3 rounded corners - and in my company it is the one that we chose, but there are many other ways to do it.
The way CSS3PIE creates the rounded corners it will create the <css3-container> tag as the previous sibling to the element that has the behavior attribute, so it will change DOM structure and break your prev() calls. The css-container is important because it is a VML drawing of the rounded corner background behind your <pre> tag.
One way you could do this would be to wrap your <pre> tag in something else like a <div> and then use that <div> to navigate the DOM using the prev() function.
Another way you could do this would be to create a jQuery plugin like this
/* This adds a plugin prevPie and nextPie - it is the same as the
existing prev and next, but it will ignore css3-containers. */
(function($){
function addPlugin(name) {
$.fn[name + 'Pie'] = function() {
var result = [];
this[name]().each(function(i,el){
if (el.tagName == 'css3-container') {
var val = $(el)[name]()[0];
val && result.push(val);
} else {
result.push(el);
}
});
return $(result);
}
}
addPlugin('prev');
addPlugin('next');
})(jQuery);
Now the following should work like you wanted it to in all browsers.
// undefined expected: getme
alert($("pre").prevPie().attr("class"));
// css3-container expected: p
alert($("pre").prevPie()[0].tagName);
// getme expected: foo
alert($("pre").prevPie().prevPie().attr("class"));
// P expected: div
alert($("pre").prevPie().prevPie()[0].tagName));
Have you tried this:
http://blog.reybango.com/2010/10/11/how-polyfills-fill-in-the-gaps-to-make-html5-and-css3-usable-today/
Here is a list of polyfills you can use for other features:
https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills
This is probably not the answer you're looking for, but instead of trying to get jQuery to ignore PIE's injected elements, I recommend (re)writing your jQuery to use classes / IDs more and be less dependent on page structure. This has the benefit of making your code more resilient against other page structure changes, as well as making your code a bit more portable and reusable.
When you must traverse the DOM, most (if not all) of jQuery's traversal methods include a filter selector argument that you can use to exclude PIE's elements, for example:
$("pre").prevUntil('*', 'not(css3-container)')
$("body").children('not(css3-container)')
Instead of just using the raw prev() add a CSS selector to it to narrow down the search
$("pre").prevUntil('p').attr("class");
// OR
$("pre").prevUntil('.paragraph').attr("class");
If you are going to use a CSS3 "hack" to make IE 6/7/8 behave correctly don't try and rely on expected DOM structure when walking the DOM try to be more specific.
EDIT
changed the prev() function call to prevUntil()
I have an app built using jQuery (and using various jQuery-UI tools).
For some reason, i have to port it to smartphones/tablet computer, and decided to use jQuery Mobile for that (in order to minimize the number of changes).
In my vanilla app, I created some elements of the page on the fly, depending of user interactions.
For example a slider could be created like that (p is an object with a bunch of params):
function createSlider(p){
return $("<div/>",{
"id":p.id,
"class":p.divClass,
}).slider({
"orientation": p.align,
"min":p.constraint.min,
"max":p.constraint.max,
"step":p.step,
"value":p.curVal,
"animate":"normal"
/*and some event handling here, but it doesn't matter*/
});
}
And it will produce a nice looking slider. Now it looks like:
function createSlider(p){
return $("<range/>",{
"id":p.id,
"class":p.divClass,
"min":p.constraint.min,
"max":p.constraint.max,
"step":p.step,
"value":p.curVal,
});
}
But as it's created on the fly, all the stuff done by jQuery Mobile on the page load isn't done on it.
Is there a way to force that initialization without writing the slider in the html?
Thanks.
EDIT: I found in the doc that it could be achieved using container.trigger("create");
However this does not work yet.
EDIT2: Ok create was the solution.
According to the documentation (see edit in the question), using trigger("create") on the containing element works.
And to make that work, you also need to remember that range is an input type and not a tag...
Working solution:
function createSlider(){
return $("<input/>",{
"type":"range",
"id":"sl",
"min":0,
"max":15,
"step":1,
"value":1,
});
}
function appendSlider(){
$("#yourdiv").append(createSlider()).trigger("create");
}
As a sidenote, the documentation for jQuery mobile lacks a search option.
Try calling .page() on the container the content is being added to. Alternatively, adding .page() to the content you're returning may also work.
Hi I have this following code with jquery , so it will alternate colors on each row of a table:
$("tr").filter(':nth-child(2n+1)').addClass('odd').next().addClass('even');
but unfortunately it doesnt work when the table comes from an ajax call .. is there a way to put this into a $("tr").live... and make it work like that? .. I have tried different aproaches like this: ( I know the syntax may not be correct ).
$("tr").live({
$("this").filter(':nth-child(2n+1)').addClass('odd').next().addClass('even')
});
But doestn seem to work
live isn't a catch-all solution for problems that come from dynamic content. It only works with events. Normally, you listen for events with bind; when your content is dynamic, live is a way to capture events reliably. So you need another solution for styles...
The simplest solution is to define your CSS using nth-child:
tr:nth-child(2n+1) {
// whatever the odd styles are
}
tr:nth-child(2n) {
// whatever the even styles are
}
This won't work in all browsers, since it's CSS3. (In particular, it won't work in Firefox 3 or Internet Explorer before version 9.)
The other solution is to update all the tr elements on the page after every AJAX call using ajaxComplete:
$(document).ajaxComplete(function() {
$('tr:nth-child(2n+1)').addClass('odd').next().addClass('even');
});
This won't have great performance, but it probably won't be a particular drain as it will always happen asynchronously. This will, obviously, work cross-browser.
Its possible to use the :odd and :even tags for example
JSfiddle example
I want to spruce up some areas of my website with a few jQuery animations here and there, and I'm looking to replace my AJAX code entirely since my existing code is having some cross-browser compatibility issues. However, since jQuery is a JavaScript library, I'm worried about my pages not functioning correctly when JavaScript is turned off or doesn't exist in a user's browser.
I'll give an example: Currently, I'm using a pure CSS tooltip to give my users (players, the site is a browser game) information on other users. For example, if the other players in the game satisfy one or more conditions, a target icon is displayed next to their name, and upon hovering over that target icon information regarding the reasons behind the target is displayed. This is useful information, as it helps my players to know who they should plan to attack next in the game.
Currently, I do such tooltips using CSS. I have a parent div that holds the image of the target icon of class "info". I then have a div inside of that with class "tooltip" that, on the hover state of the "info" class that it is contained in, is shown, but on the normal state is hidden. I thought it was rather clever when I read about it, and since no JavaScript is used it works on any CSS compliant browser.
I would like to use jQuery to achieve the same effect, mostly because it would look much cleaner, but also because I believe quick and subtle animations can make such things "randomly appearing" make a lot more sense to the user, especially on the first encounter. I'm just wondering if the two will conflict. This is only one example of this, there are numerous other examples where the inability to use JavaScript would hinder the site.
So what I'm asking I guess is, how does one make a jQuery site degrade gracefully on browsers that do not support JavaScript, but otherwise do support most CSS? My goal is for the site to function on a basic level for all users, regardless of choice in browser. The animation is a good example, but I'm also worried about the more dynamic bits, like the auto-updating with AJAX, etc. Are there any good resources on how to achieve this, or do you have any advice about the best way such degradability could be achieved?
Thanks
PS: Totally irrelevant, but Firefox seems to think that "degradability" isn't a word, but "biodegradability" (with the "bio" prefix) is. Weird...
If you consider the "Cascading Order" of css, could you not just add a css style at the very end of all your previous css definition in order to cancel any css effect you currently have for tooltip effect ?
That css rule would only be declared if Javascript is activated and JQuery detected.
That way, you are sure your css tooltip effect is not in conflict with your JQuery effect.
Something like:
a.info:hover span{ display:none}
with the use of "js_enabled" class to make this css rule conditional.
You also can do it by adding css rule on the fly:
function createCSSRule(rule,attributes)
{
//Create the CSS rule
var newRule = "\n"+rule+"{\n";
for (var attribute in attributes)
{
newRule += "\t" + attribute + ": " + attributes[attribute] + ";\n";
}
newRule += "}\n";
//Inject it in the style element or create a new one if it doesn't exist
styleTag = $E('style[type="text/css"]') || new Element("style").setProperty('type','text/css').injectInside(document.head);
if(window.ie)
{
styleTag.styleSheet.cssText += newRule;
}
else
{
styleTag.appendText(newRule);
}
}
The most simple solution for Separation of CSS and Javascrip is to remove your css class
function jscss(a,o,c1,c2)
{
switch (a){
case 'swap':
o.className=!jscss('check',o,c1)?o.className.replace(c2,c1): <-
o.className.replace(c1,c2);
break;
case 'add':
if(!jscss('check',o,c1)){o.className+=o.className?' '+c1:c1;}
break;
case 'remove':
var rep=o.className.match(' '+c1)?' '+c1:c1;
o.className=o.className.replace(rep,'');
break;
case 'check':
return new RegExp('\\b'+c1+'\\b').test(o.className)
break;
}
}
This example function takes four parameters:
a
defines the action you want the function to perform.
o
the object in question.
c1
the name of the first class
c2
the name of the second class
Possible actions are:
swap
replaces class c1 with class c2 in object o.
add
adds class c1 to the object o.
remove
removes class c1 from the object o.
check
test if class c1 is already applied to object o and returns true or false.
If something can be done completely in CSS I say keep it that way. If lack of javascript in the browser is a concern, then most of the time I show the entire page unaffected.
Say for instance I'm going to use jQuery to toggle an element when a checkbox is clicked. On page load I look at the checkbox and update the element accordingly. If javascript is not enabled the element will still appear and the site will still be usable. Just not as nice.
Man, you have a browser-based game, right? You have less than 1% users with JS disabled! And that 1% is the apocalyptic number because I can BET that you have less than that ;)
Anyhow, if you are really concerned about this, just do the site without any JavaScript. And make it functional 100%. After your site works completely without any JS flavour, just start to improve with jQuery (or any other library; jQuery is the best :P ). But with careful: do not change ANY of you HTML. It's easier than it looks ;)
And yes, if you have things that work without JS (like those tooltips) keep it!