I want my main logo to change when mousing over.
I understand there are several ways to achieve this, and was wondering what's the best way for stability, browser compatibility, efficiency - and ease to setup.
Some ways I've found are:
Javascript (jQuery) replacement of the "src" attribute.
CSS using backgrounds and "hover"
Any more?
What's best?
Bottom line
For content-ful images, you want to have the src in the HTML markup. You want to use the Javascript solution and put the rollover image in an attribute.
For content-less images UI elements, especially ones that are common across the site or duplicated, a straight CSS solution would be the best (so you don't have to re-declare the image locations at each invocation). Among the CSS solutions, sprites are the best since they don't require preloading overhead.
The Javascript solution
HTML:
<img src="/img/one.jpg" data-rollover="/img/two.jpg" />
In jQuery:
$(function(){
$('img.rollover').hover(function(){
var e = $(this);
e.data('originalSrc', e.attr('src'));
e.attr('src', e.attr('data-rollover'));
}, function(){
var e = $(this);
e.attr('src', e.data('originalSrc'));
}); /* a preloader could easily go here too */
});
Sample implementation: http://jsfiddle.net/dtPRM/1/
Benefits: It's easy; it makes sense; it works with minimal additional markup once you have your library set up.
Downsides: Requires Javascript and overhead of loading the jQuery library.
Probably the best option. If your user is using a browser where rollovers are relevant (probably the case), they have the Javascript capabilities to run this option. The folks who have intentionally turned Javascript off for some reason will clue in if you leave a little <noscript> note saying that they may not get the full featureset.
The CSS solution: Best
HTML:
<div id="img1" />
CSS:
div#img1 {
height: 400px;
width: 300px;
background: url('http://dummyimage.com/600x400/000/fff') no-repeat top left;}
div#img1:hover {
background-position: top right;}
Sample implementation: http://jsfiddle.net/dtPRM/5/
Personally, I think that for content-ful images, this is an even worse option than the CSS + two background images solution. You're separating the HTML markup from the semantic value of the display.
If you're using content-less images like UI elements, though, this is the best solution in my opinion.
The CSS solution: Also okay
Another CSS option is available that doesn't involve background images (preferred among the CSS solutions if you want to have the image tags in the HTML, like for semantically meaningful images).
<div class="rollover">
<img class="rollover" src="http://dummyimage.com/600x400/000/fff" />
<img class="" src="http://dummyimage.com/600x400/fff/000" />
</div>
CSS (I use the :not pseudo-selector here, but it's pretty easy to avoid using it; I also think I got the classnames semantically backwards):
div.rollover img:not(.rollover) {display: none;}
div.rollover:hover img:not(.rollover) {display: inline;}
div.rollover:hover img.rollover {display: none;}
Sample implementation: http://jsfiddle.net/dtPRM/2/
Benefits: Semantically sensible compared to the previous CSS solution of putting all the information the stylesheet.
Downsides: Extraneous markup needed.
Comment: This one may automatically pre-load depending on whether the browser calls for it.
Bottom line: A decent fallback if option (1) is unavailable because you absolutely need IE2 compatibility or non-JS support.
The CSS unsolution: Stay away
I mention this only because you mentioned it in the question. I wouldn't use it.
HTML:
<div id="img1" />
CSS:
div#img1 {
height: 400px;
width: 600px;
background: url('http://dummyimage.com/600x400/000/fff') no-repeat top left;}
div#img1:hover {
background-image: url('http://dummyimage.com/600x400/fff/000');}
Sample implementation: http://jsfiddle.net/dtPRM/4/
Benefits: Widely compatible; all you really need to support is background images and hover.
Downsides: Semantically weird to put images in CSS and to centralize it there. Makes future modifications more difficult. That being said, if you have a scenario that warrants a rollover image, there's a good chance it may be a non-content image (e.g., a UI element), in which case CSS would be semantically (perhaps) even more suitable than a regular image. See the note on sprites below.
Other downsides: You'd have to be careful to declare image height and width (a good practice anyway, but it may get cumbersome when you just want to get things done). Users viewing on mobile browsers that may treat CSS background images unusually.
Even more downsides: If you want to layer a preloader on top of it, you're going to be using Javascript and somehow selecting the rollover-able elements, and at that rate, you may as well use Javascript for everything.
Bottom line: Don't use this for content-ful images. If you must stay away from Javascript, use sprites for UI elements and the alternate solution for semantically meaningful images.
#btn{
width:100px; height:100px;/*the dimensions of your image*/
background:url(bird.png) left top no-repeat;
}
#btn:hover{
background-position:left bottom;/* pixel references can be used if prefered */
}
Using an image like this:
Note: Avoid JS image replacements as you will incur a short image load time if images are not cached before.
Hope this helps bro!
W.
CSS using backgrounds and "hover"
Use CSS sprites, in other words combine both images into one and then use css :hover to shift the image.
One advantage of using CSS is that it'll work even if JavaScript is turned off.
One advantage of using a single image is it'll avoid the extra HTTP request.
See: http://css-tricks.com/css-sprites/
Tools to help generate image and CSS:
http://csssprites.com/
http://css-sprit.es/
You should use a :hover CSS rule.
CSS by far. Though you may want to precache your image with javascript.
Image rollovers using 'sprites' List a part - sprites CSS
Use CSS sprites and the :hover psuedo-class in CSS. Here's why:
Switching image source either through JS or through the CSS will cause a "blink" on the first mouse-over while the new image is downloaded by the browser. If you use the sprite, it's just one image that changes position, so no blink.
A single image reduces HTTP requests, making the site load faster in general.
It works if the user has JavaScript disabled.
It's supported by all browser types (desktop, anyways, phone browsers without a :hover state don't count for this anyways).
More information: http://css-tricks.com/css-sprites/
$('#div1').hover(function(){
this.style.color='white';
},function(){
this.style.color='black;
});
or
$('#div1').onmouseover()...
$('#div1').onmouseout()...
Related
I've been working with some basic animations lately and trying to follow good web practices at the same time. The problem I'm encountering is image flicker when not using a preset css method to hide the element before the page loads.
It's very easy to prevent the flicker by just hiding the element with my normal css and then revealing it with javascript, but that seems to me a horrible practice if someone has javascript disabled.
Should I use the HTML5 feature of putting <noscript> tags in the header and then use a separate style sheet to set the opacity and position to the final settings for users without javascript? Is that the most elegant solution?
I've started using the greensock (gsap) library to TweenLite.from, since I can just set everything to the final state in the css, but I get a slight image/text flicker the first time the page is loaded. I like this solution because I can set all of the css as it will be for someone with no javascript, and it allows me to easily animate from a point, to an existing point, instead of working backwards like I have to do with Javascript or jQuery. But, there's still that image flicker which isn't really acceptable. Would a page preloader solve this?
What is the generally agreed upon practice for this these days? I'm also worried about SEO and the consequences of setting stuff to visibility: hidden or display:none and then animating it in. Does the Google spider read javascript?
Here's an example of the screen flicker and animations I'm talking about.
Have a look at HTML5 Boilerplate and Modernizr.
http://html5boilerplate.com/
http://modernizr.com/
It ships with a smart solution to see if a client has JavaScript enabled in CSS.
By default a class no-js is applied to HTML tag and it is then replaced by js by Modernizr. That way you can qualify your CSS selectors accordingly.
Example CSS:
.no-js .foo { }
.js .foo { }
This should execute fast enough that clients with enabled JavaScript don't see the no-js styles.
References:
What is the purpose of the HTML "no-js" class?
https://github.com/Modernizr/Modernizr/blob/master/src/setClasses.js#L9
We're currently building a website for mobile devices. Supported operating systems and browsers should be:
Android 4.x (Stock Browser, Google Chrome)
iOS6+ (Safari, Google Chrome)
In order to also support high resolution displays we evaluated various techniques and libraries to automatically replace images with their high-res pendants:
Attempt 1: retina.js
http://retinajs.com/
The first attempt was to use a normal <img> Tag like this: <img src="foo.png"> and use retina.js to let it automatically replace the src Attribute with the name of the retina image (foo#2x.png). This works but has 2 downsides: First, it will create unwanted overhead because both, the original as well as the retina image, would be loaded and second, if there is no retina image available it will cause lots of 404 errors on server log which we do not want.
Attempt 2: picturefill.js
https://github.com/scottjehl/picturefill
This framework uses some weird html markup based on <span> elements. For me it looks like as if the author tried to mimic the proposed <picture> element which is not a standard (yet), see http://picture.responsiveimages.org - I don't like this approach because of the weird markup. For me it doesn't make sense to semantically describe images with spans.
Attempt 3: Replace images via CSS property background-image
I see sometimes people using CSS media queries to detect retina displays and then set a background-image on a div (or similar element) with a higher or lower solution picture. I personally don't like this approach either because it completely discourages creating semantically good markup à la <img src="foo.png">. I can't imagine building a website just with div's and then set all images as background images - This just feels very weird.
Attempt 4: Set images via CSS property content:url(...)
As proposed here Is it possible to set the equivalent of a src attribute of an img tag in CSS? it seems to be possible to overwrite the src Attribute in img Tags via CSS using the property content:url(). Now, here is the plan: We set img tags for each image with a transparent blank 1x1 png referenced in its src attribute, like this: <img id="img56456" src="transp_1x1.png" alt="img description">. Now this is semantically ok and also valid against the W3C validator. Then we load a CSS Stylesheet that sets all the images on the website via Media Queries.
Example:
#img56456{content:url(foo.png)}
#media (-webkit-min-device-pixel-ratio: 2){
#img56456{content:url(foo#2x.png)}
}
Now, this approach works pretty good:
No overhead
Solid markup
Works on the required devices/browsers
SEO for Images is not requirement here
Now, could this approach cause any side effects we didn't think of? I am just asking because I know it works but kinda "feels" weird to set all images via CSS and I also found this comment on this approach on SO Is it possible to set the equivalent of a src attribute of an img tag in CSS?:
"Worth to add that even in browsers that support assigning content to
img, it changes its behavior. The image starts to ignore size
attributes, and in Chrome/Safari it loses the context menu options
like 'Save image'. This is because assigning a content effectively
converts img from empty replaced element to something like
<span><img></span>"
Could this be a problem? (I didn't notice any sizing problems and the context menu is not a requirement)
There are lots of advantages and disadvantages, but one disadvantage is that the image won't be cached. This is more of a problem on mobile devices where internet is generally slower and more expensive for the user (if on a data connection not wifi).
I don't know about those libraries but you could use media-queries, depending on how many images you have, otherwise it would be lots of code variations to write. And have a threshold screen size at which point you use a different file. Only one file is actually loaded, even though you specify both in the media-queries.
The new version of picturefill http://scottjehl.github.io/picturefill/ doesn't rely on <span> any more. Instead it simply uses the official HTML5 srcset attribute and mimics its behavior if the browser doesn't support it, so for me this is the ideal solution after quite a while now.
Using the CSS property content:url(...) was a neat little idea but it made things a little complicated and hackish too.
So, to answer my own question: No, it's a bad idea. Using the new version of picturefill is a way better solution. You can even remove it after a while when newer versions of all major browsers support the srcset attribute and you'll still be standard compliant. http://caniuse.com/#search=srcset
Example:
<img srcset="examples/images/small.jpg, examples/images/medium.jpg 2x" alt="A giant stone face at The Bayon temple in Angkor Thom, Cambodia">
<script src="picturefill.js"></script>
I always use a CSS pre-processor for web-related projects. A CSS pre-processor pretty much lets you do everything that CSS lets you do, but enables DRY coding principles and cleaner syntax. I'm wondering though - why not drop the style sheets completely? Why not make a styling-language that compiles to JavaScript instead? JavaScript apparently has full control over CSS styles anyway so it should be possible. Such a language would also be much more powerful than vanilla CSS since it would enable logic, such as selectors based on element sizes and positions, browser window size etc. A contrived example of possibilities:
div#test {
if windowWidth > 800px {
width: (windowWidth / 3 + 10)px;
height: 200px;
}
else {
width: 100px;
height: 50px;
}
}
Or a div that is positioned absolutely, but should follow the window when it scrolls too far down:
div#side_panel {
position: absolute;
top: 100px;
right: 25px;
if windowScrollY > 90px {
position: fixed;
top: 10px;
}
}
I have Googled this topic to the best of my ability without any success. Are there any styling languages that allows for dynamic styles such as those in my example, and compiles down to JavaScript? If not, why not? Is this not viable performance-wise? Or are there perhaps browser support issues?
I know some browsers, including Chrome, exposes an object called document.styleSheets that gives JavaScript full control over the document's styles, which would be perfect for this kind of project.
A few years ago I thought about it too.
In my conclusions, the first point is that CSS is meant for web designers and not for web developers. Designers are very creative on making the same artistic work again and again and again, but are also very dumb in programming logic and understand programming languages. Those simle if-else's would be enough to drive them crazy.
The other, is performance. CSS is meant to style a whole page layout. Even with AJAX, JavaScript is meant to do little changes and handle small user interactions. Simplicity is also at hand, imagine if we'd use only JavaScript to build a whole layout out of a HTML document.
There's also the stability concern. CSS parsing and processing is handled by browser's engine, which is very well tested, much more than our own JS codes. If we use Unobstructive JavaScript, our WebSite will be fully working when CSS is applied and images are loaded, therefore if JS bugs it will still work. Imagine if JavaScript code that lays out a page crashes. And for that, all we need is an infinite loop, which for sure would be available.
Lastly, we must separate content-HTML, look-CSS and feel/behavior-JavaScript. Therefore, just serve all content in the HTML document, even if it's gonna stay hidden. Style everything in a working manner with CSS and provide the best static page possible. Then use JS just to do changes on the layout and use if-else's when needed to change it.
Are there any differences in performance or load/caching behavior when displaying images in img tags vs divs with image backgrounds?
My example:
I have a site with many overlapping images, some of which I will need to load dynamically with javascript. One issue is that I need to anchor the images to the right of the element, so that I can do a nice wipe-to-right effect. Because of this I was using a div with background image positioned right. Couldn't figure out how to do this with img but since divs are working for me I didn't know if this would matter...
AFAIK, browsers cache images the same whether they're in a DIV or an IMG. In any case, I think this one of those cases where specific performance is defined as an implementation detail internal to each rendering engine (and possibly the browsers built around them). As such, it's both out of our control as designers/developers and subject to change from browser to browser and version to version. In other words, I wouldn't spend too much time worrying about it.
The main performance difference is using background images allows you to use CSS sprites. Having one image contain a large number of images from your page means the user only has to make one request instead of one for each image.
Another difference is with responsive layouts. If you have an element that is only shown at certain screen widths (ie, not on mobile phones), it will still load the image if it is specified in the html (using display:none for instance), but most all browsers now will NOT load the image if is a background-image specified in unused media query-CSS rules. A lot of early responsive layouts got criticized because they still used the same bandwidth as the full size sites.
It is also useful with such designs because you can easily specify different images for different screen sizes. "Retina" displays on tablets and even laptops now won't look their best without 2x res graphics. So... even if you don't do such things now, it is probably a good practice to get into, because you might find yourself needing it soon!
I think by using background-image attribute in the div, the page layout gets loaded first and image present in the divs loaded later after the dom is loaded. so by using background-image the html layout is loaded faster on the web browser.
The only difference I can conceive of it this:
You can't scale images as backgrounds, although you can for img tags. This would open a scenario where background images loaded faster becuase it forces you to have the correct native size as opposed to downloading the entire image and scaling it. However, the converse could be true: given that you didn't care about image quality so much, you could deliver smaller imgs to your page and scale them up.
I'd stick with whatever rendered cleaner (and more consistently -- IE/FF/Chrome/Safari/etc).
Technical differences yes, most notably you can set the width/height of an IMG tag and it will stretch the image, which can be useful in some situations.
The main thing you've got to keep in mind though is the context of the image within the HTML document. If the image is content, say an image in a gallery, I'd use a IMG tag. If it is just part of the interface I might use a div instead.
When setting up a rollover effect in HTML, are there any benefits (or pitfalls) to doing it in CSS vs. JavaScript? Are there any performance or code maintainability issues I should be aware of with either approach?
CSS is fine for rollovers. They're implemented basically using the :hover pseudo-selector. Here's a really simple implementation:
a{
background-image: url(non-hovered-state.png);
}
a:hover{
background-image: url(hovered-state.png);
}
There are a few things you need to be aware of though:
IE6 only supports :hover on <a> tags
Images specified in CSS but not used on the page won't be loaded immediately (meaning the rollover state can take a second to appear first time)
The <a>-tags-only restriction is usually no problem, as you tend to want rollovers clickable. The latter however is a bit more of an issue. There is a technique called CSS Sprites that can prevent this problem, you can find an example of the technique in use to make no-preload rollovers.
It's pretty simple, the core principle is that you create an image larger than the element, set the image as a background image, and position it using background-position so only the bit you want is visible. This means that to show the hovered state, you just need to reposition the background - no extra files need to be loaded at all. Here's a quick-and-dirty example (this example assumes you have an element 20px high, and a background image containing both the hovered and non-hovered states - one on top of the other (so the image is 40px high)):
a{
background-image: url(rollover-sprites.png);
background-position: 0 0; /* Added for clarity */
height: 20px;
}
a:hover{
background-position: 0 -20px; /* move the image up 20px to show the hovered state below */
}
Note that using this 'sprites' technique means that you will be unable to use alpha-transparent PNGs with IE6 (as the only way IE6 has to render alpha-transparent PNGs properly uses a special image filter which don't support background-position)
It will still work in CSS if the browser happens to have Javascript disabled.
Because it's an aspect of presentation, I'd say it's more standards based to do it with CSS. It used to be done in Javascript, simply because we couldn't do it with CSS (old browsers suck, and I don't think :hover was even added until CSS 2).
Implementing a rollover with CSS uses the :hover pseudo-class to define the style of the target element when it is hovered over. This works great in many browsers but not in IE6 where it only works well with the anchor tag (i.e. a:hover). I used CSS hover to implement a tabbed navigation bar but had to use IE behaviors to get it working in IE6.
Yep, the best way to do this is css sprites. An annoying problem occurs in IE6, when browser make a request every time an element is hovered. To fix this, take a look here.
I'd stay on the CSS side of the house, but I've done very little Javascript.
CSS seems to be easier to standardize across browsers than Javascript, though that may be changing with the advent of Chrome's V8 and Firefox's upcoming new rendering tool.
Isn't there a mnemonic for remembering the sequence of declarations in CSS?