7
\$\begingroup\$

Recently I learned HTML+CSS and a bit of jQuery and am building various web-things to stretch my skills and learn more about how to do things the right way. I was a bit surprised at just how many different ways there are to do the same thing using just CSS and JavaScript.

Currently I am building a bit of a "landing page" style website bit by bit, and the component I am working on right now is an interactive discovery menu type thing. Essentially there is an initial text, which incites the user to hover over it, and once hovering, various options appear, which are links. My current code is below and functional, however I am not confident that I am executing this efficiently or properly.

A couple of specifics I want to learn are:

  • What HTML element should I use for the initial text?
  • Is the structure of my hover-menu proper? Or is there a better way that is more standard for this sort of thing?
  • Would this be better done in CSS transitions rather than JS? NOTE: I want to add a context box below the menu (or somewhere not directly attached to the individual links) which fills with contextual information about the currently hovered link, so I assume JS is the solution in the long run.
  • Not that important but: I had trouble attempting to classify what to call this sort of thing (so as to google it). Is there a standard name for this sort of set-up?

Final Note:

I don't really know any general JavaScript outside of the jQuery I have learned. I do however have programming experience, so I am not opposed to using any other external JS libraries which would be more suited to my goals. I have simply not had much time to explore JavaScript and the many extensions it has. Basically I'd love some directing from anyone who knows what I don't!

$(document).ready(function() {
  $('#menu').hover(
    function() { // mouseenter
      // hide & compress initial text
      $('#menu span').stop().animate({
        width: '0px',
        opacity: 0
      }, $('#menu span').hide);

      // show & decompress link options
      $('#menu a').stop().show().animate({
        width: '100px',
        opacity: 1
      });

    },
    function() { //mouseleave
      // hide & compress options
      $('#menu a').stop().animate({
        width: '0px',
        opacity: 0
      }, $('#menu a').hide);

      // show & decompress link options
      $('#menu span').stop().show().animate({
        width: '250px',
        opacity: 1
      });

    });
});
#menu {
  width: auto;
}
#menu * {
  overflow: hidden;
  white-space: nowrap;
  font-size: 30px;
  text-align: center;
}
#menu a {
  display: none;
  width: 0px;
  opacity: 0;
}
#menu span {
  display: inline-block;
  width: 250px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<body>
  <div id="menu">
    <span>Hover for items!</span>
    <a href="#1">Item 1</a>
    <a href="#2">Item 2</a>
    <a href="#3">Item 3</a>
  </div>
</body>

\$\endgroup\$
2
\$\begingroup\$

Markup :

I am not sure the content you are displaying is supposed to be a navigation menu or just options. In the first case (navigation menu), you should consider using the nav element instead of <div id="menu"> a it has a semantic value.

Transitions :

You can achive almost the same animation easily with CSS transitions. It would avoid the jQuery lib download for the client especialy if you use it only for this functionality. A drawback for transitions can be browser support (see lower).

The following snippet shows how you can use transitions for your animation but it doesn't contain vendor prefixes which you need to use to maximize browser compatibility (canIuse is a great ressource to find out which ones are needed according to your target browsers).

#menu {
  position: relative;
  display: inline-block;
  overflow: hidden;
  text-align: center;
  width: 250px;
}
#menu span, #menu a {
  display: inline-block;
  font-size: 30px;
  white-space: nowrap;
  transition: transform .5s ease-out, opacity .5s;
}
#menu a {
  position: absolute;
  left: 100%; top: 0;
  width: 33.33%;
}
#menu:hover a:nth-child(2) { transform:translateX(-300%); }
#menu:hover a:nth-child(3) { transform:translateX(-200%); }
#menu:hover a:nth-child(4) { transform:translateX(-100%); }
#menu:hover span{
  transform:translateX(-50%);
  opacity:0;
}
<body>
  <nav id="menu">
    <span>Hover for items!</span>
    <a href="#1">Item 1</a>
    <a href="#2">Item 2</a>
    <a href="#3">Item 3</a>
  </nav>
</body>

Browser support (with appropriate prefixes):

\$\endgroup\$
  • \$\begingroup\$ I did implement this using CSS transitions before but it didn't look as clean as this. Since I want to add context display in a separate part of the screen I am certain I will need JS. So I ask is it considered OK to mix CSS transition and JS animation? If I manipulate the DOM will CSS transition rules apply to those changes? \$\endgroup\$ – mgallagher May 22 '15 at 16:58
  • 1
    \$\begingroup\$ @MylesGallagher JS an CSS transitions work fine together. JS is often used to trigger transions. \$\endgroup\$ – web-tiki May 22 '15 at 17:18
5
\$\begingroup\$

One thing you could do is create functions to call instead of writing each sub function out every time you want to animate something.

var hideText = function(element) {

    $('#menu ' + element).stop().animate({
      width: '0px',
      opacity: 0
    }, $('#menu ' + element).hide);
}

var showText = function(element, elementWidth) {

    $('#menu ' + element).stop().show().animate({
      width: elementWidth,
      opacity: 1
    });
}

Now you can call this like this, with less repeated code:

  $('#menu').hover(
    function() { // mouseenter

      hideText('span');
      showText('a', '100px');
    },
    function() { //mouseleave

      hideText('a');
      showText('span', '250px');
    });
});

$(document).ready(function() {

  var hideText = function(element) {
      
      $('#menu ' + element).stop().animate({
        width: '0px',
        opacity: 0
      }, $('#menu ' + element).hide);
  }

  var showText = function(element, elementWidth) {
      
      $('#menu ' + element).stop().show().animate({
        width: elementWidth,
        opacity: 1
      });
  }

  $('#menu').hover(
    function() { // mouseenter

      hideText('span');
      showText('a', '100px');
    },
    function() { //mouseleave

      hideText('a');
      showText('span', '250px');
    });
});
#menu {
  width: auto;
}
#menu * {
  overflow: hidden;
  white-space: nowrap;
  font-size: 30px;
  text-align: center;
}
#menu a {
  display: none;
  width: 0px;
  opacity: 0;
}
#menu span {
  display: inline-block;
  width: 250px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<body>
  <div id="menu">
    <span>Hover for items!</span>
    <a href="#1">Item 1</a>
    <a href="#2">Item 2</a>
    <a href="#3">Item 3</a>
  </div>
</body>

\$\endgroup\$
2
\$\begingroup\$

Avoid traversing the DOM multiple times to get the same element.

$(document).ready(function() {
  var $menu = $('#menu'),
      $spans = $menu.find('span'),
      $anchors = $menu.find('a');
  $menu.hover(mouseEnter, mouseLeave);

function mouseEnter() {
      // hide & compress initial text
      $spans.stop().animate({
        width: '0px',
        opacity: 0
      }, $spans.hide);

  // show & decompress link options
  $anchors.stop().show().animate({
    width: '100px',
    opacity: 1
  });
}

function mouseLeave() {
      // hide & compress options
      $anchors.stop().animate({
        width: '0px',
        opacity: 0
      }, $anchors.hide);

  // show & decompress link options
  $anchors.stop().show().animate({
    width: '250px',
    opacity: 1
  });

}

});
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.