Search code examples
htmlcsscss-transitionsfont-size

Problematic CSS transition based on em units


I'm trying to create an effect where an anchor element that's located in header scales itself up on hovering while maintaining the width and height of an element so that it fits the header and doesn't move or affect other elements in any way. Animations are working great in Chrome but in Mozilla, Firefox and Edge/IE the transitions don't work well at all.

  • The header has a height of 4em.
  • Default font size for anchor elements that are to be animated is 2em. Width and height are also 2em (2*2 = 4em so I get the perfect squares that fit the header).
  • When hovering i change the font-size to 2.5em and both width and height to 1.6em (2.5*1.6 = 4em of the header height) <- I think that this is a problem.

I tried animating only height, font-size and line-height but that doesn't eliminate the problem. It seems that browsers are confused by the width and height being defined by em units so they scale down the content first and than scale it up. Still, that behavior isn't present in Chrome where everything works just fine.

Is there any solution for this problem as I would like to avoid using px units because of the easier implementation of responsiveness of the website. Or maybe I should switch to using px units and use more media queries for the site?

Problematic code:

<!-- Header -->
        <div id="header">
            <nav class="nav-buttons">
                <a href="#">L1</a>
                <a href="#">L2</a>
                <a href="#">L3</a>
            </nav>
        </div>

CSS:

#header {
  position: fixed;
  height: 4em;
  width: 100%;
}

/* global element settings */
a,
a:link,
a:visited,
a:hover,
a:active{
    text-decoration: none;
}
/* navigation buttons */

.nav-buttons > *,
.nav-buttons > *:visited {
  display: inline-block;
  vertical-align: middle;
  text-align: center;
  font-size: 2em;
  font-weight: 700;
  line-height: 2em;
  margin: 0;
  padding: 0;
  width: 2em;
  height: 2em;
  /*text-shadow: 0 0 0.1em #555555;*/
  transition-property: height, line-height, font-size, text-align, vertical-align;
  transition-duration: 0.3s;
}

.nav-buttons > *:hover,
.nav-buttons > *:active,
.button-active {
  transition-property: height, line-height, font-size, text-align, vertical-align;
  transition-duration: 0.3s;
  font-size: 2.5em;
  line-height: 1.6em;
  width: 1.6em;
  height: 1.6em;
}

Accompanying JSFiddle: https://jsfiddle.net/2futafsw/3/


Solution

  • Unfortunately, it looks like the browsers are simply handling the transitions differently. What you need to do is append the browser prefixes to the transition-property rules and apply the styles accordingly.

    For FireFox, that's -moz-transition-property, Chrome / Safari is -webkit-transition-property.

    I've simplified your transitions a bit. Chrome works fine with just the font size, and FireFox needs an animation on the margins (which, funny enough, mess up the Chrome animations).

    #header {
      position: fixed;
      height: 4em;
      width: 100%;
    }
    
    /* global element settings */
    a,
    a:link,
    a:visited,
    a:hover,
    a:active{
    	text-decoration: none;
    }
    
    .nav-buttons > a,
    .nav-buttons > a:visited {
      display: inline-block;
      vertical-align: middle;
      text-align: center;
      font-size: 2em;
      font-weight: 700;
      line-height: 2em;
      margin: 0;
      padding: 0;
      width: 2em;
      height: 2em;
      -moz-transition-property: font-size, margin;
      -webkit-transition-property: font-size;
      transition-duration: 0.3s;
    }
    
    .nav-buttons > a:hover,
    .nav-buttons > a:active,
    .button-active {
      transition-duration: 0.3s;
      font-size: 2.5em;
      margin: -.20em;
    }
    <!-- Header -->
    <div id="header" class="">
      <nav class="nav-buttons">
        <a href="#" class="glyphicon glyphicon-menu-hamburger">a</a>
        <a href="#">L1</a>
        <a href="#">L2</a>
        <a href="#">L3</a>
      </nav>
    </div>