picture element srcset responsive image rollovers - javascript

I am trying to figure out how to apply an image rollover effect to the picture element in a responsive website.
The question is can an image rollover be applied the scrset attribute in the picture tag?
Working example img tag with javascript rollover effect
<img src="media/images/feature-films/tmbs/zen-zero.jpg"
onmouseover="this.src='media/images/feature-films/tmbs/zen-zero-ro.jpg'"
onmouseout="this.src='media/images/feature-films/tmbs/zen-zero.jpg'"
alt=""/>
Not working example of picture element with javascript rollover effect
<picture>
<source srcset="media/images/feature-films/tmbs/zen-zero-large.jpg"
onmouseover="this.src='media/images/feature-films/tmbs/zen-zero-large-ro.jpg'"
onmouseout="this.src='media/images/feature-films/tmbs/zen-zero.jpg'"
media="(min-width: 880px)">
<source srcset="media/images/feature-films/tmbs/zen-zero-small.jpg" media="(max-width: 478px)">
<source srcset="media/images/feature-films/tmbs/zen-zero-medium.jpg">
<!-- fall back -->
<img srcset="media/images/feature-films/tmbs/zen-zero-medium.jpg" alt="">
</picture>
Does anyone have any suggestions hoe to achieve a rollover effect on the picture tag using the srcset?
The web page has about 12 responsive images that need a rollover effect.

Changing src/srcset is not optimal, even for a single img, since it can abort the download of the image if you hover it or leave it before the download is complete.
I think I would do one of these:
Clone the picture with cloneNode(true) and rewrite the URLs of the clone. When the original picture element receives a mouseover event, replace it with the clone. When the clone receives a mouseout event, replace it with the original.
Duplicate the picture in the markup, with the second one representing the hovered image. The second picture has a hidden attribute set. Toggle the hidden attribute on both elements as appropriate.
In the future, it should be possible to toggle the image with CSS using something like img:hover { content:image-set(...); }.

HTML:
<picture id="zen">
<source class="large" srcset="media/images/feature-films/tmbs/zen-zero-large.jpg" media="(min-width: 880px)">
<source srcset="media/images/feature-films/tmbs/zen-zero-small.jpg" media="(max-width: 478px)">
<source srcset="media/images/feature-films/tmbs/zen-zero-medium.jpg">
<!-- fall back -->
<img srcset="media/images/feature-films/tmbs/zen-zero-medium.jpg" alt="">
</picture>
jQuery:
$(document).ready(function() {
$('#zen').on('mouseover', function () {
$(this).find('.large').attr('srcset', 'media/images/feature-films/tmbs/zen-zero-large-ro.jpg');
console.log('mouse over');
})
$('#zen').on('mouseout', function () {
$(this).find('.large').attr('srcset', 'media/images/feature-films/tmbs/zen-zero-large.jpg');
console.log('mouse out');
})
});

Related

iphone video image on load not displaying

I display a video on my web page with the following:
<div class="gl-bot-left">
<video controls="">
<source src="https://www.sustainablewestonma.org/wp-content/uploads/2019/09/video.fixgasleaks.mp4"
type="video/mp4">Your browserdoes not support the video tag.
</video>
</div>
This works fine on the desktop. The video loads and you can see a image of the start. However, on the iphone I get an image of the play button instead of an actual image. When I press it the video starts. Is there a way we can display a image for the video when it's first loaded?
The HTML <video> object has a specific attribute for your use-case: poster. It specifies an image to be shown while playback of your video didn't start yet.
<div class="gl-bot-left">
<video controls="" poster="https://picsum.photos/id/1/200/300">
<source src="https://www.sustainablewestonma.org/wp-content/uploads/2019/09/video.fixgasleaks.mp4"
type="video/mp4">Your browserdoes not support the video tag.
</video>
</div>
Edit
I really can't tell you why it ain't working on your iOs device but I can offer a nifty workaround.
add a HTML <image> with your desired placeholder image right before the <video> tag and group those two inside a <div>.
make the image invisible by setting it's visibility to hidden
create an empty 64x64x (or smaller) empty transparent .png and use it as the poster image for the video element. This will make sure it doesn't display the video's first frame.
finally listen for the loadedMetaData event and inside it's callback function resize the image to the dimensions of the video and set the image's opacity to visible
var video = document.querySelector('video');
function metaDataLoaded() {
var image = document.querySelector('img');
image.width = video.videoWidth;
image.height = video.videoHeight;
image.style.visibility = "visible";
}
.container img {
position: absolute;
visibility: hidden;
}
video {
position: absolute;
}
<div class="gl-bot-left">
<div class="container">
<img src="https://picsum.photos/id/2/300/200">
<video controls="" poster="https://i.imgur.com/A9WPATe.png" onloadedmetadata="metaDataLoaded()">
<source src="https://www.sustainablewestonma.org/wp-content/uploads/2019/09/video.fixgasleaks.mp4"
type="video/mp4">Your browserdoes not support the video tag.
</video>
</div>
</div>

