//tiny replacement for jQuery - adapted version of ki.js
!function (b, c, d, e, f) {
f = b['add' + e]
function i(a, d, i) {
for(d = (a && a.nodeType ? [a] : '' + a === a ? b.querySelectorAll(a) : c), i = d.length; i--; c.unshift.call(this, d[i]));
}
$ = function (a) {
return /^f/.test(typeof a) ? /in/.test(b.readyState) ? setTimeout(function() { $(a); }, 9) : a() : new i(a);
};
$[d] = i[d] = {
on: function (a, b) {
return this.each(function (c) {
f ? c['add' + e](a, b, false) : c.attachEvent('on' + a, b)
})
},
off: function (a, b) {
return this.each(function (c) {
f ? c['remove' + e](a, b) : c.detachEvent('on' + a, b)
})
},
each: function (a, b) {
for (var c = this, d = 0, e = c.length; d < e; ++d) {
a.call(b || c[d], c[d], d, c)
}
return c
},
splice: c.splice
}
}(document, [], 'prototype', 'EventListener');
$.each = function(arr, callback) {
if(toString.call(arr) === '[object Array]'){
var i = 0, l = arr.length;
for(; i < l; ++i) {
callback.call(arr[i], i, arr[i]);
}
} else {
for (i in arr)
callback.call(arr[i], i, arr[i]);
}
return arr;
};
//extended to include "attr"
$.prototype.attr = function(a, b) {
return b === []._ ? this[0].getAttribute(a) : this.each(function(c) {
c.setAttribute(a, b);
});
};
//extended to include "removeAttr"
$.prototype.removeAttr = function(a) {
return this.each(function(b) {
b.removeAttribute(a);
});
};
//extend to include "parent"
$.prototype.parent = function() {
return (this.length < 2) ? $(this[0].parentNode): [];
};
//custom function to wrap an element in another
$.prototype.wrap = function(a) {
return this.each(function(b) {
var c = document.createElement(a)
b.parentNode.insertBefore(c, b);
c.appendChild(b);
});
};
//quick way of exposing everything like 'addClass', 'removeClass' etc. without having to define each one indivdually
var props = ['add', 'remove', 'toggle', 'has'],
maps = ['add', 'remove', 'toggle', 'contains'];
props.forEach(function(prop, index) {
$.prototype[prop + 'Class'] = function(a) {
return this.each(function(b) {
if(a){
b.classList[maps[index]](a);
}
});
};
});
//extend to include "after"
$.prototype.after = function(a) {
return this.each(function(b) {
b.insertAdjacentHTML('afterend', a);
});
};
//Below is the actual function, all of the above is just a simple replacement for jQuery.
//Should work with just jQuery but you would have to check.
$("img").each(function(){
$(this).wrap("div"); //create a div around an image
var title = $(this).attr("title"); //grab the title
var wrapper = $(this).parent(); //grab the div we just created
wrapper.attr("data-title", title); //set the data-title that we use in the CSS on the wrapper
wrapper.addClass("image"); //add the class that we use for CSS
wrapper.attr("tabindex", "0"); //make the div focusable with tabindex="0"
$(this).after('<span class="visually-hidden">, Title ' + title + '</span>'); //add a span with the title in that is accessible to screen readers - note the use of a comma before the 'Title' part as this makes it more natural (as we are 'hacking' an experience similar to that of a screen reader reading an actual title.)
$(this).removeAttr('title'); //remove the actual title, otherwise some screen readers will announce the title twice.
});
.image{
display:block;
overflow:hidden;
}
/*need relative position in order to absolutely position the overlay*/
.image {
position:relative;
width:200px;
height:200px;
margin: 10px;
}
.image img {
width:100%;
vertical-align:top;
}
/*add a transition*/
.image:after,
.image:before {
position:absolute;
opacity:0;
transition: all 0.5s;
}
/*remove the transition for people who have reduced motion as a preference*/
@media (prefers-reduced-motion: reduce) {
.image:after,
.image:before {
transition: none;
}
}
/*create an overlay*/
.image:after {
content:'';
width:100%;
height:100%;
top:0;
left:0;
background:rgba(0,0,0,0.4);
}
/*create a box at the bottom that contains the 'data-title' text that was added to the div we created*/
.image:before {
content: attr(data-title);
font-size: 1.25rem;
line-height: 1.9rem;
width:100%;
color:#fff;
z-index:1;
bottom:0;
padding:4px 10px;
text-align:left;
background:black;
box-sizing:border-box;
-moz-box-sizing:border-box;
}
/*make the overlay visible on hover and focus*/
.image:hover::after,
.image:hover::before,
.image:focus::after,
.image:focus::before{
opacity:1;
}
/*put a border around on focus*/
.image:focus{
outline: 2px solid #333;
outline-offset: 4px;
}
/*visually hidden class used to make text screen reader accessible but not visible*/
.visually-hidden {
position: absolute !important;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
clip: rect(1px, 1px, 1px, 1px);
white-space: nowrap; /* added line */
}
<img src="https://via.placeholder.com/150" title="First Image" alt="First Image"/>
<img src="https://via.placeholder.com/150" title="Second Image, A Longer Text Test for a more complex title, adjust to your needs" alt="Second Image"/>