Showing posts with label UI. Show all posts
Showing posts with label UI. Show all posts

tickertapes

Users can search for any word or phrase and opt for news of common financial market indexes


Originally implemented as "Twickertapes" and utilizing the original Twitter API (v2.0), this app is merely a demonstration of what can be done with a little text input, and API (the Google News API) and scrolling text and ASCII art.

You can find it on the web here: https://tickertapes.net

 

Neat UI Effects with jQueryUI and Animate.CSS

So you want neat animation effects on your UI? Seems like it might be a tricky implementation, right?

Animate.css makes it easy to implement modern UI animation effects that make for better user experience/cues


It could not be simpler with jQuery UI and other open source options. Here is an easy sample to pick up and run with from jQuery.com:

jQuery UI Effects
 <!doctype html>  
 <html lang="en">  
 <head>  
   <meta charset="utf-8">  
   <meta name="viewport" content="width=device-width, initial-scale=1">  
   <title>jQuery UI Effects - Effect demo</title>  
   <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">  
   <link rel="stylesheet" href="/resources/demos/style.css">  
   <style>  
     .toggler {  
       width: 500px;  
       height: 200px;  
       position: relative;  
     }  
     #button {  
       padding: .5em 1em;  
       text-decoration: none;  
     }  
     #effect {  
       width: 240px;  
       height: 170px;  
       padding: 0.4em;  
       position: relative;  
     }  
       #effect h3 {  
         margin: 0;  
         padding: 0.4em;  
         text-align: center;  
       }  
     .ui-effects-transfer {  
       border: 2px dotted gray;  
     }  
   </style>  
   <script src="https://code.jquery.com/jquery-1.12.4.js"></script>  
   <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>  
   <script>  
     $(function () {  
       // run the currently selected effect  
       function runEffect() {  
         // get effect type from  
         var selectedEffect = $("#effectTypes").val();  
         // Most effect types need no options passed by default  
         var options = {};  
         // some effects have required parameters  
         if (selectedEffect === "scale") {  
           options = { percent: 50 };  
         } else if (selectedEffect === "transfer") {  
           options = { to: "#button", className: "ui-effects-transfer" };  
         } else if (selectedEffect === "size") {  
           options = { to: { width: 200, height: 60 } };  
         }  
         // Run the effect  
         $("#effect").effect(selectedEffect, options, 500, callback);  
       };  
       // Callback function to bring a hidden box back  
       function callback() {  
         setTimeout(function () {  
           $("#effect").removeAttr("style").hide().fadeIn();  
         }, 1000);  
       };  
       // Set effect from select menu value  
       $("#button").on("click", function () {  
         runEffect();  
         return false;  
       });  
     });  
   </script>  
 </head>  
 <body>  
   <div class="toggler" style="margin-top:200px;">  
     <div id="effect" class="ui-widget-content ui-corner-all">  
       <h3 class="ui-widget-header ui-corner-all">Effect</h3>  
       <p>  
         Etiam libero neque, luctus a, eleifend nec, semper at, lorem. Sed pede. Nulla lorem metus, adipiscing ut, luctus sed, hendrerit vitae, mi.  
       </p>  
     </div>  
   </div>  
   <select name="effects" id="effectTypes">  
     <option value="blind">Blind</option>  
     <option value="bounce">Bounce</option>  
     <option value="clip">Clip</option>  
     <option value="drop">Drop</option>  
     <option value="explode">Explode</option>  
     <option value="fade">Fade</option>  
     <option value="fold">Fold</option>  
     <option value="highlight">Highlight</option>  
     <option value="puff">Puff</option>  
     <option value="pulsate">Pulsate</option>  
     <option value="scale">Scale</option>  
     <option value="shake">Shake</option>  
     <option value="size">Size</option>  
     <option value="slide">Slide</option>  
     <option value="transfer">Transfer</option>  
   </select>  
   <button id="button" class="ui-state-default ui-corner-all">Run Effect</button>  
 </body>  
 </html>  


