Search code examples
javascripthtml

Move element to right or left with keyboard


So I'm trying to make this block move left or right based on the keypress, but for some reason when i move right and then when i move left it doesn't reach the left screen frame boundary. It seems to me that when i move right the whole frame moves to the right so the steps it takes to reach the left frame boundary reduces.

I don't know what's going wrong here.

var element = document.getElementById("lupo");
var val = 0;
var cal = 0;

document.addEventListener("keypress", function(event) {
  move(event.key);
});

function move(key) {
  switch (key) {
    case "a":
      console.log("bleh");
      val += 50;
      console.log(val);
      element.style.right = `${val}px`;
      break;
    case "d":
      console.log("brrr");
      cal += 50;
      console.log(cal);
      element.style.left = `${cal}px`;
      break;

    default:
      break;
  }
}
body {
  background-color: red
}

#lupo {
  height: 200px;
  width: 200px;
  background-color: yellow;
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0%;
  margin: auto;
}
<div id="lupo"></div>


Solution

  • You want to move your element #lupo on keydown on the x axis, so use only an x variable. Also, don't forget to event.preventDefault() to override the browser's default behavior (page scroll). Also, use only element.style.left:

    var element = document.getElementById("lupo");
    
    var x = 0; // Use only the `x` axis 
    
    document.addEventListener("keydown", function(event) {
      event.preventDefault(); // Add this
      if (!event.repeat) move(event.key);
    });
    
    function move(key) {
      switch (key) {
        case "a":
          x -= 50;
          element.style.left = `${x}px`; // use only `left` CSS prop
          break;
        case "d":
          x += 50;
          element.style.left = `${x}px`; // use only `left` CSS prop
          break;
        default:
          break;
      }
    }
    body { overflow: hidden; }
    
    #lupo {
      height: 100px;
      aspect-ratio: 1 / 1;
      margin: auto;
      background-color: orange;
      position: absolute;
      inset: 0;
    }
    <div id="lupo">Use A,D keys to move</div>


    Here's an alternative way without the switch/case statement:

    const elLupo = document.querySelector("#lupo");
    let x = 0;
    
    const move = (x) => elLupo.style.left = `${(x)}px`;
    
    const keyActions = {
      a: () => move(x -= 50),
      d: () => move(x += 50),
    };
    
    addEventListener("keydown", (event) => {
      event.preventDefault();
      if (!event.repeat) keyActions[event.key]?.();
    });
    body { overflow: hidden; }
    
    #lupo {
      height: 100px;
      aspect-ratio: 1 / 1;
      margin: auto;
      background-color: orange;
      position: absolute;
      inset: 0;
    }
    <div id="lupo">Use: A,D keys to move</div>

    or by modifying the CSS Property (Variable) on the translate CSS rule and modify it using style.setProperty() from JS. With this solution you can also add CSS transitions/animations:

    const elLupo = document.querySelector("#lupo");
    let x = 0;
    
    const move = (x) => {
      elLupo.style.setProperty("--x", x);
    };
    
    const keyActions = {
      a: () => move(--x),
      d: () => move(++x),
    };
    
    addEventListener("keydown", (event) => {
      event.preventDefault();
      if (!event.repeat) keyActions[event.key]?.();
    });
    body { overflow: hidden; }
    
    #lupo {
      height: 100px;
      aspect-ratio: 1 / 1;
      margin: auto;
      background-color: orange;
      position: absolute;
      inset: 0;
      
      transition: translate 0.3s;
      translate: calc(var(--x, 0) * 50px) calc(var(--y, 0) * 50px);
    }
    <div id="lupo">Use: A,D keys to move</div>

    Notice in the above examples the if (!event.repeat), added to prevent moving the element on key long-press.