Une bordure au survol d'une image ?

Vous désirez afficher (ou changer) une bordure de couleur lorsque l'utilisateur survole une image-lien, une vignette par exemple.

Voici un comportement qui semble simple à première vue, mais qui demande un certain nombre de précautions pour fonctionner correctement sur tous les navigateurs.

Premier essai

L'image choisie pour cette petite expérience est un avatar de 100px par 100px :

Elle servira de vignette : lorsque le visiteur la survolera pour agrandir l'image, elle doit s'entourer d'une bordure bleue.

Je commence à supprimer les bordures bleues par défaut de l'image-lien :

a img {
border: 0 none;
}

Ensuite, j'applique une bordure sur le comportement :hover, elle sera de 2 pixels, solide et bleue :

a:hover {
border: 2px solid blue;
}

Cette manipulation semble suffisante, mais le résultat est assez surprenant :

Résultat sur Internet Explorer :

Résultat sur Internet Mozilla/Geckos :

Voir le résultat sur votre navigateur

Adaptations

Les problèmes d'affichage rencontrés nous rappellent à l'ordre : la balise <a> est un élément en-ligne qui n'est pas prévu pour posséder des dimensions.
La bordure entoure par conséquent un élement sans dimension et il est logique que cela provoque quelques soucis.

Voyons ce qu'il se passe en transformant notre balise <a> en élément bloc :

a {
display: block;
}

Résultat sur les deux navigateurs :

Voir le résultat sur votre navigateur

A noter que le résultat est le même en ajoutant la propriété "width: auto" à notre balise devenue bloc.

Une solution serait évidemment de donner à la balise <a> les mêmes dimensions que l'image vignette, mais cela risque d'être répétitif et ennuyeux dans le cas de multiples vignettes de tailles différentes.

Une solution au problème

Notre balise <a> doit se comporter en bloc... mais sans utiliser toute la largeur disponible de son conteneur.

Cela est possible en utilisant les propriétés "float" ou "position", car en les positionnant, ces propriétés transforment automatiquement les balises en-ligne en balises bloc.

En positionnant la balise en "absolu", la bordure entoure correctement l'image :

a {
position: absolute;
}

Le résultat est comparable avec un positionnement flottant :

a {
float: left;
}

Cependant, il reste quelques petits soucis d'affichage :

  • L'image est décallée de quelques pixel lors du survol
  • Mozilla laisse un espace blanc sous l'image

Le premier souci est réglé en donnant au lien une bordure au repos, de la même taille que la bordure au survol :

a {
float: left;
border : 2px solid white;
}

Le second problème est dû au fait que l'image est une balise en-ligne et qu'elle s'aligne sur la ligne de texte par défaut. Le problème se corrige en donnant une hauteur d'interligne minime :

a {
float: left;
border : 2px solid white;
line-height: 1px;
}

Voir le résultat avec la solution "position absolue"

Voir le résultat avec la solution "float"

A vous de jouer ?

Les solutions proposées ne sont pas la panacée, comme vous vous en doutez : les positionnement absolus et flottant ont leur lots de contraintes.

Mais peut-être connaissez-vous une autre solution, ou avez-vous envie de vous amuser un peu à en trouver :-)

Trackbacks

Aucun trackback pour le moment.

Les trackbacks pour ce billet sont fermés.

Evaluez ce billet

Commentaires

Le mercredi 1 septembre 2004 à 22:02, par Etienne :: site :: #

En envisagent d'autres techniques qui pourraient marcher on pourrait lui attribuer un margin de départ de l'épaisseur de la futur bordure, qui disparaît quand la bordure apparaît, donc pas de déplacement ; j'utilise cette méthode pour mon menu de navigation sur mon site

Le mercredi 1 septembre 2004 à 22:08, par Raphael Goetter :: site :: #

@Etienne > ma première tentative misait sur une margin effectivement, mais cela posait ensuite (avec border) des soucis de box-model sur IE :-(

Le mercredi 1 septembre 2004 à 22:48, par Stéph' :: site :: #

Pour gecko il existe au moins 3 solution pour arriver à un résultat correct :

img:hover{border: 2px solid blue;}
a:hover img{border: 2px solid blue;}
et
a:hover { display:table-cell;
border: 2px solid blue;}

Mais seule la troisième fonctionne sous IE avec le même défaut que tu évoques à savoir que le border-top part dans la nature... Mais on peut corriger celà très facilement en ajoutant simplement un margin-top dans la déclaration a img :
a img {
border: 0 none; /* suppression des marges par défaut sur l'image */
margin-top:1px; /* Hack ie pour faire apparaitre la bordure sup */
}
Ca fonctionne également sous Opéra >7.

Sinon on peut aussi jouer sur le fond vu que l'image est transparente, l'exemple suivant fonctionne sur les deux :
a:hover { display:table-cell;
background-color:blue;}

On pourrais donc aussi envisager d'avoir une image de 100x100px avec une bordure déssinnée et l'intérieur transparent que l'on viendrait plaque en background avec cette même règle CSS.

Cdlt,
Stéph'



Le jeudi 2 septembre 2004 à 01:06, par Bobe :: #

Avec display: inline-block; c'est ok sur IE (sauf qu'il bouffe la bordure supérieure) et Opera. Pour que ce soit bon aussi sous Mozilla, ajouter un deuxième display avec la valeur -moz-inline-box.

