Creating a caption hover animation for an image is a common web design task that can be achieved using HTML and CSS.
HTML:
First, create a basic HTML structure with an image and a caption:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Caption Hover Animation</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container demo-3">
<ul class="grid cs-style-3">
<li>
<figure>
<img src="https://tympanus.net/Tutorials/CaptionHoverEffects/images/6.png" alt="img03">
<figcaption>
<h3>Code With Ubes</h3>
<span>Ubes Aslam</span>
<a href="https://codewithubes.in">Read More</a>
</figcaption>
</figure>
</li>
</ul>
</div>
<script src="toucheffects.js"></script>
</body>
</html>
CSS:
Next, style the image and caption. The caption will be hidden by default and appear with an animation when the image is hovered over.
@import url(https://fonts.googleapis.com/css?family=Lato:300,400,700);
@font-face {
font-famiy: 'codropsicons';
font-weight: normal;
font-style: normal;
}
*, *:after, *:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body, html {
font-size: 100%;
padding: 0;
margin: 0;
}
.clearfix:before, .clearfix:after {
content: " ";
display: table;
}
.clearfix:after {
clear: both;
}
body {
font-family: 'Lato', Calibri, Arial, sans-serif;
color: #b3b9bf;
background: #f9f9f9;
}
.grid {
padding: 20px 20px 100px 20px;
max-width: 1300px;
margin: 0 auto;
list-style: none;
text-align: center;
}
.grid li {
display: inline-block;
width: 440px;
margin: 0;
padding: 20px;
text-align: left;
position: relative;
}
.grid figure {
margin: 0;
position: relative;
}
.grid figure img {
max-width: 100%;
display: block;
position: relative;
}
.grid figcaption {
position: absolute;
top: 0;
left: 0;
padding: 20px;
background: #2c3f52;
color: #ed4e6e;
font-face: "san-serif";
}
.grid figcaption h3 {
margin: 0;
padding: 0;
color: #fff;
font-face: "san-serif";
}
.grid figcaption span:before {
content: 'by ';
}
.grid figcaption a {
text-align: center;
padding: 5px 10px;
border-radius: 2px;
display: inline-block;
background: #ed4e6e;
color: #fff;
text-decoration: none;
}
.cs-style-3 figure {
overflow: hidden;
}
.cs-style-3 figure img {
-webkit-transition: -webkit-transform 0.4s;
-moz-transition: -moz-transform 0.4s;
transition: transform 0.4s;
}
.no-touch .cs-style-3 figure:hover img,
.cs-style-3 figure.cs-hover img {
-webkit-transform: translateY(-50px);
-moz-transform: translateY(-50px);
-ms-transform: translateY(-50px);
transform: translateY(-50px);
}
.cs-style-3 figcaption {
height: 100px;
width: 100%;
top: auto;
bottom: 0;
opacity: 0;
-webkit-transform: translateY(100%);
-moz-transform: translateY(100%);
-ms-transform: translateY(100%);
transform: translateY(100%);
-webkit-transition: -webkit-transform 0.4s, opacity 0.1s 0.3s;
-moz-transition: -moz-transform 0.4s, opacity 0.1s 0.3s;
transition: transform 0.4s, opacity 0.1s 0.3s;
}
.no-touch .cs-style-3 figure:hover figcaption,
.cs-style-3 figure.cs-hover figcaption {
opacity: 1;
-webkit-transform: translateY(0px);
-moz-transform: translateY(0px);
-ms-transform: translateY(0px);
transform: translateY(0px);
-webkit-transition: -webkit-transform 0.4s, opacity 0.1s;
-moz-transition: -moz-transform 0.4s, opacity 0.1s;
transition: transform 0.4s, opacity 0.1s;
}
.cs-style-3 figcaption a {
position: absolute;
bottom: 20px;
right: 20px;
}
Javascript:
This is toucheffects.js
library reference by Modernizr 2.6.2 (Custom Build).
/* Modernizr 2.6.2 (Custom Build) | MIT & BSD
* Build: https://modernizr.com/download/#-touch-shiv-cssclasses-teststyles-prefixes-load
*/
;
window.Modernizr=function(a, b, c) {
function w(a) {
j.cssText=a
}
function x(a, b) {
return w(m.join(a + ";") + (b || ""))
}
function y(a, b) {
return typeof a===b
}
function z(a, b) {
return ! !~("" + a).indexOf(b)
}
function A(a, b, d) {
for (var e in a) {
var f=b[a[e]];
if (f !==c) return d=== !1 ? a[e]: y(f, "function") ? f.bind(d || b): f
}
return !1
}
var d="2.6.2",
e= {},
f= !0,
g=b.documentElement,
h="modernizr",
i=b.createElement(h),
j=i.style,
k,
l= {}.toString,
m=" -webkit- -moz- -o- -ms- " .split(" "),
n= {},
o= {},
p= {},
q=[],
r=q.slice,
s,
t=function(a, c, d, e) {
var f,
i,
j,
k,
l=b.createElement("div"),
m=b.body,
n=m || b.createElement("body");
if (parseInt(d, 10)) while (d--) j=b.createElement("div"),
j.id=e ? e[d]: h + (d + 1), l.appendChild(j);
return f=["­",
'<style id="s',
h,
'">',
a,
"</style>"].join(""),
l.id=h,
(m ? l : n).innerHTML+=f,
n.appendChild(l),
m || (n.style.background="", n.style.overflow="hidden", k=g.style.overflow, g.style.overflow="hidden", g.appendChild(n)),
i=c(l, a),
m ? l.parentNode.removeChild(l): (n.parentNode.removeChild(n), g.style.overflow=k), ! !i
},
u= {}.hasOwnProperty,
v;
!y(u, "undefined") && !y(u.call, "undefined") ? v=function(a, b) {
return u.call(a, b)
}
: v=function(a, b) {
return b in a && y(a.constructor.prototype[b], "undefined")
},
Function.prototype.bind || (Function.prototype.bind=function(b) {
var c=this;
if (typeof c !="function") throw new TypeError;
var d=r.call(arguments, 1),
e=function() {
if (this instanceof e) {
var a=function() {}
;
a.prototype=c.prototype;
var f=new a,
g=c.apply(f, d.concat(r.call(arguments)));
return Object(g)===g ? g : f
}
return c.apply(b, d.concat(r.call(arguments)))
}
;
return e
}),
n.touch=function() {
var c;
return "ontouchstart" in a || a.DocumentTouch && b instanceof DocumentTouch ? c= !0 : t(["@media (", m.join("touch-enabled),("), h, ")", "{#modernizr{top:9px;position:absolute}}"].join(""), function(a) {
c=a.offsetTop===9
}),
c
}
;
for (var B in n) v(n, B) && (s=B.toLowerCase(), e[s]=n[B](), q.push((e[s] ? "" : "no-") + s));
return e.addTest=function(a, b) {
if (typeof a=="object") for (var d in a) v(a, d) && e.addTest(d, a[d]);
else {
a=a.toLowerCase();
if (e[a] !==c) return e;
b=typeof b=="function" ? b(): b, typeof f !="undefined" && f && (g.className +=" " + (b ? "" : "no-") + a), e[a]=b
}
return e
}
,
w(""),
i=k=null,
function(a, b) {
function k(a, b) {
var c=a.createElement("p"),
d=a.getElementsByTagName("head")[0] || a.documentElement;
return c.innerHTML="x<style>"+b+"</style>",
d.insertBefore(c.lastChild, d.firstChild)
}
function l() {
var a=r.elements;
return typeof a=="string" ? a.split(" "): a
}
function m(a) {
var b=i[a[g]];
return b || (b= {}
, h++, a[g]=h, i[h]=b),
b
}
function n(a, c, f) {
c || (c=b);
if (j) return c.createElement(a);
f || (f=m(c));
var g;
return f.cache[a] ? g=f.cache[a].cloneNode(): e.test(a) ? g=(f.cache[a]=f.createElem(a)).cloneNode(): g=f.createElem(a), g.canHaveChildren && !d.test(a) ? f.frag.appendChild(g): g
}
function o(a, c) {
a || (a=b);
if (j) return a.createDocumentFragment();
c=c || m(a);
var d=c.frag.cloneNode(),
e=0,
f=l(),
g=f.length;
for (; e < g; e++) d.createElement(f[e]);
return d
}
function p(a, b) {
b.cache || (b.cache= {}
, b.createElem=a.createElement, b.createFrag=a.createDocumentFragment, b.frag=b.createFrag()),
a.createElement=function(c) {
return r.shivMethods ? n(c, a, b): b.createElem(c)
}
,
a.createDocumentFragment=Function("h,f", "return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&(" + l().join().replace(/\w+/g, function(a) {
return b.createElem(a), b.frag.createElement(a), 'c("' + a + '")'
}) + ");return n}")(r, b.frag)
}
function q(a) {
a || (a=b);
var c=m(a);
return r.shivCSS && !f && !c.hasCSS && (c.hasCSS= ! !k(a, "article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}mark{background:#FF0;color:#000}")),
j || p(a, c),
a
}
var c=a.html5 || {}
,
d=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,
e=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,
f,
g="_html5shiv",
h=0,
i= {}
,
j;
(function() {
try {
var a=b.createElement("a");
a.innerHTML="<xyz></xyz>", f="hidden" in a, j=a.childNodes.length==1 || function() {
b.createElement("a");
var a=b.createDocumentFragment();
return typeof a.cloneNode=="undefined" || typeof a.createDocumentFragment=="undefined" || typeof a.createElement=="undefined"
}
()
}
catch (c) {
f= !0, j= !0
}
})();
var r= {
elements: c.elements || "abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",
shivCSS: c.shivCSS !== !1,
supportsUnknownElements: j,
shivMethods: c.shivMethods !== !1,
type: "default",
shivDocument: q,
createElement: n,
createDocumentFragment: o
}
;
a.html5=r,
q(b)
}
(this, b),
e._version=d,
e._prefixes=m,
e.testStyles=t,
g.className=g.className.replace(/(^|\s)no-js(\s|$)/, "$1$2")+(f ? " js " + q.join(" ") : ""),
e
}
(this, this.document),
function(a, b, c) {
function d(a) {
return "[object Function]"==o.call(a)
}
function e(a) {
return "string"==typeof a
}
function f() {}
function g(a) {
return !a || "loaded"==a || "complete"==a || "uninitialized"==a
}
function h() {
var a=p.shift();
q=1,
a ? a.t ? m(function() {
("c"==a.t ? B.injectCss : B.injectJs)(a.s, 0, a.a, a.x, a.e, 1)
}
, 0) : (a(), h()) : q=0
}
function i(a, c, d, e, f, i, j) {
function k(b) {
if ( !o && g(l.readyState) && (u.r=o=1, !q && h(), l.onload=l.onreadystatechange=null, b)) {
"img" !=a && m(function() {
t.removeChild(l)
}
, 50);
for (var d in y[c]) y[c].hasOwnProperty(d) && y[c][d].onload()
}
}
var j=j || B.errorTimeout,
l=b.createElement(a),
o=0,
r=0,
u= {
t: d,
s: c,
e: f,
a: i,
x: j
}
;
1===y[c] && (r=1, y[c]=[]),
"object"==a ? l.data=c : (l.src=c, l.type=a),
l.width=l.height="0",
l.onerror=l.onload=l.onreadystatechange=function() {
k.call(this, r)
}
,
p.splice(e, 0, u),
"img" !=a && (r || 2===y[c] ? (t.insertBefore(l, s ? null : n), m(k, j)) : y[c].push(l))
}
function j(a, b, c, d, f) {
return q=0,
b=b || "j",
e(a) ? i("c"==b ? v : u, a, b, this.i++, c, d, f): (p.splice(this.i++, 0, a), 1==p.length && h()), this
}
function k() {
var a=B;
return a.loader= {
load: j,
i: 0
}
,
a
}
var l=b.documentElement,
m=a.setTimeout,
n=b.getElementsByTagName("script")[0],
o= {}
.toString,
p=[],
q=0,
r="MozAppearance" in l.style,
s=r && ! !b.createRange().compareNode,
t=s ? l : n.parentNode,
l=a.opera && "[object Opera]"==o.call(a.opera),
l= ! !b.attachEvent && !l,
u=r ? "object" : l ? "script" : "img",
v=l ? "script" : u,
w=Array.isArray || function(a) {
return "[object Array]"==o.call(a)
}
,
x=[],
y= {}
,
z= {
timeout: function(a, b) {
return b.length && (a.timeout=b[0]),
a
}
}
,
A,
B;
B=function(a) {
function b(a) {
var a=a.split("!"),
b=x.length,
c=a.pop(),
d=a.length,
c= {
url: c,
origUrl: c,
prefixes: a
}
,
e,
f,
g;
for (f=0; f < d; f++) g=a[f].split("="),
(e=z[g.shift()]) && (c=e(c, g));
for (f=0; f < b; f++) c=x[f](c);
return c
}
function g(a, e, f, g, h) {
var i=b(a),
j=i.autoCallback;
i.url.split(".").pop().split("?").shift(),
i.bypass || (e && (e=d(e) ? e : e[a] || e[g] || e[a.split("/").pop().split("?")[0]]), i.instead ? i.instead(a, e, f, g, h) : (y[i.url] ? i.noexec= !0 : y[i.url]=1, f.load(i.url, i.forceCSS || !i.forceJS && "css"==i.url.split(".").pop().split("?").shift() ? "c" : c, i.noexec, i.attrs, i.timeout), (d(e) || d(j)) && f.load(function() {
k(), e && e(i.origUrl, h, g), j && j(i.origUrl, h, g), y[i.url]=2
})))
}
function h(a, b) {
function c(a, c) {
if (a) {
if (e(a)) c || (j=function() {
var a=[].slice.call(arguments);
k.apply(this, a), l()
}),
g(a, j, b, 0, h);
else if (Object(a)===a) for (n in m=function() {
var b=0,
c;
for (c in a) a.hasOwnProperty(c) && b++;
return b
}
(), a) a.hasOwnProperty(n) && ( !c && !--m && (d(j) ? j=function() {
var a=[].slice.call(arguments);
k.apply(this, a), l()
}
: j[n]=function(a) {
return function() {
var b=[].slice.call(arguments);
a && a.apply(this, b), l()
}
}
(k[n])), g(a[n], j, b, n, h))
}
else !c && l()
}
var h= ! !a.test,
i=a.load || a.both,
j=a.callback || f,
k=j,
l=a.complete || f,
m,
n;
c(h ? a.yep : a.nope, ! !i),
i && c(i)
}
var i,
j,
l=this.yepnope.loader;
if (e(a)) g(a, 0, l, 0);
else if (w(a)) for (i=0; i < a.length; i++) j=a[i],
e(j) ? g(j, 0, l, 0) : w(j) ? B(j) : Object(j)===j && h(j, l);
else Object(a)===a && h(a, l)
}
,
B.addPrefix=function(a, b) {
z[a]=b
}
,
B.addFilter=function(a) {
x.push(a)
}
,
B.errorTimeout=1e4,
null==b.readyState && b.addEventListener && (b.readyState="loading", b.addEventListener("DOMContentLoaded", A=function() {
b.removeEventListener("DOMContentLoaded", A, 0), b.readyState="complete"
}
, 0)),
a.yepnope=k(),
a.yepnope.executeStack=h,
a.yepnope.injectJs=function(a, c, d, e, i, j) {
var k=b.createElement("script"),
l,
o,
e=e || B.errorTimeout;
k.src=a;
for (o in d) k.setAttribute(o, d[o]);
c=j ? h : c || f,
k.onreadystatechange=k.onload=function() {
!l && g(k.readyState) && (l=1, c(), k.onload=k.onreadystatechange=null)
}
,
m(function() {
l || (l=1, c(1))
}
, e),
i ? k.onload() : n.parentNode.insertBefore(k, n)
}
,
a.yepnope.injectCss=function(a, c, d, e, g, i) {
var e=b.createElement("link"),
j,
c=i ? h: c || f;
e.href=a,
e.rel="stylesheet",
e.type="text/css";
for (j in d) e.setAttribute(j, d[j]);
g || (n.parentNode.insertBefore(e, n), m(c, 0))
}
}
(this, document),
Modernizr.load=function() {
yepnope.apply(window, [].slice.call(arguments, 0))
};
Happy coding!