Derniers récits
Voir les 48 récits →Nouveau récit chaque jeudi
Votre image grossit doucement dans son cadre quand la souris passe dessus ou quand le lien qui l'entoure reçoit le focus clavier, sans une ligne de JavaScript.
Mis à jour le
Cet effet est gratuit — la catégorie Galerie en contient 44 au total, dont 6 gratuits. Effect.Labs regroupe 840 effets vanilla. Découvrir la catégorie →
Voir les 48 récits →Nouveau récit chaque jeudi
21 – 23 mars · Halle couverte · 140 éditeurs · entrée libre le dimanche
ProgrammeDédicacesVenir au salon
Le cadre .hzm-frame coupe ce qui dépasse (overflow: hidden) et contient votre <img class="hzm-image">, recadrée comme une photo de couverture (object-fit: cover). Au survol, l'image passe à scale(var(--hzm-scale)), soit 1,3, en --hzm-duration (0,5 s) avec une courbe qui ralentit à la fin.
Par défaut le cadre est un lien <a> : remplacez href="#" par votre adresse. Le zoom se déclenche aussi quand le lien reçoit le focus au clavier, et quand on survole ou atteint au Tab un lien qui entoure le cadre, par exemple toute une carte d'article. Si l'image n'est pas cliquable, changez le <a> en <div> : le survol reste, le focus n'a plus lieu d'être.
Tout est en CSS rattaché à .fx-0179-root et au préfixe hzm- : autant de copies que voulu sur une page, aucun conflit avec vos propres classes. Le cadre prend la largeur disponible jusqu'à --hzm-width (280 px) et garde --hzm-ratio.
:focus-visible). Dans Safari, Tab n'atteint les liens que si l'option « Tab pour sélectionner chaque élément » est active (Option + Tab sinon).aria-hidden).prefers-reduced-motion: reduce, la transition est retirée ; l'image passe directement à sa taille agrandie.CSS seul : transform, object-fit, aspect-ratio, :focus-visible (règle séparée pour ne pas faire tomber le survol dans les navigateurs qui ne la connaissent pas). Mesuré dans Chromium 151, Firefox 153 et WebKit 26.5 : deux copies indépendantes, zoom au survol et au focus clavier, mouvement réduit sans transition, aucun débordement à 390 px.
Avant Safari 15.4, le zoom au focus clavier ne s'applique pas (le survol, si). Sans aspect-ratio, le cadre prend la hauteur de l'image.
Copiez les deux blocs (HTML et CSS) dans votre page. Aucun JavaScript, aucune dépendance.
<div class="fx-0179-root">
<a class="hzm-frame" href="#">
<img class="hzm-image" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='560' height='400' viewBox='0 0 560 400'%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop stop-color='%23667eea'/%3E%3Cstop offset='.5' stop-color='%23764ba2'/%3E%3Cstop offset='1' stop-color='%23f093fb'/%3E%3C/linearGradient%3E%3Cpattern id='s' width='20' height='20' patternUnits='userSpaceOnUse' patternTransform='rotate(45)'%3E%3Crect x='10' width='10' height='20' fill='%236366f1' fill-opacity='.1'/%3E%3C/pattern%3E%3Cpattern id='q' width='20' height='20' patternUnits='userSpaceOnUse'%3E%3Cpath d='M0 .5H20M.5 0V20' stroke='%23fff' stroke-opacity='.1'/%3E%3C/pattern%3E%3CradialGradient id='l' cx='168' cy='120' r='241' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-color='%23fff' stop-opacity='.3'/%3E%3Cstop offset='1' stop-color='%23fff' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='d' cx='392' cy='280' r='241' gradientUnits='userSpaceOnUse'%3E%3Cstop stop-opacity='.2'/%3E%3Cstop offset='1' stop-opacity='0'/%3E%3C/radialGradient%3E%3Crect width='560' height='400' fill='url(%23g)'/%3E%3Crect width='560' height='400' fill='url(%23s)'/%3E%3Crect width='560' height='400' fill='url(%23q)'/%3E%3Crect width='560' height='400' fill='url(%23l)'/%3E%3Crect width='560' height='400' fill='url(%23d)'/%3E%3C/svg%3E" alt="Motif dégradé violet quadrillé" width="560" height="400">
<span class="hzm-label" aria-hidden="true">Hover Me</span>
</a>
</div>
/* fx-0179 — Hover Zoom: the image grows inside its frame on hover or keyboard focus (CSS only).
Everything is scoped to .fx-0179-root and the hzm- prefix: two copies on one page stay independent. */
.fx-0179-root,
.fx-0179-root *,
.fx-0179-root *::before,
.fx-0179-root *::after {
box-sizing: border-box;
}
.fx-0179-root {
--hzm-scale: 1.3; /* zoom level on hover / keyboard focus */
--hzm-duration: 0.5s; /* zoom-in and zoom-out time */
--hzm-width: 280px; /* maximum frame width (the frame shrinks on small screens) */
--hzm-ratio: 7 / 5; /* frame shape */
--hzm-radius: 0.75rem; /* frame corners */
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 250px;
padding: 16px;
position: relative;
background: #0a0a0f;
color: #fff;
font-family: sans-serif;
}
/* Frame: fluid width (capped by --hzm-width), height from --hzm-ratio */
.hzm-frame {
position: relative;
display: block;
width: 100%;
max-width: var(--hzm-width);
aspect-ratio: var(--hzm-ratio);
border-radius: var(--hzm-radius);
overflow: hidden;
isolation: isolate;
background: #12121a;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.hzm-frame:focus-visible {
outline: 2px solid #fff;
outline-offset: 3px;
}
/* Your image: any <img>, cropped to the frame like a cover photo */
.hzm-image {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
-webkit-user-select: none;
user-select: none;
}
/* Optional caption over the image (delete the span if you do not want it) */
.hzm-label {
position: absolute;
inset: 0;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-weight: 600;
font-size: 1.2rem;
text-shadow: rgba(0, 0, 0, 0.3) 0 2px 4px;
pointer-events: none;
}
.hzm-frame {
cursor: pointer;
color: inherit;
text-decoration: none;
}
.hzm-image {
transition: transform var(--hzm-duration) cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
/* Hover on the frame or on a link that wraps it */
.hzm-frame:hover .hzm-image,
.fx-0179-root a:hover .hzm-image {
transform: scale(var(--hzm-scale));
}
/* Keyboard focus on the frame (a link) or on a link that wraps it (separate rule: older browsers skip it alone) */
.hzm-frame:focus-visible .hzm-image,
.fx-0179-root a:focus-visible .hzm-image {
transform: scale(var(--hzm-scale));
}
/* Reduced motion: the image still zooms, without the transition */
@media (prefers-reduced-motion: reduce) {
.hzm-image {
transition: none;
}
}
CSS pur — aucun JavaScript requis.
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Image (HTML — src de .hzm-image) |
motif violet quadrillé (SVG intégré) | Votre photo et son alt, qui nomme aussi le lien. |
--hzm-scale |
1.3 | Grossissement au survol ; 1.05 à 1.15 pour des cartes, 1.3 pour un effet marqué. |
--hzm-duration |
0.5s | Durée de l'aller et du retour ; 1s et plus pour une grande image. |
--hzm-width · --hzm-ratio · --hzm-radius |
280px · 7 / 5 · 0.75rem | Largeur maximale du cadre (il rétrécit sur petit écran), proportions et arrondi. |
| Balise du cadre | <a href="#"> |
Mettez votre adresse ; ou une <div> si l'image n'est pas un lien, ou placez le cadre dans un lien plus large (carte entière). |
Légende .hzm-label |
« Hover Me » | Texte centré sur l'image ; supprimez le <span> sur une vraie photo. |
Non. Tout tient dans le CSS : :hover et :focus-visible déclenchent le transform, le cadre coupe l'excédent.
Entourez le cadre et le texte d'un même lien placé dans .fx-0179-root : la règle .fx-0179-root a:hover .hzm-image agrandit l'image dès que la carte est survolée.
Seulement si le fichier est juste à la taille du cadre. Prévoyez une image 1,3 fois plus large (ou la valeur de --hzm-scale).