Travis Hardaway
Travis Hardaway

Reputation: 61

Background image flickering with user interaction on iOS [Ionic 5]

I'm trying to get a background image to work on a multi-paged Ionic app that I'm updating from Ionic 3 to 5. I was getting the flickering background image problem on iOS for any page other than the first page loaded. I tried implementing this solution: How to put image in both <ion-header> and <ion-content> in Ionic and it works in the web browser but when I run it in the simulator in Xcode, ionViewWillEnter does not fire in iOS but will fire in the browser (live reload).

This is the old code in CSS that produces the flickering in iOS:

ion-content {
    --background: url(/assets/imgs/bg/piano.jpg) no-repeat center/ cover fixed;
    }

The workaround looks like this:

import { DomController } from '@ionic/angular';

...

constructor(public navCtrl: NavController, private domCtrl: DomController) {
  }

...

private initializeBackground(): void {
    try {
      console.log ('initializing background');
      const content = document.querySelector('#level');
      const innerScroll = content.shadowRoot.querySelector('.inner-scroll');
      this.domCtrl.write(() => {
        innerScroll.setAttribute(
          'style',
          'background: url("/assets/imgs/bg/piano.jpg") no-repeat center center / cover'
        );
        });
        console.log('background initialized'); } catch (e) {}
        console.log('background not initialized');
  }

...

ionViewWillEnter() {
    console.log('After Init?');
    this.initializeBackground();   
  }

When I run this, ionViewWillEnter fires when running it in the web browser but when I run it in the simulator, it does not. I've been reading that it will only trigger once and has problems when triggering from a side menu https://fantashit.com/ionic-4-ionviewwillenter-only-triggers-once/ But I'm not sure this is the problem I've got because it makes no mention of this working in the browser, but not in iOS.

All I want is to set different background images on different pages that work on all platforms. Surely there is a better way? Any help would be greatly appreciated.

Upvotes: 4

Views: 1760

Answers (3)

Cristian R.
Cristian R.

Reputation: 1

I'm late to the party but some might still find the answer useful.

If you convert the image to Base64 and use that in the CSS, the flickering doesn't occur.

--background: url("data:image/svg+xml;base64,YOUR_BASE64_IMAGE")

I usually use this website to convert SVG to Base64 converter and select as Output: (CSS Background Image --background-image:url())

Upvotes: -1

rushjs
rushjs

Reputation: 114

Just to be a bit more concise for others. Here is a working solution for having different images for both Web and mobile views with no flash.

 import { DomController } from "@ionic/angular";

...

 constructor(private domCtrl: DomController
  ) {}

...

 private initializeBackgroundWeb(): void {
try {
  console.log("initializing background");
  const content = document.querySelector(".background");
  const innerScroll = content.shadowRoot.querySelector(".inner-scroll");
  this.domCtrl.write(() => {
    innerScroll.setAttribute(
      "style",
      'background: url("../../assets/images/back7.jpg") center center / cover no-repeat'
    );
  });

  console.log("background initialized");
} catch (e) {}
console.log("background not initialized");
  }


 private initializeBackgroundMobile(): void {
try {
  console.log("initializing background");
  const content = document.querySelector(".background");
  const innerScroll = content.shadowRoot.querySelector(".inner-scroll");
  this.domCtrl.write(() => {
    innerScroll.setAttribute(
      "style",
      'background: url("../../assets/images/back18.jpg") center center / cover no-repeat'
    );
  });

  console.log("background initialized");
} catch (e) {}
console.log("background not initialized");

}

and check media query in ionViewWillEnter like so.

 ionViewWillEnter() {
   const x = window.matchMedia("(min-width: 850px)");
   if (x.matches) {
    // If media query matches
   this.initializeBackgroundWeb();
  } else {
  this.initializeBackgroundMobile();
  }
  }

Then you can additionally create a div just inside your ion-content and set height and width like the above answer.

 .splash {
  height: 100%;
  width: 100%;
  } 
    

Upvotes: 1

Travis Hardaway
Travis Hardaway

Reputation: 61

After giving up on the ionViewWillEnter feature/bug problem I came up with a workaround. Instead of using .ion-content {--background...} I created a wrapper in the html

<ion-content>
  <div class = "splash"></div>

and set the css as follows:

.splash {
background: url(/assets/imgs/bg/piano.jpg) no-repeat center/ cover fixed;
width: 100%;
height: 100%;

} And then moved the actual content up 100% to go over the background:

ion-grid{
    margin-top: -100vh;
    height: 100%;
    width:100%;
}

This solved the problem for me.

Upvotes: 2

Related Questions