Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does calling focus() break my CSS transition?

This html file shows a 3 panel layout. A css transition on the "left" property gives me a nice sliding effect when I change panels. It all works but, when I change panels, I want to place the focus on an input in the new panel. Can anyone tell me why the call to focus() breaks the css transition, and lands me half way between two panels? It only happens going forward. It works if I comment out the transition, and it works if I delay the call to focus() with a timeout.

The problem occurs in Chrome, IE and Firefox.

var panelContainer;
var panels = new Array();
var numPanels;
var currentPanel = 0;

window.addEventListener('load', init, false);

function init() {
  setTimeout(function() {
    window.scrollTo(0, 1);
  }, 10); //hiding the browser address bar in iPhone/Android

  panelContainer = document.getElementById("panelContainer");
  panels = document.getElementsByClassName("panel");
  numPanels = panels.length;
  sizeResize();
}

function sizeResize() {
  panelContainer.style.width = (numPanels * window.innerWidth) + "px";
  panelContainer.style.height = window.innerHeight + "px";
  for (var i = 0; i < numPanels; i++) {
    panels[i].style.width = window.innerWidth + "px";
    panels[i].style.height = window.innerHeight + "px";
  }
  slide();
}
window.onresize = sizeResize;

function slide(panel) {
  if (panel != undefined)
    currentPanel = panel;
  panelContainer.style.left = -(window.innerWidth * currentPanel) + "px";
  if (panel >= 0) {
    panels[panel].getElementsByTagName("input")[0].focus(); //shows problem
    //window.setTimeout(function () { panels[panel].getElementsByTagName("input")[0].focus() }, 100);//no problem

  }
}
#wrapper {
  width: 100%;
  height: auto;
  overflow: hidden;
}

#panelContainer {
  position: relative;
  transition: left 1000ms ease;
}

.panel {
  float: left;
}
<div id="wrapper">
  <div id="panelContainer">
    <div id="panel0" class="panel" style="background-color: #888;">
      panel zero
      <input id="btn0" class="focussable" type="button" onclick="slide(1);" value="forward" />
    </div>
    <div id="panel1" class="panel" style="background-color: #AAA;">
      panel 1
      <input id="btn1" class="focussable" type="button" onclick="slide(2);" value="forward" />
      <input type="button" onclick="slide(0);" value="back" />
    </div>
    <div id="panel2" class="panel" style="background-color: #CCC;">
      panel 2
      <input id="btn2" class="focussable" type="button" onclick="slide(1);" value="back" />
    </div>
  </div>
</div>
like image 451
bbsimonbb Avatar asked Nov 06 '14 15:11

bbsimonbb


1 Answers

As @user1585345 correctly stated a browser immediately scrolls to the focused element in order to bring it inside the current view, and not a px further!

What happens here is the following: you change the relative position of your element, but immediately you change focus, since the focused elements when the event fires is not visible the content also scrolls (ending the animation abruptly).

You should explicitly fire your focus only when the animation is complete, so that the browser recognise that no scrolling is necessary.

like image 171
Kuzeko Avatar answered Oct 03 '22 14:10

Kuzeko