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()
Related
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!
I know it's possible to change css attributes on elements on the current page:
$('.changeMyStyle').css("color", "#FF0000");
But this won't affect new elements added after the change is made.
I know it's possible to remove, add, or swap out css stylesheets to re-style a page after it's been loaded:
$('link.swappableStylesheet').attr('href', 'path/to/new/style.css');
But this is a poor solution for changing one or two attributes, especially to programmatically-determined values (such as changing color from a colorpicker).
I could probably grab a stylesheet's raw data, search it, and modify it:
var sheet= document.styleSheets[0];
var rules= 'cssRules' in sheet? sheet.cssRules : sheet.rules; // IE compatibility
rules[0].style.padding= '0.32em 2em';
// assumes the first entry in the first stylesheet is the one you want to modify.
// if it's not, you have to search to find the exact selector you're looking for
// and pray it's not in a slightly different order
But that's also a poor solution and requires IE-compatibility hacks.
This linked answer also suggests appending another <style> element and adding css there. That could work for narrow cases, but it's still not ideal (and the answer is 5 years old, so new tools may be available now).
Is there a way to alter the page's css at a selector & attribute level instead of stylesheet level or DOM element level? jQuery and vanilla javascript solutions both welcome, as well as libraries designed to do this specifically. Ideally I'd like something that's as easy and versatile as
$(document).stylesheet('.arbitraryCssSelector.Here').put('color', '#FF0000');
...where .stylesheet('.Here.arbitraryCssSelector') would modify the exact same style entry.
Even Chrome's dev tools just modifies the stylesheet it's using when you make modifications or add new rules. There's not currently a way around it, but you can keep a dedicated stylesheet at the bottom of the page that you update with the newest rules. If it's empty or contains invalid rules it will just fall back to the current stylesheet. If any library exists out there this is how it would do it, and it's very little code.
I think the key to keeping it uncluttered is to simply keep overwriting one stylesheet instead of adding new stylesheets to the DOM.
document.getElementById("dynamic-color").addEventListener("input", function () {
document.getElementById("dynamic-styles").innerHTML = "label { color: " + this.value + " }";
});
label {
color: blue;
}
<label for="#dynamic-color">Change the label's color!</label>
<input id="dynamic-color" />
<style id="dynamic-styles"></style>
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'm a rookie designer having a few troubles with this page: http://www.resolvegroup.co.nz/javasurvey.php
There are problems with the javascript operation of the expanded questions. For Internet Explorer (Version 7) the first question when expanded gets partly hidden under question 2. This happens to varying degrees with all questions, at times making the next question completely hidden and other problems.
Firefox (Version 3.03) does not have the problem as above, but you cannot get access to the explanations or select next question as in IE7.
Does anyone know what's going on with this, and how to fix it?
I'd recommend looking at using a pre-built Accordion script, like that built into the jQuery UI library: http://docs.jquery.com/UI/Accordion
Also, there's a few things I could suggest. This code of yours:
$(".score-list").slideUp(speed);
$(".score-list").removeClass("open");
$("a.open-answer").removeClass("hidden");
$(this).parent().children(".score-list").slideDown(speed);
$(this).parent().children(".score-list").toggleClass("open");
$(this).toggleClass("hidden");
could be made a lot more efficient by storing the results from a jQuery query, as well as taking advantage of jQuery's chaining abilities: quite a lot of jQuery's functions return the jQuery object itself, which means you can call a number of functions in a row without having to reference the object again and again. Here's what I mean:
$(".score-list") // my own preference is to split the calls onto
.slideUp(speed) // multiple lines to make it easier to read.
.removeClass("open")
;
$("a.open-answer").removeClass("hidden");
var $this = $(this); // store the result from a query in an object so you
// don't have to go through that again.
$this
.parent()
.children(".score-list")
.slideDown(speed);
.toggleClass("open")
;
$this.toggleClass("hidden");
If I'm not mistaken, your CSS has some wonkiness. ".question-container h3" and ".question-container h3 span" have relative and absolute positioning, respectively. Internet Explorer does not handle out-of-flow positioning very well. In result, it gets confused and tries to place these elements in weird places.
Construct the accordion without relative or absolute positioning and it should work fine.
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!