Tyler Bramer
Tyler Bramer

Reputation: 275

AJAX loaded images not displaying properly in Safari

So I'm using AJAX to load the content from each page and inject it into the current page. Everything is working great on Chrome, Firefox, Internet Explorer (as much as it can haha), and the content loads fine on Safari, aside from two curious parts.

  1. Images loaded via AJAX are getting a height of 0
  2. Images loaded via AJAX are losing their object-fit property.

Issue 1: Image height 0

I'll be using this page for reference: http://insight.insightcreative.info/about

If you open the page up in Safari everything should be displaying great, but now if you click the About link to reload the page using AJAX loading, the images on the page will break.

What I'm finding is happening is that the image heights are getting set to 0 when they are loaded in by AJAX.

Here is an example of an image on the page that gets broken after being loaded by AJAX

<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 is it that the page will render properly if it is an initially loaded page (or a hard refresh), but when the content is loaded by AJAX it doesn't apply the height properly?


Issue 2: Object-fit not working

I'll be using this page for reference: http://insight.insightcreative.info/work

If you open the page in Safari, everything should be displaying great, but now if you click the Work link to reload the page using AJAX loading, the images on the page will not display with object-fit.

If you inspect the page, you'll find all the same CSS settings are being applied to the images, including the object-fit property, but for some reason they no longer are respecting their properties. Instead the images are stretching to fill the container.

Why is it that the page will render properly if it is an initially loaded page (or a hard refresh), but when the content is loaded by AJAX it doesn't adhere to the object-fit property anymore?


Both of these issues only seem to be occuring in Safari, and I'm guessing it has something to do with the way Safari handles the image properties when loaded through AJAX.

Is there a way I could try force Safari to properly re-apply these settings after the page is loaded through AJAX? Or is there a coding god out there that know's how to handle these issues with Safari?


EDIT 1:

I wrote a function to change the CSS of my page after the AJAX loaded so that it would rewrite the properties for my images. I intentionally change the object-fit to fill then back to cover in an attempt 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 confirmed this code works by intentionally changing some of these settings so that they would drastically reflect in the browser. I found that even changing the settings after the page has loaded all content that I still cannot seem to fix the issue (in regards to styling).

However, this did lead me to try something else. By removing the srcset attribute completely from my image, it will then render properly even with AJAX load. So essentially, for some reason, by using srcset it only allows the page to display properly if it is hard loaded, but won't display properly if loaded by AJAX. I'm not sure if this is in correlation with the fact that Safari also will only load the first image it sees in srcset and ignores the rest, but I think the issues lies in how Safari is handling srcset.

SOLUTION: Barba.js

Without going into crazy detail I managed to fix the issue. Before I was using my own written script for loading in the content of each page. After testing Barba.js I found that the images did not have any issues on Safari. So I loaded in Barba.js and then rewrote all of my JS so that it functioned correctly with that PJAX library. So somehow the way I was loading the pages before was causing this issue, but only with Safari.

Below is a snippet of the code I was using to load 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;
}
});

Upvotes: 3

Views: 2740

Answers (3)

Toby T
Toby T

Reputation: 81

I was also experiencing the Safari bug outlined in Issue 1 but instead of rebuilding my app on Barba.js chose to rewrite the safariResize function using the imagesLoaded script. Here is my function in case someone else 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;");
        }
    });
};

Upvotes: 0

Tyler Bramer
Tyler Bramer

Reputation: 275

So I managed to solve the bigger of the two issues, which was the images not displaying because of 0 height. For some reason, when loading an image with srcset through AJAX Safari was removing the auto height and making it 0px.

I wrote a function that waits till all the images are loaded (because otherwise naturalHeight was returning 0) then it changes the height to be a height that retains the same aspect ratio of the original image. I also made it so that it only targets images that don't have object-fit: cover applied to them as these were the images that were giving me problems, otherwise it would have messed up the object-fit images.

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 my AJAX load inside an if statement to make sure it only fires on 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'll be able to solve the object-fit issue, which only happens on the desktop version of Safari (works fine on iPad). Let me know if you find an easier way to solve this problem, as this was quite a process for me to fix.

Upvotes: 0

Farrukh Subhani
Farrukh Subhani

Reputation: 2038

Check following on your image css

  • display: usually set to block
  • position: might need to set to fixed if not loading initially
  • max-width: check if this is changed
  • max-height: check if this is changed

You might be assuming that css rules applied to components stay as they were on initial load but you might have to reapply some of these after ajax has finished loading specially if you had some javascript running to manage these rules. Some browsers might be able to apply them. I need to find that post online but for now if you can look into above and its not solving your issue then let me know here. To isolate img issue you can create a test page with single image and share a link and remove as much of other items from that page as possible. Maybe just basic header and footer to isolate other issues.

Upvotes: 0

Related Questions