Le jeudi 2 septembre 2004 à 04:07, par Laurent Denis :: #

Pourquoi vous compliquez-vous la vie ?

a {
display: table-cell;
border: 2px solid #fff;
}
a:hover {
border: 2px solid blue;
}

Cela dit, la méthode "logique" serait d'appliquer le :hover à l'image et non au lien, et de renoncer à cet effet dans IE.

Le jeudi 2 septembre 2004 à 06:11, par Laurent Denis :: site :: #

@Raphael > "Les problèmes d'affichage rencontrés nous rappellent à l'ordre : la balise <a> est un élément en-ligne qui n'est pas prévu pour posséder des dimensions."

???
Un élément en ligne a des dimensions ! Une image en est le meilleur exemple...

Ce qui est exact, c'est qu'un élément en ligne **non remplacé** (le a) n'a en effet pas de hauteur, celle-ci n'étant calculée qu'à partir de 'line-height'. Voir:
www.w3.org/TR/REC-CSS2/vi...

Le jeudi 2 septembre 2004 à 10:00, par vchahun :: site :: #

Conclusion: vivement que IE accepte le img:hover, qui fait partie de la norme CSS2 (et oui, pauvres utilisateurs de ce browser obsolète ...)

Le jeudi 2 septembre 2004 à 12:13, par Raphael Goetter :: site :: #

@Laurent Denis >

- Pourquoi on se complique la vie? Pour que ce soit compatible avec le navigateur qui occupe entre 80 et 90% des parts de marché et qui ne comprend pas display: table-cell;

- "Un élément en ligne a des dimensions ! Une image en est le meilleur exemple..."
> L'image est, je crois, le seul élément en ligne qui possède des propriétés de dimension (width et height)

Qu'est-ce qu'un élément en ligne **non remplacé** ?

@vchahun : "vivement que IE accepte le img:hover" > oui évidemment, mais en attendant, il faut bien trouver des solutions qui fonctionnent partout.

Le jeudi 2 septembre 2004 à 12:15, par Raphael Goetter :: site :: #

Si les éléments en-ligne ont des dimensions, pourquoi ce genre de choses ne fonctionne-t-il pas ?

em {
width: 5em;
height: 5em;
background-color: blue;
}

En effet, le em n'aura toujours que la taille du texte qu'il contient.

Le jeudi 2 septembre 2004 à 12:57, par Bobe :: #

Parce que width et height ne s'appliquent pas sur un élément en-ligne non-remplacé.
Par contre, ils pourront s'appliquer à un élément IMG qui est un élément en-ligne remplacé.

Le jeudi 2 septembre 2004 à 13:03, par Raphael Goetter :: site :: #

@Bobe> Ok, mais qu'est-ce qu'un élément remplacé ? Lesquels sont-ils ?

Le jeudi 2 septembre 2004 à 13:07, par Bobe :: #

www.w3.org/TR/REC-CSS2/co...

Le jeudi 2 septembre 2004 à 13:16, par Raphael Goetter :: site :: #

Merci Bobe, je venais de tomber dessus également.
Les éléments "remplacés" sont donc les seuls qui possèdent des dimensions (height, width) par défaut. Il s'agit des éléments IMG, INPUT, TEXTAREA, SELECT, et OBJECT.

