Downloaded AJAX images not displaying properly in Safari
So, I am using AJAX to load content from each page and inject it into the current page. Everything works fine in Chrome, Firefox, Internet Explorer (as far as possible, haha) and the content is loaded in Safari except for two curious parts.
- Images loaded via AJAX get height 0
- Images loaded via AJAX lose their object property.
Problem 1: Image Height 0
I will use this page for reference: http://insight.insightcreative.info/about
If you open the page in Safari everything should display great, but now if you click the "ON" link to reload the page with an AJAX load, the images on the page break.
What I find is happening is that the height of the images is set to 0 when they are AJAX loaded.
Here is an example of an image on a page that will break after the AJAX load
<img data-aos-anchor-placement="bottom-bottom" data-aos-offset="100" src="/img/agency/clients/affinity-medical-group.jpg" alt="Affinity"
srcset="
/img/agency/clients/affinity-medical-group-2400.jpg 2400w,
/img/agency/clients/affinity-medical-group-1800.jpg 1800w,
/img/agency/clients/affinity-medical-group-1200.jpg 1200w,
/img/agency/clients/affinity-medical-group-900.jpg 900w,
/img/agency/clients/affinity-medical-group-600.jpg 600w,
/img/agency/clients/affinity-medical-group-400.jpg 400w" />
Why will the page render correctly if it is the originally loaded page (or hard refresh), but when the content is loaded by AJAX it does not apply the height properly?
Problem 2: Working with objects doesn't work
I will use this page for reference: http://insight.insightcreative.info/work
If you open the page in Safari, everything should display great, but now if you click the Work link to reload the page with an AJAX load, the images on the page will not be rendered object-aware.
If you check the page, you can see that all the same CSS settings are applied to the images, including the object snap property, but for some reason they no longer respect their properties. Instead, the images stretch to fill the container.
Why will the page render correctly if it is the originally loaded page (or hard refresh), but when the content is loaded by AJAX, it is no longer bound to an object oriented property?
Both of these problems seem to only happen in Safari, and I'm guessing it has something to do with how Safari handles image properties when loaded via AJAX.
Is there a way to get Safari to properly reapply these settings after the page has loaded via AJAX? Or is there some rich code out there that knows how to deal with these problems with Safari?
EDIT 1:
I wrote a function to change the CSS of my page after the AJAX load so that it overrides the properties for my images. I intentionally change object-fit
to fill
and then back to cover
, trying to completely reset the style.
function checkImages() {
var images = $('img');
for (var i = 0; i <= images.length; i++){
var result = $(images[i]).css("object-fit");
if (result == 'cover'){
$(images[i]).css("object-fit","fill");
$(images[i]).css("object-fit","cover");
$(images[i]).css("display","block");
$(images[i]).css("position","relative");
$(images[i]).css("max-width","100%");
$(images[i]).css("max-height","100%");
}
}
}
I have confirmed that this code works by intentionally changing some of these settings so that they are sharply reflected in the browser. I found that even changing the settings after the page has loaded all of the content still cannot solve the problem (in terms of styling).
However, this made me try something else. By removing the attributesrcset
completely from my image, it will render correctly even with AJAX loading. Essentially, for some reason, using srcset
, it only allows the page to be rendered if it is hard-loaded, but will not render correctly if it is AJAX loaded. I'm not sure if this has to do with the fact that Safari will also only download the first image it sees in srcset
and ignore the rest, but I think the problems lie in the way Safari handlessrcset
.
SOLUTION: Barba.js
Without going into crazy details, I managed to fix this issue. Before I used my own script to load into the content of each page. After testing Barba.js, I found that the images had no problem with Safari. So I loaded into Barba.js and then rewrote all my JS to make it work correctly with this PJAX library. So somehow the way I was loading pages before it was causing this issue, but only with Safari.
Below is the code snippet I used to load the AJAX before
//Function that loads in the new content
var load = function(url) {
//Fadeout leaving page transition
$('#content').velocity("fadeOut", {
visibility: 'visible',
display: 'block',
complete: function() {
//Load new content
$("#content").load(url + " #content");
}
});
};
//Action to perform on link click
$(document).on('click', 'a', function(e) {
//Sets variables to be used for url and page name
var $this = $(this),
url = $this.attr("href"),
title = $this.text();
loading = true;
//Makes entries into browser history
if (url.indexOf(document.domain) > -1 || url.indexOf(':') === -1) {
history.pushState({
url: url + '/',
title: title
}, title, url);
$('#container').mixItUp('destroy');
$('a').on('click.myDisable', function() {
return false;
});
load(url);
if (url === '/') {
document.title = "Insight Creative, Inc.";
} else {
document.title = title + " - Insight Creative, Inc.";
}
return false;
}
});
source to share
Check your css image
- : usually set to block
- position: may need to be set fixed if not loaded initially
- max-width: check if this has changed.
- max-height: check if this has changed.
You can assume that the css rules applied to the components remain the same as on bootstrapping, but you may need to reuse some of them after ajax has finished loading on purpose if you have javascript to manage those rules. Some browsers may use them. I need to find this post on the internet, but for now, if you can look above and not solve your problem, let me know here. To isolate the img issue, you can create a test page with one image and share the link and remove as many other elements from that page as possible. Maybe just a basic header and footer to isolate other concerns.
source to share
Therefore, I was able to solve the larger of the two problems that caused images not to display due to 0 height. For some reason, when loading an image using srcset
via Safari AJAX, the auto-height was removed and was 0px.
I wrote a function that waits until all images are loaded (since it would naturalHeight
return 0 otherwise ), it changes the height to a height that keeps the same aspect ratio of the original image. I also made it so that it only targets the images that weren't being applied to them object-fit: cover
, as those were the images that were causing me problems, otherwise it might mess up the images object-fit
.
function safariResize() {
console.log("Running safariResize");
// This variable starts at 1 because the logo (always on the page) is image 0
var loaded = 1;
$('img').on('load',function(){
loaded++;
images = $('img');
if (loaded == $('img').length){
for (var i = 1; i < images.length; i++){
if ($(images[i]).css("object-fit") != 'cover'){
var naturalH = images[i].naturalHeight;
var naturalW = images[i].naturalWidth;
var ratio = naturalH / naturalW;
var newRatio = (images[i].width / naturalW);
var newH = naturalH * newRatio;
$(images[i]).css("height", newH + "px");
}
}
}
});
}
Then I call this function after the AJAX has loaded inside the if statement to make sure it only fires in Safari
if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
safariResize();
} else if (navigator.userAgent.indexOf('iPad') != -1 && navigator.userAgent.indexOf('Chrome') == -1) {
safariResize();
}
I donβt believe I can solve the object fit problem, which only happens in the desktop version of Safari (works great on iPad). Let me know if you find an easier way to solve this problem as it was quite a complicated process for me.
source to share
I was also experiencing the Safari bug described in issue 1, but instead of rebuilding my app to Barba.js, you decided to rewrite the safariResize function with the imagesLoaded script. Here's my function in case anyone finds it useful:
var safariResize = function() {
// Targetting collapsed images in pjax loading box (safari bug)
var imgLoad = imagesLoaded( $('.site-container > .site-inner img') );
imgLoad.on( 'progress', function( instance, image ) {
if(image.isLoaded && image.img.height == 0){
var naturalH = image.img.naturalHeight,
naturalW = image.img.naturalWidth;
if( image.img.parentElement.clientWidth < naturalW ){
var ratio = naturalH / naturalW;
naturalW = image.img.parentElement.clientWidth;
naturalH = naturalW * ratio;
}
image.img.setAttribute("style","width: "+naturalW+"px; height: "+naturalH+"px;");
}
});
};
source to share