If Browser, Use Javascript? - javascript

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

Related

Vendor prefixing with inline styles

I'm in a situation where I need to dynamically animate the position of an element with jQuery. I have some external css that takes care of all things css, then my script adds a transform inline style.
html:
<div></div>
css:
div {
width: 100px;
height: 100px;
background: pink;
transition: all 1s ease;
}
js:
$(function() {
setTimeout(function() {
$('div').css({
'-webkit-transform' : 'translateY(100%)',
'-ms-transform' : 'translateY(100%)',
'transform' : 'translateY(100%)',
});
}, 1000);
});
My question is why are all browsers I am testing (Safari 11.0.2, Firefox 56.0, Chrome 63.0.3239.84) ignoring the vendor-prefixing and returning the following?
<div style="transform: translateY(100%);"></div>
I'm obviously looking to support as many browsers as possible...
Fiddle here if seeing what the code does helps.
No browser has required a prefix for transform for many years. Once unprefixed transform has shipped, a browser simply implements its prefixed property as an alias of the unprefixed property, which means that the prefixed and unprefixed declarations will override one another in the cascade depending on the order of declarations. Furthermore, since they are aliases, they'll still show up as unprefixed even if you remove the explicit unprefixed declaration.
This is just browsers' way of telling you not to worry about the prefixes in the newer versions that don't need them. They are intended for older versions that don't yet support the unprefixed properties. For example, the only version of Internet Explorer that requires -ms-transform is 9. Internet Explorer 10, which doesn't need the prefix (for transforms and many other features), came out in 2012. Note also that some browsers, like Firefox, are known to drop support for really old prefixed properties altogether after keeping them aliased for a while — again, not something you have to worry about since you always make sure to include unprefixed declarations (which not everyone does).

How to prevent div:hover transitions from being disabled by javascript div style attributes alterations

Here's the jsfiddle that I've been trying to debug:
http://jsfiddle.net/Neoheurist/x57fkzng/
HTML
<div id="birthday">Surprise Party</div>
<p></p>
<button onclick="blue()">Blue</button>
<button onclick="red()">Red</button>
<script>
function blue()
{
element=document.getElementById("birthday");
element.innerHTML="Happy";
element.style.background="blue";
element.style.width="150px";
element.style.opacity="1.0";
element.style.transition="width 2s,background 15s,opacity 2s";
}
function red()
{
element=document.getElementById("birthday");
element.innerHTML="Birthday";
element.style.background="red";
element.style.width="300px";
element.style.opacity="0.0";
element.style.transition="width 2s,background 4s,opacity 6s";
}
</script>
CSS
div
{
width:100px;
height:50px;
background:blue;
transition:width 2s,opacity 2s,background 15s;
}
div:hover
{
width:200px;
background:green;
opacity:0.25;
transition-timing-function:linear;
transition:width 2s,background 4s,opacity 6s;
}
Questions:
Why does clicking a button disable div:hover?
How can I prevent this from happening?
It's because HTML style attributes override element selectors in a css file. Any property set directly in an HTML style attribute will automatically be used over any property set in any css selector declaration.
Style attributes are much more specific than tag selectors (that's why they aren't recommended for use in fact).
According to the inspector in webkit this also includes the :hover state, so any inline style will stop a hover state from working.
You could use important, tempting as it might be, but that's not a good idea, because it takes the current problem with specificity that you're having and amplifies it even further, leading to a specificity nightmare. The only way to over-ride !important is with more !important, further down the document, or by using more specific selectors (like IDs) or longer chains of selectors and !important and so on, you can see how this can be horrible to maintain. Also any js that adds style to the HTML directly won't work either.
The best solution is to use javascript to add and remove css classes to trigger your changes. This will solve your problem as all your classes will have manageable specificity.
#birthday.blue {
background: blue;
width: 150px;
opacity: 1.0;
transition: width 2s,background 15s,opacity 2s;
}
#birthday.red {
background: red;
width: 300px;
opacity: 0.0;
transition: width 2s,background 4s,opacity 6s;
}
Then make sure the hover state is defined for all the combinations, so any class will :hover. This is not possible with inline styles.
#birthday:hover,
#birthday.blue:hover,
#birthday.red:hover
{
width: 200px;
background: green;
opacity: 0.2;
transition-timing-function: linear;
transition: width 2s,background 4s,opacity 6s;
}
I've put together a jsfiddle that demos this. I've used JQuery, for the sake of getting a demo together quickly and their addClass() method is great. Good effort to use pure js, it's a good habit to get into; this question will elaborate on how to add and remove classes in javascript
Plus; as an added bonus, you'll also have all your style in your style file and all your functionality in your javascript, which is better separation of concerns and makes the site styling DRYer and easier to re-use elsewhere in the project (you don't have styles stuck is js that you can't easily add elsewhere, which you copy instead, then try to change in one place and not the other ... we all do it, or our colleagues do!).
[Seen as I've brought up the subject of specificity you might also be interested to know that IDs are also pretty bad for that and unnecessary in style files]
You could make the div:hover attributes all !important like so:
div:hover{
width:200px !important;
}
However I've heard you'd want to avoid !important if possible, but this does what you want...
You can also use
document.addEventListener('DOMContentLoaded', function () {
var storedStyles;
var elem = document.getElementById("birthday");
elem.addEventListener('mouseenter', function () {
if (elem.hasAttribute('style')) {
storedStyles = elem.attributes.style.value;
elem.removeAttribute('style');
}
});
elem.addEventListener('mouseleave', function () {
if (storedStyles) {
elem.setAttribute('style', storedStyles);
} else {
storedStyles = null;
}
});
});
and clear all styles on mouse enter restoring hover styles precendence and setting back your inline styles on mouse leave

CSS transition on click

I'm working on creating a mini-sort plugin with jquery.
I want to have the option to trigger css animations on click event, but I found out animation don't get triggered on elements that have been hidden using display: none;.
I tried with creating a class and applying that class to the element but this won't work.
$('.legend li').on('click',function(){
var thisClass = $(this).attr('class');
$('div').not('.'+thisClass).removeClass('active');
$('div.'+thisClass).addClass('active');
});
I found a plugin which has the same functionality that I wan't but I would like to try to build something smaller and I always like to attempt myself as a learning experience before resorting to plugins. I'm a bit confused as to how they run the animations. It looks like inline css but when I tried to add inline transitions there was no effect. Even though I could see the transitions in the style tag.
Edit
Here is a fiddle.
http://jsfiddle.net/NktDU/1/
You could use jQuery's hide and show instead
Updated demo
$('#grid div').not('.'+thisClass).hide("fast").removeClass('active');
$('#grid div.'+thisClass).show("fast").addClass('active');
and remove display:none from the CSS
Or you could do it just using CSS transitions and toggling the width, like so
#grid div {
display: block;
height: 20px;
width: 0px;
margin:0px;
float: left;
-webkit-transition: all 1s ease;
-moz-transition: all 1s ease;
transition: all 1s ease;
background: black;
}
#grid .active {
width:20px;
margin: 2px;
}
Demo for that
I think the library you would have to write for something like this is immense. In this case, I highly recommend you work on implementing Isotope by David DeSandro.
Is this the plugin you were talking about? I can assure you that while you want to come up with your own solution, you can make isotope your own. I've implemented it a couple of times. You will learn a lot, while at the same time, learning how jQuery/JS/CSS (and media queries) work together.
I've implemented the click to sort, and I also created my own sort by keyword search. I can put together a couple of fiddles if you want...
Edit:
I just saw the link to the plugin you found... it actually uses isotope's framework and recommends you use isotope in certain situations.
Good luck!

