2
\$\begingroup\$

The goal of this function is to open a menu with a CSS class (animation is done through CSS transition), call an overlay on top of content and prevent scrolling at the same time. Also, since the designer didn't add any hamburger icon, I created a class (.header.isG_navSemiOpen) to add an in-between transition to tell the user there is something to click here.

It works but since I wasn't able to code all of it by myself I used some parts of code I found on the net (the two functions bodyFreezeScroll and bodyUnfreezeScroll) and I am not sure nesting them like this into the function is a good thing. Also, should I make more variables for my selectors on the click event?

//Main menu amimation
function openMenu() {

  var $body = $(window.document.body);

  function bodyFreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('overflow', 'hidden');
    $body.css('marginRight', ($body.css('marginRight') ? '+=' : '') + ($body.innerWidth() - bodyWidth));
    $body.css({
      'overflow' : 'hidden',
      'position' : 'relative' 
    });
    $('#js-mainOverlay').on('touchmove', false);
  }
  function bodyUnfreezeScroll() {
    var bodyWidth = $body.innerWidth();
    $body.css('marginRight', '-=' + (bodyWidth - $body.innerWidth()))
    $body.css({
      'overflow' : 'auto',
      'position' : 'inherit' 
    });
  }

  $('#js-menuTrigger, #js-gnavCloseBtn, #js-mainOverlay').on('click', function (e) {
    e.preventDefault();
    $('.g_nav').toggleClass('isOpen');
    $('.header').toggleClass('isG_navOpen').removeClass('isG_navSemiOpen');
    $('#js-gnavCloseBtn').parent().toggleClass('isOpen');
    $('#js-mainOverlay').toggleClass('isG_navOpen');
    bodyFreezeScroll();
  });
  $('#js-gnavCloseBtn, #js-mainOverlay').on('click', function (e) {
    bodyUnfreezeScroll();
  });

    $('#js-menuTrigger').on('mouseover', function (e) {
      $('.header').addClass('isG_navSemiOpen');
    });
    $('#js-menuTrigger').on('mouseout', function (e) {
      $('.header').removeClass('isG_navSemiOpen');
    });

}

$(document).ready(function () {
  openMenu();
});
ul, li {
  list-style: none;
  margin: 0;
  padding: 0;
}

body {
  background: #ccc;
  font-size: 12px;
}

.mainOverlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  -webkit-transition: initial;
  transition: initial;
}
.mainOverlay.isG_navOpen {
  width: 100%;
  height: 100%;
  top: 0;
  left: 190px;
  opacity: 1;
  z-index: 9999;
  -webkit-transition: opacity 0.5s 0.5s;
  transition: opacity 0.5s 0.5s;
}

.gnav-close-btn {
  position: fixed;
  top: 25px;
  left: 210px;
  opacity: 0;
  visibility: hidden;
  color: #fff;
  font-size: 6rem;
}
.gnav-close-btn.isOpen {
  visibility: visible;
  opacity: 1;
  z-index: 99999999;
}

/* Header / Menu
/*------------------------------------------------------------------------------*/
.header {
  position: fixed;
  top: 0;
  left: 0;
  height: 0;
  width: 0;
  z-index: 300;
  cursor: pointer;
  border-top: 95px solid #fff;
  border-left: 95px solid #fff;
  border-right: 95px solid transparent;
  border-bottom: 95px solid transparent;
  -webkit-transition: all 1s cubic-bezier(0.190,1.000,0.220,1.000);
  transition: all 1s cubic-bezier(0.190,1.000,0.220,1.000);
}
.header.isG_navSemiOpen {
  height: 100%;
  height: 50vh;
  border-right: 95px solid #fff;
  background: rgba(255,255,255,1);
  background: -moz-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%);
  background: -webkit-gradient(left top, right top, color-stop(0%, rgba(255,255,255,1)), color-stop(50%, rgba(255,255,255,0.5)), color-stop(100%, rgba(255,255,255,0)));
  background: -webkit-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%);
  background: -ms-linear-gradient(left, rgba(255,255,255,1) 0%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%);
  background: linear-gradient(to right, rgba(255,255,255,1) 0%, rgba(255,255,255,0.5) 50%, rgba(255,255,255,0) 100%);
}
.header.isG_navOpen {
  height: 100%;
  height: 120vh;
  border-right: 95px solid #fff;
  background: #fff;
}
.header h1 {
  font-size: 10px;
  position: absolute;
  z-index: 150;
  top: -30px;
  left: -76px;
  -webkit-transition: all 0.4s cubic-bezier(.87,-.41,.19,1.44);
  transition: all 0.4s cubic-bezier(.87,-.41,.19,1.44);
}
.header.isG_navSemiOpen h1 {
  -webkit-transform: translate3d(40px, 0, 0);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  transform: translate3d(40px, 0, 0);
  -webkit-filter: blur(0);
  filter: blur(0);
}
.header.isG_navOpen h1 {
  -webkit-transform: translate3d(60px, 0, 0);
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  transform: translate3d(60px, 0, 0);
  -webkit-filter: blur(0);
  filter: blur(0);
}

