What is the preferred way to do a CSS rollover? - javascript

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?

Related

Styling visited links via bookmarklet?

For a while a bookmarklet I made extensive use of has been broken for me in Firefox. It may apply to other browsers, but I only use it in Firefox.
The bookmarklet in question is "hide visited" from squarefree.
Since this wasn't working (properly) I decided to have at it myself and ended up with this:
javascript:(
function(){
var css=document.createElement('style');
css.type='text/css';
var styles='a%3Avisited{display%3Anone !important}';
css.appendChild(document.createTextNode(styles));
document.getElementsByTagName("head")[0].appendChild(css);
})();
Broken up into several lines for readability, otherwise unmodified from what I'm using.
The thing is, it does append the inline stylesheet to the head, it just never alters the look of the links. Once I remove the :visited (or %3Avisited as it appears here), however, the stylesheet IS applied to links and they are hidden, though obviously the hiding is done regardless of their visited-state at this point.
Bottom line here is that I believe there is a problem with :visited, and flipping the bool for layout.css.visited_links_enabled in about:config, predictably, does nothing as this simply removes styling from visited links wholesale. This is undesirable. :)
It is probably worth noting that the squarefree bookmarklet still appends its stuff to the head, it simply has no effect either.
I am at a loss. What have I missed, and is it at all possible to hide visited links via a bookmarklet anymore?
The behavior of :visited was changed a couple of years ago due to security reasons ... while your code (and the squarefree bookmarklet) might work on older browsers, you won't be able to get the same impact in latest versions of the browsers
A note from https://blog.mozilla.org/security/2010/03/31/plugging-the-css-history-leak/
Visited links can only be different in color: foreground, background, outline, border, SVG stroke and fill colors. All other style changes either leak the visitedness of the link by loading a resource or changing position or size of the styled content in the document, which can be detected and used to identify visited links.
Other useful references:
http://www.azarask.in/blog/post/socialhistoryjs/ - what was the security problem (and its creative use)
http://dbaron.org/mozilla/visited-privacy - approach for the fix
For CSS, you can try for something like:
a:visited {
color: white !important; /* It would hide the text if the background is white too */
/* or some better css approach for your requirement */
}
I know that you cannot find out which links have been visited with javascript anymore. This was done to protect user privacy. For security purposes, I believe that even attempting to style, or create styles for, visited links will not work in any current major browser.
For security reasons browsers have taken steps to prevent the "visited" status of links from being read by JavaScript. This means that any style you apply to ":visited" via CSS will not be registered in the DOM.
You can change things like color and text-decoration (probably), and the user will see the change on screen, but the result will not be readable to JS.
Why won't it apply "display:none"? Because if the browser were to remove the link from the page, this could alter the layout of the page, such as the height of a div, and provide a potential side channel for determining which links have been visited or not. For that reason "display:none" will not be applied.
The best solution I can suggest for your goal is to change the link color to match the background color, or perhaps modify the opacity.

Unable to set marginTop style with script using IE8, but works in grown-up people browsers

