How to stop the flickering scrollbars and still get max screen sized canvas

49 Views Asked by At

I'm trying to get my canvas element to take up the whole width/height of the document body, and have it resize when the body size changes (such as a cell phone going from portrait to landscape).

The canvas resizes as expected, but for some reason causes the scroll bars to "flicker" off and on.

let dimensions = {
  w: document.body.clientWidth,
  h: document.body.clientHeight,
};

const log = console.log.bind(console);
const $ = document.querySelector.bind(document);
let canvas;
let ctx;
let screenSizeObserver;
let initialized = false;

function initialize() {
  if (document.visibilityState === "visible" && initialized === false) {
    initialized = true;

    let c = document.createElement("canvas");
    c.id = "canvas";
    document.body.append(c);

    canvas = $("#canvas");
    ctx = canvas.getContext("2d");

    dimensions.w = document.body.clientWidth;
    dimensions.h = document.body.clientHeight;
    canvas.width = dimensions.w;
    canvas.height = dimensions.h;
  }
}

document.addEventListener("DOMContentLoaded", () => {
  document.addEventListener("visibilitychange", initialize);
  initialize();
});

screenSizeObserver = new ResizeObserver(() => {
  //log(document.body.clientWidth);

  dimensions.w = document.body.clientWidth;
  dimensions.h = document.body.clientHeight;
  canvas.width = dimensions.w;
  canvas.height = dimensions.h;
});

screenSizeObserver.observe(document.body);
html,
body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    background:
        linear-gradient(180deg,
            rgba(0, 191, 254, 1) 10%,
            rgba(252, 252, 252, 1) 100%);
}

canvas {
    box-sizing: border-box;
    position: relative;
    padding: 0;
    margin: 0;
    background: rgba(0, 0, 0, .5);
}

2

There are 2 best solutions below

1
TK421 On BEST ANSWER

Looks like changing the canvas to a Block level element instead of an Inline element will fix the flickering issue. It allows exact setting of the canvas element width/height to the body element width/height, removing the scrollbars entirely and still covering the entire viewable area.

let dimensions = {
  w: document.body.clientWidth,
  h: document.body.clientHeight,
};

const log = console.log.bind(console);
const $ = document.querySelector.bind(document);
let canvas;
let ctx;
let screenSizeObserver;
let initialized = false;

function initialize() {
  if (document.visibilityState === "visible" && initialized === false) {
    initialized = true;

    let c = document.createElement("canvas");
    c.id = "fui_canvas";
    c.style.display = "block";
    // css style display property MUST be set to "block" or it will cause an annoying flickering of the scroll bars off and on;
    // also, the width/height will be 17px over/under, and not the maximum exact pixel size of the body;
    document.body.append(c);

    canvas = $("#fui_canvas");
    ctx = canvas.getContext("2d");

    dimensions.w = canvas.parentElement.clientWidth;
    dimensions.h = canvas.parentElement.clientHeight;
    canvas.width = dimensions.w;
    canvas.height = dimensions.h;

    screenSizeObserver = new ResizeObserver(() => {
      dimensions.w = canvas.parentElement.clientWidth;
      dimensions.h = canvas.parentElement.clientHeight;
      canvas.width = dimensions.w;
      canvas.height = dimensions.h;
    });

    screenSizeObserver.observe(document.body);
  }
}

document.addEventListener("DOMContentLoaded", () => {
  document.addEventListener("visibilitychange", initialize);
  initialize();
});
html,
body {
    margin: 0;
    padding: 0px;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    background:
        linear-gradient(180deg,
            rgba(0, 191, 254, 1) 10%,
            rgba(252, 252, 252, 1) 100%);
}

canvas {
    background: rgba(0, 0, 0, .25);
}

0
brk On

You can create a short of debouncing and set the width and height once the resize has done

let dimensions = {
  w: document.body.clientWidth,
  h: document.body.clientHeight,
};

const log = console.log.bind(console);
const $ = document.querySelector.bind(document);
let canvas;
let ctx;
let screenSizeObserver;
let initialized = false;
let shouldResize = true;

function initialize() {
  if (document.visibilityState === "visible" && initialized === false) {
    initialized = true;

    let c = document.createElement("canvas");
    c.id = "canvas";
    document.body.append(c);

    canvas = $("#canvas");
    ctx = canvas.getContext("2d");

    dimensions.w = document.body.clientWidth;
    dimensions.h = document.body.clientHeight;
    canvas.width = dimensions.w;
    canvas.height = dimensions.h;
  }
}

document.addEventListener("DOMContentLoaded", () => {
  document.addEventListener("visibilitychange", initialize);
  initialize();
});

screenSizeObserver = new ResizeObserver(() => {
  //log(document.body.clientWidth);
  if (shouldResize) {
    shouldResize = false
    dimensions.w = document.body.clientWidth;
    dimensions.h = document.body.clientHeight;
    if (canvas) {
      canvas.width = dimensions.w;
      canvas.height = dimensions.h;
    }

  }
  setTimeout(() => {
    shouldResize = true
  }, 1000)

});

screenSizeObserver.observe(document.body);
html,
body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  background: linear-gradient(180deg, rgba(0, 191, 254, 1) 10%, rgba(252, 252, 252, 1) 100%);
}

canvas {
  box-sizing: border-box;
  position: relative;
  padding: 0;
  margin: 0;
  background: rgba(0, 0, 0, .5);
}