.g_nav {
  width: 192px;
  height: 100vh;
  position: fixed;
  z-index: 400;
  visibility: hidden;
  opacity: 0;
  -webkit-transform: translate3d(-100%, 0, 0);
  transform: translate3d(-100%, 0, 0);
  -webkit-transition: all 0.4s cubic-bezier(0.190,1.000,0.220,1.000);
  transition: all 0.4s cubic-bezier(0.190,1.000,0.220,1.000);
}
.g_nav.isOpen {
  visibility: visible;
  opacity: 1;
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
}
.g_nav_list {
  position: relative;
  padding-top: 140px;
}
.g_nav_item a {
  display: block;
  margin: 6px 0;
  text-align: center;
  font-size: 12px;
}
.g_nav_item--home a {
  margin-bottom: 20px;
}
.g_nav_item--about a {
  margin-top: 20px;
}
.g_nav_item--about:before,
.g_nav_item--home:after {
  content: '';
  width: 6px;
  height: 2px;
  display: block;
  margin: 20px auto 0 auto;
  background: #444;
}
.g_nav_item--home:after {
  margin: 0 auto 20px auto;
}
.g_nav_item a.about_icn:before {
  content: '';
  display: inline-flex;
  width: 12px;
  height: 15px;
  margin-right: 5px;
}
.g_nav_copyright {
  margin-top: 35px;
  text-align: center;
  font-size: 1.2rem;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>

<div id="js-mainOverlay" class="mainOverlay"></div>
<div class="gnav-close-btn"><a href="javascript:void(0)" id="js-gnavCloseBtn">&times;</a></div>
<div class="gallery-close-btn"><a href="javascript:void(0)" id="js-galleryCloseBtn">&times;</a></div>

<header class="header" id="js-menuTrigger">
  <h1>TOSEI  Gallery</h1>
</header>

<nav class="g_nav">
  <ul class="g_nav_list">
    <li class="g_nav_item g_nav_item--home"><a href="">HOME</a></li>
    <li class="g_nav_item"><a href="/category/hospital">病院・医院</a></li>
    <li class="g_nav_item"><a href="/category/business">企業</a></li>
    <li class="g_nav_item"><a href="/category/commercial_facility">商業施設</a></li>
    <li class="g_nav_item"><a href="/category/shrine">社寺建築</a></li>
    <li class="g_nav_item"><a href="/category/detached_residence">戸建て住宅</a></li>
    <li class="g_nav_item"><a href="/category/rental_house">賃貸住宅</a></li>
    <li class="g_nav_item g_nav_item--about"><a href="/about" class="about_icn">会社案内</a></li>
  </ul>
  <p class="g_nav_copyright">Copyright © 2012<br>TOSEI KENSETU,.co.ltd<br>All Right Reserved.</p>
</nav>
<div  id="js-overlay" class="overlay">
  <div id="js-ajaxPostContents"></div>
</div>

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to code review. It will be nice to see the code work in action. Put all your code together and Ctrl+ M. \$\endgroup\$
    – Tolani
    Oct 2, 2016 at 7:33
  • \$\begingroup\$ Well I thought I used ctrl + M. You mean there is something else to do beside displaying a snippet with a run code button? \$\endgroup\$
    – user119060
    Oct 2, 2016 at 10:11

1 Answer 1

0
\$\begingroup\$

The code looks to be pretty sound. Here are a few things to consider ...

The need for the function openMenu() (in the global namespace?) can be avoided by moving the contents of openMenu() into the existing $(document).ready().

Some DOM elements need to be rediscovered on each of several user interactions. This is trivial in a small development document but could be slow in a large, real-world DOM. You can cache more jQuery objects in the same way $(window.document.body) is already cached. This is a trade-off of UI responsiveness against memory.

Fixed CSS maps can also be cached. Again a trade-off.

Here it is complete with a few other improvements such as method chaining :

$(document).ready(function () {
    var $$ = { // cache of jQuery objects
        'body': $(window.document.body),
        'gnavCloseBtn': $('#js-gnavCloseBtn'),
        'mainOverlay': $('#js-mainOverlay'),
        'g_nav': $('.g_nav'),
        'header': $('.header')
    };
    cssMaps = {
        'freezeScroll': { 'overflow': 'hidden', 'position': 'relative' },
        'unfreezeScroll': { 'overflow': 'auto', 'position': 'inherit' }
    }

    function bodyFreezeScroll() {
        var bodyWidth = $$.body.innerWidth();
			$$.body.css('overflow', 'hidden')
            .css('marginRight', ($$.body.css('marginRight') ? '+=' : '') + ($$.body.innerWidth() - bodyWidth))
            .css(cssMaps.freezeScroll);
        $$.mainOverlay.on('touchmove', false);
		}
		function bodyUnfreezeScroll() {
			var bodyWidth = $$.body.innerWidth();
			$$.body.css('marginRight', '-=' + (bodyWidth - $$.body.innerWidth())) // always '-=0'?
            .css(cssMaps.unfreezeScroll);
    }

    //Main menu animation
    $('#js-menuTrigger, #js-gnavCloseBtn, #js-mainOverlay').on('click', function (e) {
        e.preventDefault();
        $$.g_nav.toggleClass('isOpen');
			$$.header.toggleClass('isG_navOpen').removeClass('isG_navSemiOpen');
        $$.gnavCloseBtn.parent().toggleClass('isOpen');
			$$.mainOverlay.toggleClass('isG_navOpen');
        bodyFreezeScroll();
    });
    $('#js-gnavCloseBtn, #js-mainOverlay').on('click', bodyUnfreezeScroll); // no need for an anonymous function wrapper.
    $$.('#js-menuTrigger').on({
			'mouseover': function (e) {
				$$.header.addClass('isG_navSemiOpen');
			},
			'mouseout': function (e) {
				$$.header.removeClass('isG_navSemiOpen');
        }
    });
});
\$\endgroup\$
1
  • \$\begingroup\$ Thank you very much Roamer for the refactoring! I will look at it! \$\endgroup\$
    – user119060
    Oct 10, 2016 at 10:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.