How can this CSS card flip effect fall back gracefully when CSS3 support is lacking?

I'm using the library FlipClock.js to build an analog-style clock that uses a version of the CSS "card flip effect." Unfortunately, only after building out my project did I notice a long-standing bug affecting Internet Explorer 9 and below:
https://github.com/objectivehtml/FlipClock/issues/7
In IE9 and below, the clock time lags by one second (i.e., in the first second of animation, nothing visible changes), and the digits in the clock are also offset by a value of 1. My expectation is not for the CSS flip animation to work, but for the digits to change instantly as they currently do, only be correct.
I've been troubleshooting for a while but have yet to find a solution or even pinpoint the problem. I have a hunch that this isn't a script-related bug; I suspect that the digits are changing correctly in the HTML (hard to verify with IE's developer tools), but that they're just not showing as intended due to one or more CSS rules that were written not considering IE9's poor CSS3 support. I'm kind of expecting (or at least hoping) to stumble upon a CSS property or two that just fixes it.
The library is based on a proof-of-concept, which exhibits the same problem:
http://codepen.io/ademilter/pen/czIGo
I'm troubleshooting there to keep it simple, and if I find a fix, will submit a pull request to the FlipClock.js library.
I would greatly appreciate any help!
After removing the CSS animations and shadows, changing the z-index of li.before might do the trick (see http://codepen.io/cbuckley/pen/rysja):
body.play ul li.before {
z-index: 1; /* was previously 3 */
}
So you could use z-index: 1 by default, then feature-detect for CSS animations in the JavaScript and add a body class (say body.supports-animation). Then the relevant CSS might look like:
body.play ul li.before {
z-index: 1;
}
body.play.supports-animation ul li.before {
z-index: 3;
}
/* Prefix animation/background declarations with body.supports-animation too */
Caveat: I haven't tried this with FlipClock, nor have I actually tested on a browser without animation support, but I hope it gives one possible option :-)
Just changing the z-index will fix the problem for IE8 and IE9 but will break the transition for all modern browsers.
To Target specifically I8 or IE9 you can use this:
On your JS file add:
var doc = document.documentElement;
doc.setAttribute('data-useragent', navigator.userAgent);
then on your css you can detect IE8 and IE9 with this code (flipclock.css line 160):
/* PLAY */
.flip-clock-wrapper ul.play li.flip-clock-before {
z-index: 3;/*Original */
}
/*ie8 and ie9 fixes*/
html[data-useragent*='MSIE 8.0'] .flip-clock-wrapper ul.play li.flip-clock-before {
z-index: 1;
}
html[data-useragent*='MSIE 9.0'] .flip-clock-wrapper ul.play li.flip-clock-before {
z-index: 1;
}
That fixed the problem for me!

Detecting CSS capabilities with Javascript

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
}

Categories

Resources