Pour tous les autres éléments en-ligne (cf www.w3.org/TR/REC-CSS2/vi... et www.w3.org/TR/REC-CSS2/vi... :
- The 'width' property does not apply. A specified value of 'auto' for 'left', 'right', 'margin-left' or 'margin-right' becomes a computed value of '0'.
- The 'height' property doesn't apply, but the height of the box is given by the 'line-height' property.

C'est bien ça ?

Le jeudi 2 septembre 2004 à 15:49, par Bobe :: #

Oui.
Par contre, pour les éléments non-remplacés, mais positionnés en absolus ou flottants, c'est différent d'après ce que je lis.

Le jeudi 2 septembre 2004 à 15:55, par Raphael Goetter :: site :: #

Et après on dit que les standards et les CSS sont compliqués ! :-D

Le jeudi 2 septembre 2004 à 17:59, par Laurent Denis :: #

Bon, je mets un article sur les éléments remplacés/non remplacés/en ligne/dimensionnés sur la todo list d'OpenWeb ! ;)

Cela dit, Raphael, la solution du dipslay: table-cell ci-dessus **est justement fait pour que ça MARCHE DANS IE**, plus simplement que celle que tu proposes.

Je ré-explique :

Solution simple pour Opera/Gecko/IE :
a {
display: table-cell;
border: 2px solid #fff;
}
a:hover {
border: 2px solid blue;
}

Le display:table-cell compris par Opera et les navigateurs Gecko permet simplement d'étendre les deux dimension du <a> à son contenu.

Le jeudi 2 septembre 2004 à 18:19, par Raphael Goetter :: site :: #

@Laurent : merci pour ces explications que je n'avais pas saisie en effet... et j'attends l'article avec impatience :-)

Le jeudi 2 septembre 2004 à 23:13, par Raphael Goetter :: site :: #

En attendant, j'ai pondu moi-même un petit article de vulgarisation sur le sujet bloc/en-ligne.
C'est sensé être abordable par presque tout le monde et n'entre volontairement pas dans les détails.
J'espère que je n'ai pas écrit de grosse bêtises :
www.alsacreations.com/art...

Le vendredi 3 septembre 2004 à 10:19, par ElMoustiko :: site :: #

Euh question stupide, pourquoi ne pas faire :
a:hover img {
border: 1px solid blue
}

Ca revient à img:hover mais avec un lien sur l'image (ce qui est prévu dans le problème d'après ce que j'ai compris).

Non Laurent ne me flagèle pas à coup de cable réseau dénudé, je me posais juste la question ;p

Je n'ai pas testé, mais je ne vois pas pourquoi ça ne fonctionnerais pas, et je ne vois pas de problème de compatibilité apparaitre (je peux me tromper bien sûr).

Le vendredi 3 septembre 2004 à 10:22, par ElMoustiko :: site :: #

Question subsidiaire, rapport au tuto sur les elements inline/block, tu dis que les éléments block peuvent contenir des elements block et inline, okay, mais PRE est de type block et ne peut contenir que des éléments inline... (enfin encore une fois si j'ai bien tout suivi) donc il faudrait peut être préciser cette exception (et eventuellement voir s'il y en a d'autre, si c'en est réellement une).
@++

Le vendredi 3 septembre 2004 à 10:31, par Raphael Goetter :: site :: #

@ElMoustiko > il y'a effectivement des exceptions. il y'a aussi des balises qui ne peuvent contenir QUE certaines autres balises (ul par exemple ne peut contenir que li)... mais le but n'était pas de faire un truc très complet et très pointu (je laisse ça à OpenWeb, qui est fait pour ça ;-)).
L'objectif est de donner les orientations et règles de base afin que le "tuto" soit accessible au plus grand nombre.
Les exceptions et les particularités peuvent rapidement décourager les novices.

Le vendredi 3 septembre 2004 à 10:41, par Raphael Goetter :: site :: #

En fait, pour PRE si on veut vraiment chercher la petite bête : il ne peut contenir que des en-ligne... sauf IMG, OBJECT, APPLET, BIG, SMALL, SUB, SUP, FONT et BASEFONT ! :-)

Le vendredi 3 septembre 2004 à 11:00, par ElMoustiko :: site :: #

Oui... mais même !
Très juste pour ce qui est des UL aussi ( idem pour les OL et DL, DL ne pouvant contenir que DT ou DD (enfin il me semble encore une fois))

Sinon t'as testé mon idée pour le problème des bordures ? Vais être obligé de tester tout seul !

Le vendredi 3 septembre 2004 à 11:09, par ElMoustiko :: site :: #

