Seven hover effects for images: a zoom inside a fixed frame, grayscale photos that turn to colour, a caption that slides up, an overlay with a magnifier, a gallery that blurs everything except the image you point at, a brand-coloured duotone wash and a thin inset frame.
The image scales up slightly inside a fixed frame on hover, the most common image hover there is. The frame has overflow: hidden and the link around it carries the focus style, so the same zoom shows for keyboard users.
View code
<a class="ih1" href="#journal"><span class="fr"><span class="im" role="img" aria-label="Coffee and notebook on a desk"></span></span><span class="t">How we plan a product launch</span></a>
Team photos sit in grayscale and come to life in colour when hovered or focused, a neat way to keep a grid of mixed photos looking consistent. It is a filter transition, so the image itself never changes.
A caption panel slides up from the bottom edge on hover or focus, with a gradient behind it so the white text stays readable over any photo. On touch screens the caption is always visible.
View code
<a class="ih3" href="#villa"><span class="im" role="img" aria-label="White villa above the sea"></span><span class="cap"><b>Villa Azul</b> Sleeps 6 · from €240 a night</span></a>
A dark overlay and a magnifier icon fade in over the image to say it opens larger. The link's accessible name says Open larger image of a red tram, which describes both the image and what the click does.
View code
<a class="ih4" href="#tram-large" aria-label="Open larger image of a red tram"><span class="im" aria-hidden="true"></span><span class="ov" aria-hidden="true"><svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="6"/><path d="M20 20l-4.5-4.5M11 8v6M8 11h6"/></svg></span></a>
In a gallery, hovering one image blurs and dims the rest so the chosen one stands out. :has() on the grid detects that something inside is hovered and styles every image that is not, with no JavaScript.
A colour wash in two brand colours sits over the image with mix-blend-mode, turning any photo into an on-brand duotone; hover lifts the wash to show the original. It is a common way to make stock photos feel part of one design.
View code
<a class="ih6" href="#story"><span class="im" role="img" aria-label="Mountain lake at dawn"></span><span class="wash" aria-hidden="true"></span><span class="t">Read the story</span></a>
A thin white frame draws itself inside the image edge on hover, a gallery-style touch for portfolios. The frame is an outline on a pseudo-element with a negative offset, scaling in from slightly larger, so it never affects the layout.
View code
<a class="ih7" href="#series"><span class="im" role="img" aria-label="Abstract blue and orange painting"></span></a>
Wrap the image in a frame with overflow: hidden and scale the image, not the frame. The card keeps its size and the zoom stays inside the rounded corners.
Filters are cheap to change
filter: grayscale(), blur() and contrast() transition smoothly and leave the image file untouched. Avoid blurring very large images on hover, which is heavier.
Effects on the link, not the image
Put the hover and :focus-visible rules on the link that wraps the image, so keyboard users get the same effect, and give the link a name that describes where it goes.
Touch screens show the resting state
There is no hover on phones, so any information revealed on hover, like a caption, should be visible by default under @media (hover: none).
Frequently asked questions
Where are the images?
The demos use gradients as stand-ins. Replace them with img elements with proper alt text.
How does the blur-the-others effect work?
:has() lets the gallery know one item is hovered, and :not(:hover) styles the rest.
Which effect suits product grids?
A gentle zoom or a second product photo on hover; avoid effects that hide the product.