ksenia
ksenia

Reputation: 177

Switching between images to avoid "jumping" behaviour

I am trying to imitate the behaviour of a checkbox by switching custom checkbox images depending on the condition (true or false). I get a very annoying visual bug where as I set state to the truthy or falsy condition the images depending on it and the box does a little flickr before switching, here's my code:

import React from 'react';
import boxCheckedIcon from '../../../../assets/SmallBoxChecked.svg';
import boxUncheckedIcon from '../../../../assets/SmallBoxUnchecked.svg';


class Example extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            condition: false,
        }
    }


    handleSelect = () => {
        this.setState(prevState => ({
            condition: !prevState.condition
        }));
    }


    renderCheckbox = condition => {
        return condition ? <img
            id="checkedCheck"
            src={boxCheckedIcon}
            alt="checked check box"
        /> : <img
                id="uncheckedCheck"
                src={boxUncheckedIcon}
                alt="unchecked check box"
            />
    };

    render() {
        const { condition } = this.state;

        return (
            <div onClick={() => handleSelect()}>
                {renderCheckbox(condition)}
            </div>
        );
    }
}

any idea how to make the transition between the two images smoother? CSS, React or otherwise..

Upvotes: 4

Views: 372

Answers (4)

Salman Arshad
Salman Arshad

Reputation: 272146

Try specifying the dimensions on the image. Missing image dimensions could cause reflows because the browser has to load the image to see its dimensions and it will temporarily collapse the area used by the image causing everything below the image to jump around.

Upvotes: 1

Mordechai
Mordechai

Reputation: 16264

If you're using Create React App, you can use svg components instead of img tag.

import { ReactComponent as Checked } from '../assets/checked.svg'
import { ReactComponent as Unchecked } from '../assets/unchecked.svg'

// Use it like this 
return condition ? <Checked/> : <Unchecked/>

Upvotes: 1

Dipen Shah
Dipen Shah

Reputation: 26075

Problem is that every time you render different img tag, browser will fetch/download images again. Without using any font libraries, you can avoid this situation by rendering both images on the DOM and hiding/showing them based on condition:

renderCheckbox = (condition) => {
  return (
    <>
      <img
        heigth="40"
        width="40"
        id="checkedCheck"
        src={boxCheckedIcon}
        alt="checked check box"
        className={condition ? "" : "hidden"}
      />
      <img
        heigth="40"
        width="40"
        id="uncheckedCheck"
        src={boxUncheckedIcon}
        alt="unchecked check box"
        className={condition ? "hidden" : ""}
      />
    </>
  );
};

and in your style.css file you can add hidden class:

.hidden {
  display: none;
}

take a look at this codesandbox.

Upvotes: 3

Alexandr
Alexandr

Reputation: 522

The most correct would be to move your images to a CSS-sprite and switch it background-position by an additional class

render() {
  const { condition } = this.state;

  return (
    <div
      className={classNames(
        'checkbox__icon',
        condition && 'is-checked',
      )}
      onClick={this.handleSelect}
    />
  );
}

In the example, I use the lib https://www.npmjs.com/package/classnames

Upvotes: 3

Related Questions