1

Please see an example in jsfiddle. https://jsfiddle.net/0uwmxt02/1/

In IE and EDGE the transform: translateY(-50%) causes 1px jump up and down at the start and end of the animation. In Chrome the displacement still occurs but it is smooth. Any idea of what causes it?

.submenu-arrow-hover {
  position: relative;
  width: 200px;
  top:50px;
 }
  
 .submenu-arrow-hover:after {
    //background: rgba(155, 173, 188, 0.9);
    position:absolute;
    content:'';
    width: 1px;
    height: 28px;
    border: 1px solid red;
    border-right:0;
    border-top:0;
    top:50%;
    right:-1px;
    transform-origin: 0 0;
    transform: translateY(-50%);
    transition-duration: .3s;
  }
  
.submenu-arrow-hover:hover::after {
      //background: rgba(155, 173, 188, 0.9);
      position:absolute;
      content:'';
      width: 20px;
      height:20px;
      border: 1px solid red;
      border-right:0;
      border-top:0;
      top:50%;
      right:-1px;
      transform-origin: 0 0;
      transform: translateY(-50%) rotate(45deg);
}
<div class="submenu-arrow-hover">HOVER ME</div>
Varin
  • 2,354
  • 2
  • 20
  • 37

4 Answers4

1

Appears to be some kind of confusion between the translation and rotation. As a workaround, try removing the translateY() requirement completely:

.submenu-arrow-hover {
  position: relative;
  width: 200px;
  top: 50px;
  
  /* outline and excess height added as a test */
  outline: 1px dotted #ccc;
  height: 100px;
}

.submenu-arrow-hover::after {
  position: absolute;
  content: '';
  width: 1px;
  height: 28px;
  border: 0;
  border-left: 1px solid red;
  border-bottom: 1px solid transparent;
  right: -1px;
  transform-origin: 0 0;
  transition-duration: .3s;
  
  /* position top of pseudo element halfway down */
  top: 50%;
  margin-top: -14px; /* accurately centre by offsetting by half the height */
}

.submenu-arrow-hover:hover::after {
  width: 20px;
  height: 20px;
  border-bottom-color: red;
  transform: rotate(45deg);
}
<div class="submenu-arrow-hover">HOVER ME</div>

EDIT: updated to ensure arrow is centred vertically within parent <div/>.

Conan
  • 2,659
  • 17
  • 24
  • I need the translateY though, to position the arrow horizontally exactly in the middle of the parent div. – Varin May 22 '17 at 16:33
  • because the elements will have variable height (eg folding into two lines when screen size is reduced) I can't use pixel values. I ended up having to use jQuery to dynamically adjust the position... – Varin May 25 '17 at 14:12
1
  • Equal .submenu-arrow-hover:after's height to .submenu-arrow-hover:hover::after's (20px), otherwise the height async will make it bounce.

.submenu-arrow-hover {
  position: relative;
  width: 200px;
  top: 50px;
}

.submenu-arrow-hover:after {
  //background: rgba(155, 173, 188, 0.9);
  position: absolute;
  content: '';
  width: 1px;
  height: 20px;
  border: 1px solid red;
  border-right: 0;
  border-top: 0;
  top: 50%;
  right: -1px;
  transform-origin: 0 0;
  transform: translateY(-50%);
  transition-duration: .3s;
}

.submenu-arrow-hover:hover::after {
  //background: rgba(155, 173, 188, 0.9);
  position: absolute;
  content: '';
  width: 20px;
  height: 20px;
  border: 1px solid red;
  border-right: 0;
  border-top: 0;
  top: 50%;
  right: -1px;
  transform-origin: 0 0;
  transform: translateY(-50%) rotate(45deg);
}
<div class="submenu-arrow-hover">HOVER ME</div>
Syden
  • 8,425
  • 5
  • 26
  • 45
1

For Chrome, this StackOverflow answer worked wonderfully!

Add this to the element that has translateY applied: -webkit-backface-visibility: hidden;

Prid
  • 1,272
  • 16
  • 20
0

I ended up having to use jQuery as elements will have variable height and the arrow position needs to be adjusted when the screen is resized and when elements change size/position.

    function setMargins(arrow) {
    parentHeight = $(arrow).parent().height();  
    arrowHeight = $(arrow).height();  
    topMargin = (parentHeight - (arrowHeight - 1)) / 2 ;    
    $(arrow).css("margin-top", topMargin);    
}


$(document).ready(function(){
    $('.submenu-arrow-hover--arrow').each(function() {
    setMargins(this);
})
});

// timeout function needed as there is transition on the menu elements so
// function has to fire few milliseconds after the transitions have finished animating

$(window).resize(function() {
    setTimeout(function(){
    $('.submenu-arrow-hover--arrow').each(function() {

        setMargins(this)            
    })    
}, 600);
});
Varin
  • 2,354
  • 2
  • 20
  • 37