I'm attempting to animate the slide-out of a menu with script. To do this, I need to animate the marginTop property of an element and increment it from -30px to 0px.
However, in IE8, the animation simply does nothing. I've traced this down to the fact that setting marginTop in script seems to have no effect. In Chrome and Firefox, this works fine.
Here's an example that will work with Chrome/Firefox, but not IE:
http://jsfiddle.net/rm58T/2/
Is this an IE bug, and if so, are there any workarounds for this behavior? Thanks!
Update:
Here's some screen shots of the bug.
In Chrome, my Fiddle looks like this (You can see the "Name of new menu" text, since we changed the margin with script)
In IE8/Vista, it looks like this. I can confirm in Developer Tools that topMargin is actually 0px as expected, however the elements were not re-drawn:
Another Update:
This bug repros (at least for me) on IE8 running on Windows 7, and also IE8 running on Windows 2008 Server. It does NOT repro for me on IE7 running on WinXP. I do not have any IE9 machines to test it.
Yet Another Update:
I found one potential work-around. If I set p.newmenu to position: absolute; instead of position: relative; then it works. However, in my case I'm hosting this entire thing in a popup menu and need this control to push out the bottom of the modal dialog, so absolutely positioning it is not an option. However, perhaps this knowledge can help in finding a workable solution. An example of this work around can be found here.
Would You Believe Another Update?:
I did find a workaround for now. If I use top: -30px; instead of a negative top margin, then everything works. top behaves a bit differently than a margin, though, and makes the UI not look quite as nice. In particular, when you use top: -30px, then you'll have 30px of whitespace under your element since relative positioning doesn't affect other page flow.
I'd greatly like to figure out why I can't use a negative top margin on IE like I can with other browsers, so I'm still hoping someone can provide an answer that will provide all the benefits of a negative top margin but also work with IE8.
The trigger for this behaviour is how IE8 handles the fieldset element.
You can work around it by setting the display for fieldset to inline (or inline-block).
div.modal.addmenu fieldset {
display: inline;
}
This isn't exactly a bug; it is just based on the fact that (to keep up in performance comparisons) IE was built since version 5.5 with a minimized preset of static definitions;
That means: Instead of spending any Element the whole and correct definition (depending on which god of specifications you hail out for ...) for the type it is, IE is using less.
TODO:
Give back what should be credited for acting as a top-model paragraph relatively positioned; DISPLAY it accordingly to its talents; any super-paragraph should do the catwalk inline, even if it is a block-head, you might try using sugar and whiplashes to remember your nasty P of its origin as a inline-block. It's a frenzy P, give some respect to its talents…
DOJO:
In fact, you as a rune-reading script-javalchemist be the one who has to have to take control over the brew the browser serves. Or it makes boom, silently ...
GODO:
Necessary things to do if you want to use negative-margins in browsers which don't play legally:
remember the elements you want to use of their display's origin; don't believe in browser-vendors that they would have done that already for you
IF you are just out for IE 7+ use display:inline-block;
IF you want to get negative-margins to effect on all notable browsers, but can forget about NS4, then use display:inline; or display:block;
Do not forget to build the foundation for your negative-margins: set position:relative;
MOJO:
If IE-Betas and older ones like 5.5 or 6 are in your point of interest, you have to ensure that your relative-positioned negative-margin paragraph has values for width and height; Depending on what you are trying to achieve, sometimes a height:auto; helps out.

how does the css "onmouseover" event work?