And one I whipped up from Animate.css...:
 <html>  
 <head>  
  <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>  
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.7.2/animate.min.css">  
  <script>                 
      $( document ).ready(function() {  
           myDiv = document.querySelector('#myDiv')       
           $("#buttonBounce").on("click", function () {  
                removeAllClasses();  
                myDiv.classList.add('animated', 'bounce')  
           });  
           $("#buttonSwing").on("click", function () {  
                removeAllClasses();  
                myDiv.classList.add('animated', 'swing')  
           });            
           $("#buttonWobble").on("click", function () {  
                removeAllClasses();  
                myDiv.classList.add('animated', 'wobble')            
           });            
           $("#buttonTada").on("click", function () {  
                removeAllClasses();  
                myDiv.classList.add('animated', 'tada')  
           });       
           $("#buttonBounceOut").on("click", function () {  
                removeAllClasses();  
                myDiv.classList.add('animated', 'bounceOutLeft')  
           });            
           function removeAllClasses(){  
                myDiv.classList.remove('animated', 'bounce', 'wobble', 'bounceOutLeft', 'tada', 'swing');  
           }  
      });       
  </script>  
 </head>  
 <body style="background:#000000;">  
 <div id="myDiv" style="margin-top:100px; margin-left:300px; width:250px; background:aqua; font-weight:bold; font-family:Arial; border: 2px solid lime; padding: 10px; border-radius: 25px;">~Something to animate~</h1>  
 <br/><br/>  
 &nbsp;&nbsp;<input type="button" id="buttonBounce" class="ui-state-default ui-corner-all" value="Bounce" />  
 </br><br/>  
 &nbsp;&nbsp;<input type="button" id="buttonTada" class="ui-state-default ui-corner-all" value="Tada" />  
 </br><br/>  
 &nbsp;&nbsp;<input type="button" id="buttonSwing" class="ui-state-default ui-corner-all" value="Swing" />  
 </br><br/>  
 &nbsp;&nbsp;<input type="button" id="buttonWobble" class="ui-state-default ui-corner-all" value="Wobble" />  
 </br><br/>  
 &nbsp;&nbsp;<input type="button" id="buttonBounceOut" class="ui-state-default ui-corner-all" value="Bounce Out" />  
 </br><br/>  
 </body>  
 </html>  


This is what the Animate.css code above will look like..


Happy coding!


Codepens: 

https://codepen.io/radagast27/pen/pooavXd

https://codepen.io/radagast27/pen/xxxYboM



References:

https://jqueryui.com/effect

https://github.com/daneden/animate.css

ASCII Art with Python

Have you ever wanted to convert an icon or photo to ASCII art? Fortunately there are lots of tools to do this out there. I looked around for one that works with Python 3+ and found a succinct, modular script that can output ASCII art from image files like the following:


The script is from Paul Bourke. There is very clear commenting on each step. Essentially, an image loaded from the "--file" argument is divided into a grid and each position of the grid is assigned certain ASCII character whose gray scale level most closely matches the average for that area of the image. I simply modified line 146 and 150 to demonstrate on console vs. the outfile.txt default.