Okay bah testé ... ca ne marche pas sous IE (qui l'eut cru). Donc je propose à IE d'aller prendre des cours de navigateur.
Code final qui fonctionne impecable sous les gecko et opera :
img {
border: none;
margin: 2px;
}
a:hover img {
border: 2px solid #00f;
margin: 0;
}

Avec le xhtml correspondant : <a href="index.html"><img src="avatar.gif" alt="PapySibeliusNoel" /></a>

Donc, voilà IE nous montre une fois de plus sa nullité, vous allez dire que je lui jette tout le temps la pierre mais bon c'est pas de ma faute.

La solution de Laurent ne fonctionne pas, on a une marge basse pour les gecko, ça ne fait pas très esthétique, et sous IE il manque la bordure haute. Donc à part en bourrant le tout de hacks (pas bien ! ) c'est pas vraiment envisageable sous IE.

Sinon d'accord avec Laurent sur le fait que ça n'est pas particulierement génant que ça ne fonctionne pas sous IE, ça n'empeche pas la navigation... donc pourquoi se gener.

Le vendredi 3 septembre 2004 à 11:14, par Raphael Goetter :: site :: #

"Sinon d'accord avec Laurent sur le fait que ça n'est pas particulierement génant que ça ne fonctionne pas sous IE, ça n'empeche pas la navigation... donc pourquoi se gener."

>> Sur le principe, je suis entièrement d'accord, mais le but du jeu était ici - justement - de trouver une solution appliquable partout. Sinon il était effectivement simple de trouver une solution non-IE :-)

Le vendredi 3 septembre 2004 à 11:20, par ElMoustiko :: site :: #

Ahh d'accord, j'avais encore rien compris en fait !

Sinon il existe une solution mais pas vraiment viable (je ne l'ai pas testé, mais aucun doute qu'elle fonctionne, enfin sait-on jamais avec IE...) on fait un display: block; sur les a, et on leur donne width: ; et height: ; en fonction de l'image, si c'est une image de dimension fixe, c'est envisageable mais moyen comme méthode je trouve, sinon... bah je vois pas...

J'ai quand même dans l'idée que c'est possible mais avec quelques hack obligatoirement, faudrait quand même essayer voir si le/les hack/s sont si affreux...

Le vendredi 3 septembre 2004 à 11:27, par Raphael Goetter :: site :: #

"on fait un display: block; sur les a, et on leur donne width: ; et height: ; en fonction de l'image"

>> oui mais c'était déjà prévu ;)
"Une solution serait évidemment de donner à la balise a les mêmes dimensions que l'image vignette, mais cela risque d'être répétitif et ennuyeux dans le cas de multiples vignettes de tailles différentes."

Le vendredi 3 septembre 2004 à 12:47, par Bobe :: #

Et sinon, ma solution avec display: inline-block;, elle vous plaît pas ? :(

Le vendredi 3 septembre 2004 à 12:55, par Raphael Goetter :: site :: #

@Bobe > en fait je n'ai pas testé, vu que tu dis toi-même "Avec display: inline-block; c'est ok sur IE (sauf qu'il bouffe la bordure supérieure)" :-/

Le mardi 7 septembre 2004 à 09:29, par goetsu :: #

je sais y en a qui vont crier au scandale mais ça valide et ça marche sur gecko opera et ie 5.5 et 6:

<style type="text/css">
<!--
a img
{
border: 1px solid #330000;
}
a:hover img
{
border: 1px solid #CC0000;
}
-->
</style>
<!--[if gte ie 5.5000]>
<style type="text/css">
a:hover img {
Filter: none;
}
</style>
<![endif]-->

Le mardi 7 septembre 2004 à 22:29, par Laurent Denis :: #

Faudrait que j'explique un peu mieux la solution du diplay:table-cell...

Mais surtout : goetsu, tu as sans doute eu la seule idée intelligente de cette page ;) Quoique ce soit un peu lourd pour un effet finalement généralement... moche, et dont les utilisateurs d'IE seraient sans doute ravis de se passer.

Non ?

:D

Le mardi 7 septembre 2004 à 22:36, par Raphael Goetter :: site :: #

Bah v'la t'y pas que le Laurent me casse tout mon jeu !! :D

Le mercredi 8 septembre 2004 à 09:30, par goetsu :: #

la complexité de la chose n'est là que pour laissé le css valide si on s'en fou un simple

img
{
border: 1px solid #330000;
}
a:hover img
{
border: 1px solid #CC0000;
Filter: none;
}

suffit. Mais bon pour dire la vérité je sais pas pourquoi ça marche (les méandre des filtres activeX de ie me sont inconnu) et avec XP sp2 on a un blocage par la sécurité de ie qui peut etre desactivable mais qui est toujours désagreable. Il serait d'ailleurs intéressant si ça le fait sur tous les filtres activeX notament ceux permettant la gestion de la transparence sur les png

Le mercredi 8 septembre 2004 à 19:50, par goetsu :: #

Le retour de la soluce qui tue number2:

a:link {text-decoration: none }
a:active {text-decoration: none }
a:visited {text-decoration: none}
a:hover {text-decoration: underline }
:hover img { border: 1px dashed #000000 }
img{
border: 1px solid #603913;
}

Ajouter un commentaire

Les commentaires pour ce billet sont fermés.