update-
sorry folks, i should have provided the link to the website where i saw the effect. here you go - http://www.w3schools.com/Css/css_image_transparency.asp
and the code that i saw there (and the basis of this question) is as below -
<img src="klematis.jpg" style="opacity:0.4;filter:alpha(opacity=40)"
onmouseover="this.style.opacity=1;this.filters.alpha.opacity=100"
onmouseout="this.style.opacity=0.4;this.filters.alpha.opacity=40" />
The original question is as below -
I was looking for rollover effects that can be done without using JS, and i stumbled upon the w3schools website teaching the opacity setting for images. In the code, there is no js involved, its just pure css.
i even tried using the same code into my webpage (which does not have any js, yet) and i noticed that the code happened to work perfectly in both chrome and IE 7.0. the code has a "onmouseover" event and another "onmouseout" event to give the hover effects based on the opacity settings.
wondering whether these effects (onmouseover and onmouseout) are -
1. pure css
2. standards compliant (xhtml 1+ and css2)
3. whether there are any hacks involved
i still cant believe these things worked on ie7, and wondering why there are no documentation on these events.
There's no such "onmouseover" event or attribute in CSS, that's JavaScript. CSS uses the ":hover" pseudo-class for mouse over events. A quick example,
HTML:
<div id="someid">I'm a random div.</div>
CSS:
#someid {
background: #fff;
}
#someid:hover {
background: #000;
}
In this example, when you hover over the #someid element, it's background will change from white to black.
This is the correct way to handle mouse over events in CSS. It is standards compliant and will work in all modern browsers (and some older browsers too).
Sidenote: It won't always work in IE6, IE6 only recognizes the ":hover" pseudo-class when it's applied to anchor tags ("a:hover", etc).
Based on the update to your question:
<img src="klematis.jpg" style="opacity:0.4;filter:alpha(opacity=40)"
onmouseover="this.style.opacity=1;this.filters.alpha.opacity=100"
onmouseout="this.style.opacity=0.4;this.filters.alpha.opacity=40" />
That is using JavaScript to change the style. The only bit of this which is CSS is the style='...' part. The text in onmouseover and onmouseout is JavaScript.
To do what you want in pure CSS, it should be like this,
<html>
<head>
<style>
img.opacity-image {
opacity: 0.4;
filter:alpha(opacity=40); /* This is IE specific and NOT standards complaint */
}
img.opacity-image:hover {
opacity: 1;
filter:alpha(opacity=100); /* Again, 'filter:' is IE specific. */
}
</style>
</head>
<body>
...
<img src="klematis.jpg" class="opacity-image" />
....
</body>
</html>
opacity is CSS3 and only supported by modern browsers (IE6,7,8 don't support it). You can use filter:... to get opacity to work in IE (although it won't handle PNGs correctly, but since you're using JPG that's not an issue), but then your code isn't technically standards compliant as "filter" is not in the CSS standard. That doesn't generally matter too much though since it'll still render correctly in any modern browser.
I'm assuming you're talking about the :hover event?
<div id="hoverDiv"> Something should happen when you hover on me</div>
Style:
#hoverDiv:hover{ background-color:red; }
Visual example: http://jsfiddle.net/zRnug/
All hover effects you want to add to your stylesheet within the #selector:hover{ } area.
All effects you want to pertain before (the default style of the element), just use within the #selector{ } area.
Those are Javascript inline event handlers.
You can do this in pure CSS using the :hover selector.
CSS supports the :hover selector, which is triggered when you move the mouse over the item.
.mydiv {background-color:red;}
.mydiv:hover {background-color:blue;}
Any CSS property can be set to change on mouse-over using the :hover selector in this way.
Opacity is a CSS3 feature. It is supported by most browsers, but IE8 and lower don't support it. They do have an alternative way of doing it (using the IE-specific filter property); it's more fiddly than standard CSS and harder to get right, but it can be done.
Be aware that IE6 and lower only supports :hover on <a> elements. Other browsers (including IE7 and up) support it for all elements. My advice would be just not to support IE6 on your site, but if you do need to, there are hacks for it which can make :hover work correctly.

triggering browser Zoom-in and Zoom-out functions

Is it possible to trigger Browser's zoom-in and zoom-out function through JavaScript?
I want to add Zoom-In(+) and Zoom-Out(-) buttons in my website, and by clicking on the button want to call browser's zoom-in (which can be called by pressing ctrl and +) / zoom-out (ctrl and -) function.
I do not believe there is a standards based way to do this. Certain browsers may offer their own API to do this but I am doubtful.
That being said I have accomplished this effect in the past through some CSS trickery. Essentially in your CSS define every measurement (width, height, margin, padding, font-size, etc.) in em instead of px. This essentially makes the size of everything dependent on the default font size of the document. Then to zoom you change the font-size of the body tag to make things smaller or larger. If you do this carefully the effect will look the same as if the user zoomed using their browser.
To make life easier when doing this I like to use a CSS reset stylesheet that sets 1em to be 10px. That way if you want a div to be 200px wide you just set it to be 20em. You can accomplish this by setting the body font-size to 62.5% in your CSS reset stylesheet. Since most browsers have a default font size of 16px and therefore 1em=16px, 10px is 62.5%.
I hope this helps, it is a lot of work to do it right, but using em instead of px has helped me in countless ways when working with HTML and CSS.
Think this was already answered with
window.parent.document.body.style.zoom = 1.5;
"Zoom" a browser window/view with JavaScript?
I don't believe you can. On IE you could simulate it with the zoom CSS property, but that's non-standard and so support outside IE will vary.

Best way to do image rollovers?

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()...

Categories