Save the following as ascii.py:
 #Python code to convert an image to ASCII image.  
 import sys, random, argparse  
 import numpy as np  
 import math  
 from PIL import Image  
 # gray scale level values from:  
 # http://paulbourke.net/dataformats/asciiart/  
 # 70 levels of gray  
 gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "   
 # 10 levels of gray  
 gscale2 = '@%#*+=-:. '   
 def getAverageL(image):  
      # get image as numpy array  
      im = np.array(image)  
      # get shape  
      w,h = im.shape  
      # get average  
      return np.average(im.reshape(w*h))  
 def covertImageToAscii(fileName, cols, scale, moreLevels):  
      # declare globals  
      global gscale1, gscale2  
      # open image and convert to grayscale  
      image = Image.open(fileName).convert('L')  
      # store dimensions  
      W, H = image.size[0], image.size[1]  
      print("input image dims: %d x %d" % (W, H))  
      # compute width of tile  
      w = W/cols  
      # compute tile height based on aspect ratio and scale  
      h = w/scale  
      # compute number of rows  
      rows = int(H/h)  
      print("cols: %d, rows: %d" % (cols, rows))  
      print("tile dims: %d x %d" % (w, h))  
      # check if image size is too small  
      if cols > W or rows > H:  
           print("Image too small for specified cols!")  
           exit(0)  
      # ascii image is a list of character strings  
      aimg = []  
      # generate list of dimensions  
      for j in range(rows):  
           y1 = int(j*h)  
           y2 = int((j+1)*h)  
           # correct last tile  
           if j == rows-1:  
                y2 = H  
           # append an empty string  
           aimg.append("")  
           for i in range(cols):  
                # crop image to tile  
                x1 = int(i*w)  
                x2 = int((i+1)*w)  
                # correct last tile  
                if i == cols-1:  
                     x2 = W  
                # crop image to extract tile  
                img = image.crop((x1, y1, x2, y2))  
                # get average luminance  
                avg = int(getAverageL(img))  
                # look up ascii char  
                if moreLevels:  
                     gsval = gscale1[int((avg*69)/255)]  
                else:  
                     gsval = gscale2[int((avg*9)/255)]  
                # append ascii char to string  
                aimg[j] += gsval  
      # return txt image  
      return aimg  
 # main() function  
 def main():  
      # create parser  
      descStr = "This program converts an image into ASCII art."   
      parser = argparse.ArgumentParser(description=descStr)  
      # add expected arguments  
      parser.add_argument('--file', dest='imgFile', required=True)  
      parser.add_argument('--scale', dest='scale', required=False)  
      parser.add_argument('--out', dest='outFile', required=False)  
      parser.add_argument('--cols', dest='cols', required=False)  
      parser.add_argument('--morelevels',dest='moreLevels',action='store_true')  
      # parse args  
      args = parser.parse_args()  
      imgFile = args.imgFile  
      # set output file  
      outFile = 'out.txt'   
      if args.outFile:  
           outFile = args.outFile  
      # set scale default as 0.43 which suits  
      # a Courier font  
      scale = 0.43   
      if args.scale:  
           scale = float(args.scale)  
      # set cols  
      cols = 80   
      if args.cols:  
           cols = int(args.cols)  
      print('generating ASCII art...')  
      # convert image to ascii txt  
      aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels)  
      # open file  
      f = open(outFile, 'w')  
      # write to <console or> file ..f.write(row + '\n')  
      for row in aimg:  
           print(row + '\n')   
      # cleanup  
      f.close()  
      print("ASCII art written to console...") # %s" % outFile)  
 # call main  
 if __name__ == '__main__':  
      main()  


Using Windows CMD, navigate to the directory where your ascii.py script is located. Then execute the following:

ascii.py --file C:\somedir\logo.jpg --cols 150


Referencehttp://paulbourke.net/dataformats/asciiart/

Refactoring Made Obvious

Refactoring (as a term if not as a practice) gets thrown around quite a bit. Sometimes really necessary refactoring doesn't get the priority it deserves because it is hard to quantify or even visualize/sense the result of a good refactoring (it should be relatively transparent in experience to the original, any differences should be optimization or enhancement- without losing of the original functionality along the way). We can take the case of a simple JavaScript animation, for example.

Simple animating of "+" dropping across the browser screen

Long ago, I used a mobile app that had a neat UI animation feature I really liked, but it took me a while to track down just how to accomplish it. I found some good starting points on SO, and began implementing a draft on JSFiddle.net.

The animation behavior I went about creating is simply a delay of an HTML element falling from the screen (via the "topToBottom" variable you'll see below- which is just the browser screen height property) . In a cascading and sequential set of delays, each falling element is pushed an increasing distance from the left of the screen so that the elements can fall independently (otherwise you would see just one column for all of the falling +'s in the end result).

In the following 4 steps, I am going to present a very basic refactoring scenario- going from the code template references I found, to the final refactored code (css, html and .js).

(1) First I found a fiddle via the SO question reference below: http://jsfiddle.net/reWwx/4/

(2) I then changed the code to create my own draft on JSFiddle.net: http://jsfiddle.net/reWwx/539/