How to do lazy loading image with srcset?

I'm using slick.js to build a carousel. However, even though I change the attribute from src to data-lazy the images still get loaded before I scroll to that image. I suspect that it's because I have srcset tag in in my image. My question is how to prevent browser to load responsive image or how to do lazy-loading for responsive images properly.
This is the sample of my img tag
<img data-lazy="better_me.jpg" srcset="better_me.jpg 400w, better_me.jpg 200w" class="avatar photo avatar-200" alt="better_me" width="200" height="200" sizes="(min-device-resolution: 1.6) 400px, 200px">
lazySizes is just working fine. You need to alter your markup into something like this however.
<img data-src="better_me.jpg" data-srcset="better_me2.jpg 400w, better_me.jpg 200w" class="avatar photo avatar-200 lazyload" data-sizes="auto" alt="better_me" width="200" height="200" />
Note srcset is changed to data-srcset and data-lazy is changed to data-src. Additionally you must add the class lazyload.
Your sizes attribute didn't made too much sense. Maybe you want to use x descriptors instead? Or simply use sizes="200px"? I don't know. I simply switched it to data-sizes="auto", so it gets automatically calculated for you. (But in that case the image dimension has to be computable before the image is loaded.)
lazySizes indeed loads images before they get in view. This is a big improvement for user experience. A user, who scrolls something into view doesn't want to wait then. A lazyloader that starts downloading an image after it is already in view disrupts the user experience.
One nice thing about lazySizes is that this lazy loader checks whether the browser is currently heavily downloading and decides on this fact, whether it only downloads in view images or to also preload near view images.
But if you don't want this you can control this by setting the lazySizes' expand and expFactor options.
I recommend responsivelyLazy. The implementation is SEO-friendly and does not mess your HTML code. Here is a snippet:
<div class="responsively-lazy" style="padding-bottom:68.44%;">
<img
alt=""
src="images/2500.jpg"
srcset="data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
data-srcset="images/400.jpg 400w, images/600.jpg 600w, images/800.jpg 800w, images/1000.jpg 1000w, images/1500.jpg 1500w, images/2000.jpg 2000w"
/>
As you can see the value in the src attribute is not modified.
Read more at http://ivopetkov.com/b/lazy-load-responsive-images/
Usually, to implement lazy loading in HTML, instead of src or srcset attributes, we use data-src or data-srcset so that browser does not load images during speculative parsing. Later on, when Javascript is executed, and the user has scrolled near the image element, we load the actual image and update the src or srcset attribute’s value.
Two very popular lazy loading libraries lazysizes and vanilla-lazyload support responsive images out of the box.
Here are a few examples of using lazysizes.
Lazy loading responsive images in srcset and sizes
<img
sizes="(min-width: 1000px) 930px, 90vw"
data-srcset="small.jpg 500w,
medium.jpg 640w,
big.jpg 1024w"
data-src="medium.jpg"
class="lazyload" />
Using low quality placeholder in lazy loading
<img
src="low-quaity-placeholder.jpg"
sizes="(min-width: 1000px) 930px, 90vw"
data-srcset="small.jpg 500w,
medium.jpg 640w,
big.jpg 1024w"
data-src="medium.jpg"
class="lazyload" />
Lazy loading images in picture element
<picture>
<source
data-srcset="500.jpg"
media="(max-width: 500px)" />
<source
data-srcset="1024.jpg"
media="(max-width: 1024px)" />
<source
data-srcset="1200.jpg" />
<img src="fallback-image.jpg"
data-src="1024.jpg"
class="lazyload"
alt="image with artdirection" />
</picture>
You can learn more about responsive images from this guide - https://imagekit.io/responsive-images

Change data-src to src via jquery

