Is it possible to detect CSS support by using Javascript?
For example, is it possible to detect if the browser supports attribute selectors like this?
input[type='text'] { }
Modernizr is designed to detect browser features and may well be able to help in this instance.
http://www.modernizr.com/
This is a bit speculative as I haven't tested it out, but I believe it would be possible via JS to add a style element followed by an element that it has an effect on, and then test the values:
Speculative untested code, may or may not work (jQuery used for brevity):
$('<style type="text/css" id="foo">input[type="text"]{ width: 10px; }</style>').appendTo('head');
$('<input type="text" id="bar">').appendTo('body');
if ($('#bar').width() == 10)
{
//attr selector supported
}
$('#foo, #bar').remove();
document.querySelectorAll("input[type='text']")
But that fails for older browsers, naturally.
Other than that, you could just use the style property to check if a certain CSS property has been applied or not.
input[type='text'] {
background-repeat: no-repeat; /* or any other irrelevant, non-default value */
}
and
if (myInputElem.style.backgroundRepeat == "no-repeat") {
// selector is supported
}
Related
Consider this code (also in a fiddle):
document.getElementById("span").innerHTML += $('#input').css('fontSize');
span input {
font-size: inherit;
}
input {
font-size: 15px;
}
<span id="span" style="font-size: 30px;">
<input id="input"/>
</span>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
In Chrome and Firefox, the .css('fontSize') will return 30px, in Edge and IE it's 15px. Why does it do that? The DOM Explorer in Edge even shows the 15px in strikethrough, and therefore should take the inherited 30px as the fontSize:
And the input is rendered with a 30px font, so IE/Edge is picking it up for rendering purposes.
Update: The bug below is now fixed; FremyCompany says he/she is a program manager from the Edge team and the fix will reach customers in early 2017.
It looks very much like an IE and Edge bug. Not having found it, I reported it.
Here's an update to the snippet that sees what IE/Edge is telling jQuery via getComputedStyle or currentStyle:
var input = $("#input");
console.log("jQuery: " + input.css('fontSize'));
if (window.getComputedStyle) {
console.log("getComputedStyle: " + getComputedStyle(input[0]).fontSize);
}
if (input[0].currentStyle) {
console.log("currentStyle: " + input[0].currentStyle.fontSize);
}
span input {
font-size: inherit;
}
input {
font-size: 15px;
}
<span id="span" style="font-size: 30px;">
<input id="input"/>
<span id="size"></span>
</span>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
For me, IE11 returns 15px from both getComputedStyle and the Microsoft-specific currentStyle property (it's reassuring that they do at least say the same thing):
So it's not a jQuery bug, it's a Microsoft bug when reporting the size via JavaScript (looks like when inherit is the governing rule), even though it's rendering it correctly.
I tried to find a way to make this a grey area, but couldn't think of anything. For instance, according to the spec, having an input inside a span is entirely valid.
Before I get to the real answer I'd like to dig a little into details.
What is this piece of code doing?
.css();
In the jQuery Docs they tell us:
Get the value of a computed style property for the first element in
the set of matched elements or set one or more CSS properties for
every matched element.
Furthermore:
The .css() method is a convenient way to get a computed style property
from the first matched element, especially in light of the different
ways browsers access most of those properties (...)
So what does computed mean?
MDN Docs:
the computed value of a CSS property is computed from the specified
value by:
Handling the special values inherit and initial, and
Doing the computation needed to reach the value described in the "Computed value" line in the property's summary
Ok, now that part is clear too. Let's get to the real answer:
According to Specifics on CSS Specificity there are css-rules with more 'weight' than others have on an HTML element.
Here is the actual order:
Style Attribute
ID
Class, Pseudo Class Attributes
Element
According to that rules your input should've taken the inherited 30px from the Style attribute.
So what is happening in IE11/Edge?
IE11 and Edge are both computing the CSS Rules wrong. If you change your CSS into only this:
span input {
font-size: inherit;
}
It is starting to work. With the information gathered I am assuming that the JavaScript - Engine of both is computing the real CSS value instead of following the CSS rules order.
I've tried to either change the ID and putting a class on the input but still no luck.
I can remember that IE11 and Edge had some problems with inherited CSS and pseudo classes, maybe it is related to that?
Regards,
Megajin
I created the code below to detect if Chrome add padding: 28% if all other browsers add margin: 28%. It's not working as expected and Im curious where I went wrong?
var chromeFix = document.getElementById('#slide-container');
if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
chromeFix.style.padding += 28%;
} else {
chromeFix.style.margin += 28%;
}
As an alternate to this messy hack, I would suggest looking into a css reset. Each browser has it's own user agent’ stylesheet, a css reset is designed to clear these styles for cross browser consistency
From http://cssreset.com/what-is-a-css-reset/
What Is A CSS Reset?
A CSS Reset (or “Reset CSS”) is a short, often compressed (minified) set of CSS rules that resets the styling of all HTML elements to a consistent baseline.
Why Use A CSS Reset?
You might wonder what this is all for – well, it’s simple. From the consistent base that you’ve set up via your reset, you can then go on to re-style your document, safe in the knowledge that the browsers’ differences in their default rendering of HTML can’t touch you!
Normalize.css is a commonly used css reset
https://necolas.github.io/normalize.css/
Just make sure this is the first css reference in your page as it is designed to override, and it will!
Here's a jQuery solution I found....
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
$('#slide-container').css('padding-top', '28%');
} else {
$('#slide-container').css('margin-top', '28%');
}
Anyone know the proper syntax/way to write the above in pure JS?
For the next project my team is working on, we have an ASP.NET/HTML 4 project that we're (slowly) upgrading to MVC 4.0/HTML 5. It is a requirement that this setup work on IE 9, but we can't yet fully upgrade to HTML 5 for a number of reasons.
The problem I am trying to solve involves the simple task of toggling a callout, based on the jQuery :hidden selector. While it is possible to get the callout to appear, getting it to hide is causing me some trouble.
We have an MVC partial with the following markup:
<link rel='stylesheet' href='my-styles.css' />
<h4>Information</h4>
<div>
#Html.LabelFor(m => m.PersonName, "Person's Name")
#Html.InputFor(m => m.PersonName)
<a href='#' id='info-link'>[ ! ]</a>
</div>
<div id='info-callout' class='callout hidden'>
<div class='callout-before'></div><div class='callout-main'>
This is the name of the person this form refers to.
</div>
</div>
<script src='this-form.js'></script>
...and inside of this-form.js:
var MyTeamCallout = function($control, $callout) {
var pub = {};
pub.$control = $control;
pub.$callout = $callout;
pub.RegisterClickEvent = function () {
pub.$control.click(function () {
e.preventDefault();
e.stopPropagation();
// Repositioning of the control removed for purposes of this post.
if(pub.$callout.is(':hidden')) {
pub.$callout.show();
}
else {
pub.$callout.hide();
}
});
}
return pub;
};
// --- Functional Code... -----------------------------------
var $link = $('#info-link'),
$callout = $('#info-callout');
$(document).ready(function () {
var calloutObject = new MyTeamCallout($link, $callout);
calloutObject.RegisterClickEvent();
});
...Finally, with the given CSS:
.hidden {
display: none;
}
.callout {
position: absolute;
z-index: 2;
/* Left/Top assigned by JavaScript, normally */
}
.callout-before {
position: absolute;
top: 0.5em;
left: -1em;
/* SNIP: Borders are used to create a CSS triangle. */
}
.callout-main
{
position: absolute;
top: 0;
width: 10em;
}
When I run this in IE9, I can cause the callout to appear, but not to hide again. I am showing no JavaScript errors in F12 Developer Tools.
Questions:
A) Are there known compatibility issues with the :hidden selector in IE9 Quirks Mode?
B) If so, what would be a better vehicle to overcome these limitations?*
*: The problem in question is a little more complex than I've posted here, but our current solution uses the :hidden selector. I'm trying to preserve that if at all possible.
jQuery does not support Quirks mode. The lowest browser they support (or have ever supported) is IE6 in Standards mode.
So the fact that something has broken is not a surprise; in fact, if anything in jQuery works in Quirks mode, you should consider it lucky.
I strongly recommend trying to bring the site into standards mode as soon as possible by adding a doctype. This doesn't necessarily mean you have to go all HTML5, but you should consider at least making the minimal switch to standards mode to be a priority.
If you're worried about your layout breaking in standards mode, try adding
* {box-sizing:border-box;}
to the top of your CSS file; this will set the standards mode box model to emulate quirks mode, and will mitigate a large portion of the layout glitches that occur due to the switch.
Hope that helps.
I don't see any documentation about it, but I doubt that :hidden works in QuirksMode as a psuedo selector. You probably need to instead make a direct comparison against the visibility / display state / opacity of the element.
I have a script that detects what browser (and version) someone is using, and I'd like to set it up so that for certain browsers, a div class gets an animation on hover. I'd like to do this using jQuery, but I'm open to whatever.
My idea for the JavaScript is this...
if (browser == IE || browser < Firefox 4) {
// somehow animate a div class on hover (could be id-based too)
} else {
// do nothing
}
The CSS I have set up for this is something like this
.item {
height: 100px;
width: 100px;
/* css3 */
transition: height .5s, width .5s;
-moz-transition: height .5s, width .5s;
-webkit-transition: height .5s, width .5s;
}
.item:hover {
height: 200px;
width: 200px;
}
And then the HTML is (obviously)
<div class="item" id="item">
<p>Content here</p>
</div><!-- end item -->
The purpose is a CSS3 fix for older browsers. Transitions are, in my opinion, one of the best things about CSS3, and it annoys the hell out of me that IE9 doesn't include support for them.
Instead of this, how about using something like the Modernizr library?
http://www.modernizr.com/
Modernizr adds classes to the element which allow you to target specific browser functionality in your stylesheet. You don't actually need to write any Javascript to use it.
You can then do stuff like this:
.multiplebgs div p {
/* properties for browsers that
support multiple backgrounds */
}
.no-multiplebgs div p {
/* optional fallback properties
for browsers that don't */
}
You're going down a very dangerous path here using browser sniffing like that.
What you should be trying to do instead is use feature detection. There are libraries out there like the fantastic Modernizr which can do this for you.
Use $.support to check if the browser supports it and not even have to mess with version detecting. This helps future proof your code and more accurately models what you really want to do.
In fact, there's already a jQuery plugin to do this specifically. :D
Browser sniffing is not the best way to write JS-code.
If you prefer jQuery, here is jQuery.browser object
Some examples:
if ($.browser.webkit) {
alert( "this is webkit!" );
}
var ua = $.browser;
if ( ua.mozilla && ua.version.slice(0,3) == "1.9" ) {
alert( "Do stuff for firefox 3" );
}
if ( $.browser.msie ) {
$("#div ul li").css( "display","inline" );
} else {
$("#div ul li").css( "display","inline-table" );
}
You could do something like this:
<![if (IE 6)|(IE 7)|(IE 8)]-->
<link type="text/css" rel="stylesheet" href="nocss3.css" />
<script type="text/javascript" src="nocss3.js"></script>
<![endif]-->
You can use the library Modernizer (http://www.modernizr.com) which detects and fixes support of various HTML 5 and CSS3 features on different browsers.
Here's what they have in their documentation about CSS3 transitions:
http://www.modernizr.com/docs/#csstransitions
CSS Transitions are an incredibly
useful new part of CSS3. Using them,
you can let the browser animate—or
rather, transition—from one state to
the other. You only have to specify a
start and end and the browser takes
care of the rest.
In Modernizr we test for CSS
Transitions using the transition
property with all vendor prefixes.
Transitions can typically be used
without using Modernizr's specific CSS
class or JavaScript property, but for
those occasions you want parts of your
site to look and/or behave differently
they are available. A good example use
case is to build Modernizr into an
animation engine, which uses native
CSS Transitions in the browsers that
have it, and relies on JavaScript for
the animation in browsers that don't.
Sample Usage:
a {
color: #090;
-webkit-transition: color .2s ease-out;
}
a:focus,
a:hover {
color: #9f9;
}
You might look in to this tutorial https://developer.mozilla.org/en/Browser_Detection_and_Cross_Browser_Support
How to detect, using JavaScript, if the browser supports the CSS :first-child selector?
You could just use that :first-child rule to set some specific value, and then get the computed style in Javascript to see if the :first-child rule is applied, e.g.
<style>
#foo { width: 200px; }
#foo:first-child { width: 400px; }
</style>
<span><span id="foo"></span></span>
<script>
if ($('#foo').width() < 400)
alert('first-child not supported.');
</script>
(This is not tested. I have no IE 6.)
I don't think there is a jQuery function to find out support for this. I expect if it does exist, it is going to be quite complicated. Are you really sure you need this? Care to share why?
If you can use jQuery anyway, why not add a jQuery statement to assign the class/property/whatever to the desired element, instead of relying on CSS?
As a "manual" answer, looking at the quirksmode.org compatibility table, the selector is fully supported in all modern browsers except the IE family which seems to have problems even in IE8.