(3) Next, I created an .htm file with the CSS styles and JavaScript inline (not quite what we'd want to check into source control...):
 <html>  
 <head>  
 <style>  
 body {height: 600px; background-color: #999}  
 #line-3 {  
   position:absolute;  
   width:100%;  
   left:20px;  
   top:0px;  
 }  
 #line-4 {  
   position:absolute;  
   width:100%;  
   left:30px;  
   top:0px;  
 }  
 #line-5 {  
   position:absolute;  
   width:100%;  
   left:40px;  
   top:0px;  
 }  
 #line-6 {  
   position:absolute;  
   width:100%;  
   left:55px;  
   top:0px;  
 }  
 #line-7 {  
   position:absolute;  
   width:100%;  
   left:70px;  
   top:0px;  
 }  
 #line-8 {  
   position:absolute;  
   width:100%;  
   left:85px;  
   top:0px;  
 }  
 #line-9 {  
   position:absolute;  
   width:100%;  
   left:100px;  
   top:0px;  
 }  
 #line-10 {  
   position:absolute;  
   width:100%;  
   left:115px;  
   top:0px;  
 }  
 #line-11 {  
   position:absolute;  
   width:100%;  
   left:130px;  
   top:0px;  
 }  
 #line-12 {  
   position:absolute;  
   width:100%;  
   left:145px;  
   top:0px;  
 }  
 #line-13 {  
   position:absolute;  
   width:100%;  
   left:160px;  
   top:0px;  
 }  
 #line-14 {  
   position:absolute;  
   width:100%;  
   left:175px;  
   top:0px;  
 }  
 #line-15 {  
   position:absolute;  
   width:100%;  
   left:195px;  
   top:0px;  
 }  
 #line-16 {  
   position:absolute;  
   width:100%;  
   left:210px;  
   top:0px;  
 }  
 </style>  
 <script>  
 $(document).ready(function(){  
   var bodyHeight = $('body').height();  
   var footerOffsetTop = $('#line-3').offset().top;  
   var topToBottom = bodyHeight -footerOffsetTop;  
  $('#line-3').css({top:'auto',bottom:topToBottom});  
  $("#line-3").delay(100).animate({  
   bottom: '100px',  
   }, 2200);   
  $('#line-4').css({top:'auto',bottom:topToBottom});  
  $("#line-4").delay(108).animate({  
   bottom: '100px',  
   }, 2200);   
  $('#line-5').css({top:'auto',bottom:topToBottom});  
  $("#line-5").delay(145).animate({  
   bottom: '100px',  
   }, 2200);   
  $('#line-6').css({top:'auto',bottom:topToBottom});  
  $("#line-6").delay(119).animate({  
   bottom: '100px',  
   }, 2200);   
  $('#line-7').css({top:'auto',bottom:topToBottom});  
  $("#line-7").delay(115).animate({  
   bottom: '100px',  
   }, 2200);   
    $('#line-8').css({top:'auto',bottom:topToBottom});  
  $("#line-8").delay(176).animate({  
   bottom: '100px',  
   }, 2100);   
    $('#line-9').css({top:'auto',bottom:topToBottom});  
  $("#line-9").delay(13).animate({  
   bottom: '100px',  
   }, 2200);   
    $('#line-10').css({top:'auto',bottom:topToBottom});  
  $("#line-10").delay(12).animate({  
   bottom: '100px',  
   }, 2200);   
    $('#line-11').css({top:'auto',bottom:topToBottom});  
  $("#line-11").delay(11).animate({  
   bottom: '100px',  
   }, 2000);   
    $('#line-12').css({top:'auto',bottom:topToBottom});  
  $("#line-12").delay(10).animate({  
   bottom: '100px',  
   }, 2100);   
    $('#line-13').css({top:'auto',bottom:topToBottom});  
  $("#line-13").delay(11).animate({  
   bottom: '100px',  
   }, 600);   
    $('#line-14').css({top:'auto',bottom:topToBottom});  
  $("#line-14").delay(14).animate({  
   bottom: '100px',  
   }, 700);   
      $('#line-15').css({top:'auto',bottom:topToBottom});  
  $("#line-15").delay(14).animate({  
   bottom: '100px',  
   }, 800);   
      $('#line-16').css({top:'auto',bottom:topToBottom});  
  $("#line-16").delay(24).animate({  
   bottom: '100px',  
   }, 900);   
 })  
 </script>  
 </head>  
 <body>  
 <div id="line-3">+</div>  
 <div id="line-4">+</div>  
 <div id="line-5">+</div>  
 <div id="line-6">+</div>  
 <div id="line-7">+</div>  
 <div id="line-8">+</div>  
 <div id="line-9">+</div>  
 <div id="line-10">+</div>  
 <div id="line-11">+</div>  
 <div id="line-12">+</div>  
 <div id="line-13">+</div>  
 <div id="line-14">+</div>  
 <div id="line-15">+</div>  
 <div id="line-16">+</div>  
 </body>    
 </html>  