Im using a flexslider that has audio files for each slide, but I don't want to load countless audio files right away on the page. So im trying to get the data-src to become the src after each slide
the slides are currently as follows:
<div class="flexslider carousel">
<ul class="slides">
<li>
<img src="http://www.quinnmedical.com/skin/frontend/gigasavvy/quinn/ppt/Slide01.jpg" />
<audio id="demo" controls>
<source src="/skin/frontend/gigasavvy/quinn/audio/Slide1.mp3" type="audio/mpeg" />
</audio>
</li>
<li>
<img src="http://www.quinnmedical.com/skin/frontend/gigasavvy/quinn/ppt/Slide03.jpg" />
<audio id="demo" controls>
<source data-src="/skin/frontend/gigasavvy/quinn/audio/Slide3.mp3" src="" type="audio/mpeg" />
</audio>
</li>
</ul>
</div>
In the after function i want to change data-src to src. Any help would be greatly appreciated as how to go from data-src to src
Renaming an attribute is not be possible. You can add new attribute and remove the old one.
Suppose there is a click event as in the following example:
$('#demo').on("click", "img", function () {
var t = this;
var source = $(t).children("source");
$source.attr({
src: $t.attr('data-src')
}).removeAttr('data-src');
}
Please modify the event according to your requirements.
Try this:
$('source').attr("src", $(this).data('src'));
$('source').removeAttr('data-src');
This should move the url from data-src to src, and then remove the data-src attribute.
Inside the after function get the currently visible slide and then get the auto on it and it's source. Next check to see if it already has a src attribute. If not then set it to it's own .data('src'). Add this into the flexslider object.
after: function(){
var $currentAudio = $('.flex-active-slide audio source');
if(!$currentAudio.attr('src')){
$currentAudio.attr('src', $currentAudio.data('src'));
}
}

Lazy Loading HTML5 picture element

I have been searching (unsuccessfully) for a reliable method to lazy load images while using the HTML5 spec for <picture>. Most solutions/plugins out there currently rely on using data- attributes. I could be wrong, but it doesn't seem this method will work in conjunction w/ <picture>.
I'm really just looking to be pointed in the right direction. If anyone has a solution that they're currently using, I'd love to see. Thanks!
Here is standard markup per the HTML5 spec:
<picture width="500" height="500">
<source media="(min-width: 45em)" src="large.jpg">
<source media="(min-width: 18em)" src="med.jpg">
<source src="small.jpg">
<img src="small.jpg" alt="">
</picture>
It's February 2020 now and I'm pleased to report that Google Chrome, Microsoft Edge (the Chromium-based Edge), and Mozilla Firefox all support the new loading="lazy" attribute. The only modern browser hold-out is Apple's Safari (both iOS Safari and macOS Safari) but they've recently finished adding it to Safari's codebase, so I expect it will be released sometime this year.
The loading="lazy" attribute is only for the <img /> element (and not <picture>) but remember that the <picture> element does not represent the actual replaced-content, the <img /> element does (i.e. the image that users see is always rendered by the <img /> element, the <picture> element just means that the browser can change the <img src="" /> attribute. From the HTML5 spec as of February 2020 (emphasis mine):
The picture element is somewhat different from the similar-looking video and audio elements. While all of them contain source elements, the source element's src attribute has no meaning when the element is nested within a picture element, and the resource selection algorithm is different. Also, the picture element itself does not display anything; it merely provides a context for its contained img element that enables it to choose from multiple URLs.
So doing this should just work:
<picture>
<source media="(min-width: 45em)" srcset="large.jpg" />
<source media="(min-width: 18em)" srcset="med.jpg" />
<source src="small.jpg" />
<img src="small.jpg" alt="Photo of a turboencabulator" loading="lazy" />
</picture>
Note that the <picture> element does not have any width or height attribute of its own; instead the width and height attributes should be applied to the child <source> and <img> elements:
4.8.17 Dimension attributes
The width and height attributes on img, iframe, embed, object, video, source when the parent is a picture element [...] may be specified to give the dimensions of the visual content of the element (the width and height respectively, relative to the nominal direction of the output medium), in CSS pixels.
[...]
The two attributes must be omitted if the resource in question does not have both an intrinsic width and an intrinsic height.
So if you want all <source> images to be rendered as 500px by 500px then apply the size to the <img> element only (and don't forget the alt="" text for vision-impaired users, it's even a legal requirement in many cases):
<picture>
<source media="(min-width: 45em)" srcset="large.jpg" />
<source media="(min-width: 18em)" srcset="med.jpg" />
<source src="small.jpg" />
<img src="small.jpg" alt="Photo of a turboencabulator" loading="lazy" width="500" height="500" />
</picture>
For anyone still interested...
After revisiting this issue, I came across a fairly new script called, Lazysizes. It's actually quite versatile, but more importantly it allows me to do lazy loading of images while utilizing the HTML5 markup as described in the OP.
Much thanks to the creator of this script, #aFarkas.
Working example of lazy loading images using the picture element and intersection observer tested in Chrome and Firefox. Safari doesn't support intersection observer so the images are loaded immediately, and IE11 doesn't support the element so we fallback to the default img
The media queries in the media attr are arbitrary and can be set to suit.
The width threshold set is 960px - try a reload above and below this width to see either the medium(-m) or large(-l) variation of the image being downloaded when the image is scrolled into the viewport.
Codepen
<!-- Load images above the fold normally -->
<picture>
<source srcset="img/city-m.jpg" media="(max-width: 960px)">
<source srcset="img/city-l.jpg" media="(min-width: 961px)">
<img class="fade-in" src="img/city-l.jpg" alt="city"/>
</picture>
<picture>
<source srcset="img/forest-m.jpg" media="(max-width: 960px)">
<source srcset="img/forest-l.jpg" media="(min-width: 961px)">
<img class="fade-in" src="img/forest-l.jpg" alt="forest"/>
</picture>
<!-- Lazy load images below the fold -->
<picture class="lazy">
<source data-srcset="img/river-m.jpg" media="(max-width: 960px)">
<source data-srcset="img/river-l.jpg" media="(min-width: 961px)">
<img data-srcset="img/river-l.jpg" alt="river"/>
</picture>
<picture class="lazy">
<source data-srcset="img/desert-m.jpg" media="(max-width: 960px)">
<source data-srcset="img/desert-l.jpg" media="(min-width: 961px)">
<img data-srcset="img/desert-l.jpg" alt="desert"/>
</picture>
and the JS:
document.addEventListener("DOMContentLoaded", function(event) {
var lazyImages =[].slice.call(
document.querySelectorAll(".lazy > source")
)
if ("IntersectionObserver" in window) {
let lazyImageObserver =
new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.srcset = lazyImage.dataset.srcset;
lazyImage.nextElementSibling.srcset = lazyImage.dataset.srcset;
lazyImage.nextElementSibling.classList.add('fade-in');
lazyImage.parentElement.classList.remove("lazy");
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
} else {
// Not supported, load all images immediately
lazyImages.forEach(function(image){
image.nextElementSibling.src = image.nextElementSibling.dataset.srcset;
});
}
});
One last thought is that if you change the screen width back and forth, the image files are repeatedly downloaded again. If I could tie the above method in to a cache check then this would be golden...
On web.dev Google advices that picture tags can be loaded lazy.
https://web.dev/browser-level-image-lazy-loading/
Images that are defined using the element can also be lazy-loaded:
<picture>
<source media="(min-width: 800px)" srcset="large.jpg 1x, larger.jpg 2x">
<img src="photo.jpg" loading="lazy">
</picture>
Although a browser will decide which image to load from any of the elements, the loading attribute only needs to be included to the fallback element.

Dynamically control HTML5 audio with JavaScript

I've got a gallery of sorts with 10 or so thumbnails that each represent one song. To control the playback of each, I've set a play button to fades in via jQuery. After some digging around Apple's Dev Center I found some native JavaScript to control audio. It works beautifully, but is written for control of one object at a time. What I'd like to do is rewrite it as one function that dynamically controls the playback/pause of the thumbnail you're selecting.
Below is the code that I found.. works, but it'd be a lot of unnecessary code to write it 10 times.
Thanks for your help and advice, always!
HTML:
<div class="thumbnail" id="paparazzixxx">
<a href="javascript:playPause();">
<img id="play" src="../images/icons/35.png" />
</a>
<audio id="paparazzi">
<source src="../audio/fernando_garibay_paparazzisnlmix.ogg" type="audio/ogg" />
<source src="../audio/fernando_garibay_paparazzisnlmix.mp3" type="audio/mpeg" />
Your browser does not support HTML5 audio.
</audio>
</div>
JavaScript:
<script type="text/javascript">
function playPause() {
var song = document.getElementsByTagName('audio')[0];
if (song.paused)
song.play();
else
song.pause();
}
</script>
jQuery is awesome for this sort of thing. It gives you the ability to easily manipulate elements based on their relationship to other elements in the DOM tree. In your example you want to be able to make the <a> elements only affect the <audio> elements that are right next to them when clicked.
The problem with your current Javascript code is that it is actually just grabbing only the first audio element on the entire page.
Here's how you can change your code to support an unlimited number of <a> & <audio> pairs.
Add a class to the <a> tag ('playback' in my example)
Replace the href attribute with a '#'
Then use jQuery to attach a handler to the click event for elements with that class.
HTML
<div class="thumbnail" id="paparazzixxx">
<a class="playback" href="#">
<img id="play" src="../images/icons/35.png" />
</a>
<audio id="paparazzi">
<source src="../audio/fernando_garibay_paparazzisnlmix.ogg" type="audio/ogg" />
<source src="../audio/fernando_garibay_paparazzisnlmix.mp3" type="audio/mpeg" />
Your browser does not support HTML5 audio.
</audio>
</div>
Javascript
<script type="text/javascript">
$(function() {
$(".playback").click(function(e) {
e.preventDefault();
// This next line will get the audio element
// that is adjacent to the link that was clicked.
var song = $(this).next('audio').get(0);
if (song.paused)
song.play();
else
song.pause();
});
});
</script>

Categories