(4) And lastly I identified all of the repeating parts and made them dynamic in JavaScript, using the jQuery library to shorten much of the .js behavior:
  <html>   
  <head>   
  <style>   
  body {height: 600px; background-color: #000000; color:lime;}   
  div {   
   position:absolute;   
   top:0px;   
    width:100%;   
  }   
  </style>   
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>   
  <script>   
  $(document).ready(function(){   
   var base = $('#base');  
   var topToBottom = $('body').height();    
   for(i=0; i<83; i++){   
    base.append('<div id=\"line-'+i+'\" style=\"left:'+ Math.abs(i*10) +'\px">+</div>')   
    $("#line-" + i).css({top:'auto', bottom:topToBottom}).delay(100*i).animate({bottom: '100px'}, (1000));    
   }   
  })   
  </script>   
  </head>   
  <body id="base">   
  </body>    
  </html>   

The final result contains the same behavior of the draft but it eliminates repetition by dynamically generating the HTML and dynamically attaching the falling action (which is really just coordinated position and visibility property changes behind the scenes of .animate()). Eliminating duplication, standardizing for better readability, reorganization for better clarity of code purpose and finding patterns (or finding different patterns that are a better match for the task) are the key concepts in refactoring.

Try it yourself by copying the code above, saving to an .htm file and opening the file in a web browser.

Final JSFiddle result: https://jsfiddle.net/radagast/6uzypc80/5

Larger font is always fun: https://twickrtape.azurewebsites.net/Home/About

Reference: https://stackoverflow.com/questions/8518400/jquery-animate-from-css-top-to-bottom

Application Walkthroughs with Anno.js

If you need to provide your users a quick intro to your app or new features that you have just released, you might want to give Anno.js a try. Of the several frameworks I sampled, this is was the sharpest looking and easiest to work with (for me, maybe for you too).


To configure:

1). Link to or host the required files in the DemoAnno.html <head> (see code on GitHub).

2). Configure the annoJS object by setting targets (by element selector, '#demo', '.walkDivs', etc.)

3). Create a button and set its onClick() == anno.show(); //anno, or the name of the annoJS object


And in 3 simple steps, you have a walkthrough:






All credit to @iamdanfox who created this great .js plug in. Here is the htm page source code, see references below for more:

 <html>  
 <head>  
 <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>  
 <script src="anno.js" type="text/javascript"></script>  
 <script src="jquery.scrollintoview.min.js" type="text/javascript"></script>  
 <link href="anno.css" rel="stylesheet" type="text/css" />  
 </head>  
 <body>  
 <div style="background-color='gray'; margin-left:33%;">  
 <b><i>Use this guided tour to see our latest features!</i></b>  
 <br/>  
 <button type="button" class="btn btn-default" onclick="anno.show();">Show Tour</button>  
 <br/>  
 <br/>  
 <div id="demo" style="width:27%;">  
 Your new login button is here: <button name="LOGIN" value="LOGIN">LOGIN</button>  
 <div>  
 </div>  
 <br />  
 </body>  
 <script>  
      var anno = new Anno([{  
       target: '#demo',  
       position:'left',  
       content: "This is our shiny new left div edge!",  
       buttons: [AnnoButton.NextButton]  
      }, {  
       target: '#demo',  
       position:'right',  
       content: "...and on the right...",  
       buttons: [AnnoButton.BackButton]  
      }]);       
 </script>  
 <html>  
Note the NextButton and BackButton- these are very useful for app walkthroughs


GitHub: https://github.com/Radagast27/AnnoJS_WalkthroughDemo

References: http://iamdanfox.github.io/anno.js/

https://github.com/iamdanfox/anno.js#usage

Animated X-to-Horizontal Lines (Hamburger) Toggle for UI Menu

Here is what you are looking for: https://codepen.io/radagast27/pen/OYmvmd

Implementing this UI feature is just a matter of wiring up some icon animation and fadeIn()/fadeOut() to the menu items.

 <html>  
 <head>  
 <script  
  src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>  
 <script>  
 $(document).ready(function(){  
      $('#nav-icon').click(function(){  
           $(this).toggleClass('open');  
       if($('#menu').css('opacity') == '0'){  
        $('#menu').css('opacity','1');  
        $('#menu').fadeIn(300).css('display','table');  
       }else{  
        $('#menu').css('opacity','0');  
        $('#menu').fadeOut(300).css('display','none');  
       }  
      });  
 });  
 </script>  
 </head>  
 <style>  
 body{  
  background-color: #000000;  
 }  
 #menu{  
   z-index: 5;  
   width: 40%;  
   height: 40%;  
   background-color: rgba(0,0,0, 0.95);  
   position: fixed;  
   font-family: Arial;  
   font-size: 1.5em;  
   text-align: left;  
   left: 100px;  
   top: 0px;  
   opacity: 0;  
   display: table;  
 }  
 .hidden{  
   display: none;  
   visibility: none;  
 }  
 #menu ul{  
   margin: 0;  
   padding: 0;  
   z-index: 10;  
   width: 40%;  
   height: 40%;  
   display: table-cell;  
   vertical-align: left;  
 }  
 #menu ul li{  
   cursor: pointer;  
   text-decoration: none;  
 }  
 #menu ul li:hover{  
   background-color: cyan;  
   -webkit-transition: .15s ease-in-out;  
   -moz-transition: .15s ease-in-out;  
   -o-transition: .15s ease-in-out;  
   transition: .15s ease-in-out;  
 }  
 #menu ul a{  
   letter-spacing: 5px;  
   text-align: left;  
   margin-left: 0px;  
   color: #fff;  
   list-style: none;  
   padding: 0px;  
   line-height: 75px;  
   padding: 10px 70px;  
   text-decoration: none;  
 }  
 #menu ul a:hover{  
   text-decoration: none;  
   color: #fff ;  
 }  
 #nav-icon {  
   z-index: 20;  
  width: 50px;  
  height: 35px;  
  position: relative;  
  margin: 25px;  
  -webkit-transform: rotate(0deg);  
  -moz-transform: rotate(0deg);  
  -o-transform: rotate(0deg);  
  transform: rotate(0deg);  
  -webkit-transition: .5s ease-in-out;  
  -moz-transition: .5s ease-in-out;  
  -o-transition: .5s ease-in-out;  
  transition: .5s ease-in-out;  
  cursor: pointer;  
 }  
 #nav-icon span {  
  display: block;  
  position: absolute;  
  height: 5px;  
  width: 40px;  
  background: #bada33;  
  opacity: 1;  
  -webkit-transform: rotate(0deg);  
  -moz-transform: rotate(0deg);  
  -o-transform: rotate(0deg);  
  transform: rotate(0deg);  
  -webkit-transition: .25s ease-in-out;  
  -moz-transition: .25s ease-in-out;  
  -o-transition: .25s ease-in-out;  
  transition: .25s ease-in-out;  
 }  
 /* Icon 3 */  
 #nav-icon span:nth-child(1) {  
  top: 0px;  
 }  
 #nav-icon span:nth-child(2),#nav-icon span:nth-child(3) {  
  top: 12px;  
 }  
 #nav-icon span:nth-child(4) {  
  top: 24px;  
 }  
 #nav-icon.open span:nth-child(1) {  
  top: 8px;  
  width: 0%;  
  left: 50%;  
 }  
 #nav-icon.open span:nth-child(2) {  
  -webkit-transform: rotate(45deg);  
  -moz-transform: rotate(45deg);  
  -o-transform: rotate(45deg);  
  transform: rotate(45deg);  
 }  
 #nav-icon.open span:nth-child(3) {  
  -webkit-transform: rotate(-45deg);  
  -moz-transform: rotate(-45deg);  
  -o-transform: rotate(-45deg);  
  transform: rotate(-45deg);  
 }  
 #nav-icon.open span:nth-child(4) {  
  top: 8px;  
  width: 0%;  
  left: 50%;  
 }  
 </style>  
 <body>  
 <header>  
   <div id="topbar"> <!-- top bar -->  
       <div id="nav-icon">  
        <span></span>  
        <span></span>  
        <span></span>  
        <span></span>  
       </div>  
     <div id="menu">  
       <ul>  
         <li><a href="#">Home</a></li>  
         <li><a href="#">About Us</a></li>  
         <li><a href="#">Portfolio</a></li>  
         <li><a href="#">Case Studies</a></li>  
         <li><a href="#">Careers</a></li>  
       </ul>  
     </div>  
   </div>  
 </header>  
 </html>  
 </body>  
Some minor tweaking of the flexible code referenced above can give you a modern .js transition toggle


Reference: https://jsfiddle.net/f19kz640/