How to make menu fold like paper using CSS?


Tags: html,css,css3,css-transitions,css-transforms

Problem :

I wish to make a navigational menu that unfolds like paper using CSS only, looking like something like this: http://felixniklas.com/paperfold/ since it's mostly using CSS to create the transition effect.

Unfortunately the effect I get is still not as good, it's like this: https://jsfiddle.net/yaharga/7z2rg8gk/. There are spaces showing and the li don't stick together. Ideally I'd like to make the effect show on submenus as well.

I summarized the code to show the transition and transformation css involved:

// Nav Button Toggle
jQuery('.dropdown-toggle').on('click', function() {
  jQuery(this).toggleClass('active');
});
.dropdown-toggle {
  color: #ecf0f1;
  padding: 12px 0;
}

.dropdown-toggle.acitve {
  color: #bdc3c7
}

.toggleable {
  -webkit-transition: max-height .75s ease-in-out, -webkit-transform .75s ease-in-out, visibility .75s ease-in-out;
  transition: max-height .75s ease-in-out, transform .75s ease-in-out, visibility .75s ease-in-out;
  -webkit-transform-origin: top;
  transform-origin: top;
  -webkit-perspective: 320px;
  perspective: 320px;
  -webkit-transform: scaleY(0);
  transform: scaleY(0);
  list-style: none;
  position: relative;
  margin: 0;
  padding: 0
}

.dropdown-toggle.active+.toggleable {
  visibility: visible;
  max-height: 1200px;
  -webkit-transform: scaleY(1);
  transform: scaleY(1)
}

.nav-primary {
  margin: 30px 10px;
  text-align: center;
  position: relative
}

#menu-main-toggle {
  border: 0;
  background-color: #e74c3c;
  width: 100%;
  border-bottom: 1px dashed #c0392b;
}

#menu-main {
  width: 100%;
  position: absolute
}

#menu-main,
.toggleable {
  position: relative
}

.dropdown-toggle,
.menu-item {
  background: #e74c3c
}

.menu-item {
  border-top: 1px dashed #c0392b;
  transition: transform .75s ease-in-out;
}

.dropdown-toggle.active + #menu-main .menu-item {
  transform: rotateX(0deg);
}

.odd {
  transform: rotateX(-90deg);
}

.even {
  transform: rotateX(90deg);
}

.menu-item.first {
  border-top: none
}

.menu-link {
  display: block;
  padding: 12px 0;
  color: #ecf0f1
}

.menu-link:active {
  color: #fbfcfc
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<nav class="nav-primary">
  <button id="menu-main-toggle" class="dropdown-toggle">Menu</button>
  <ul id="menu-main" class="nav toggleable hide">
    <li class="odd first menu-item"><a class="menu-link" href="//localhost:3000/index.php/about/">About</a></li>
    <li class="even menu-item"><a class="menu-link" href="/index.php/category/bahrain/">Bahrain</a></li>
    <li class="odd menu-item parent"><a class="menu-link" href="/index.php/category/information-technology/">Information Technology</a>
    </li>
    <li class="even menu-item"><a class="menu-link" href="/index.php/category/snippets/">Snippets</a></li>
    <li class="odd last menu-item"><a class="menu-link" href="//localhost:3000/index.php/contact/">Contact</a></li>
  </ul>
</nav>



Solution :

I solved it by using a negative margin and transitioning that with the same amount of time it takes for the transformation to transition (credit for solution goes to @GCyrillus's codepen). I set the margins as double the size of the menu items as margins collapse so it was perfect. It's the closest I could get to the desired effect, though I would have prefered to get the effect of Felix Niklas's plugin. I think it uses shadows as well, but that cannot be implemented with pure CSS as transitions are linear.

You may correct me on any of which I have said or add to my code.

// Nav Button Toggle
jQuery('.dropdown-toggle').on('click', function() {
  jQuery(this).toggleClass('active');
});
.dropdown-toggle {
  color: #ecf0f1;
  padding: 12px 0;
}

.dropdown-toggle.acitve {
  color: #bdc3c7
}

.toggleable {
  -webkit-transition: max-height .75s ease-in-out, -webkit-transform .75s ease-in-out, visibility .75s ease-in-out;
  transition: max-height .75s ease-in-out, transform .75s ease-in-out, visibility .75s ease-in-out;
  -webkit-transform-origin: top;
  transform-origin: top;
  -webkit-transform: scaleY(0);
  transform: scaleY(0);
  list-style: none;
  position: relative;
  margin: 0;
  padding: 0
}

.toggleable .toggleable {
  -webkit-transform-origin: center;
  transform-origin: center;
}

.dropdown-toggle.active+.toggleable {
  visibility: visible;
  max-height: 1200px;
  -webkit-transform: scaleY(1);
  transform: scaleY(1)
}

#nav-primary {
  margin: 30px 10px;
  text-align: center;
  position: relative
}

#menu-main-toggle {
  border: 0;
  background-color: #e74c3c;
  width: 100%;
  border-bottom: 1px dashed #c0392b;
  height: 50px;
}

#menu-main {
  width: 100%;
  position: absolute
}

.dropdown-toggle,
.menu-item {
  background: #e74c3c
}

.menu-item {
  border-top: 1px dashed #c0392b;
  height: 50px;
  transition: transform .75s ease-in-out, margin .75s ease-in-out;
}

#menu-main .menu-item.odd {
  -webkit-transform: perspective(320px) rotateX(90deg);
  transform: perspective(320px) rotateX(90deg);
  -webkit-transform-origin: bottom;
  transform-origin: bottom;
  margin-top: -100px
}
#menu-main .menu-item.even {
  -webkit-transform: perspective(320px) rotateX(-90deg);
  transform: perspective(320px) rotateX(-90deg);
  -webkit-transform-origin: top;
  transform-origin: top;
  margin-bottom: -100px
}

#nav-primary .dropdown-toggle.active + .toggleable .menu-item {
  -webkit-transform: perspective(320px) rotateX(0deg);
  transform: perspective(320px) rotateX(0deg);
  margin: 0
}

.menu-item.first {
  border-top: none
}

.menu-link {
  display: block;
  padding: 12px;
  color: #ecf0f1
}

.menu-link:active {
  color: #fbfcfc
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<nav id="nav-primary">
  <button id="menu-main-toggle" class="dropdown-toggle">Menu</button>
  <ul id="menu-main" class="nav toggleable hide">
    <li class="odd first menu-item"><a class="menu-link" href="//localhost:3000/index.php/about/">About</a></li>
    <li class="even menu-item"><a class="menu-link" href="/index.php/category/bahrain/">Bahrain</a></li>
    <li class="odd menu-item parent"><a class="menu-link" href="/index.php/category/information-technology/">Information Technology</a>
    </li>
    <li class="even menu-item"><a class="menu-link" href="/index.php/category/snippets/">Snippets</a></li>
    <li class="odd last menu-item"><a class="menu-link" href="//localhost:3000/index.php/contact/">Contact</a></li>
  </ul>
</nav>

Edit: For all those interested, I completed the effect using box-shadowing here: http://stackoverflow.com/a/38083570/1934402.


    CSS Howto..

    How to achieve a “mini” select style using Bootstrap (or straight CSS)?

    How to use commas in a CSS variable fallback?

    How to get the min-height of the object when its parent is set to display none?

    Liferay: how to avoid rebuilding/redeploying CSS files

    How to convert a 'div' into a dropdown using CSS/Jquery

    How to separate Text and HTML with CSS

    How to change default theme color teal to blue without using custom CSS in materilaize

    How to make JQuery + CSS Verticle Tabs

    How to get css3 ribbon on both sides of element

    I have 3 divs in one row, how do I get the middle div to stay an exact width while the left and right div shrink in as the screen resizes smaller?

    How to restrict Visual Studio 2012.2 from generating .css files in LESS editor?

    How to make a fixed position centered after zooming the whole website out?

    how to setup css value for “-webkit-transform” in the “animate” method? [duplicate]

    How to resize the clockpicker?

    How to disable mask on selected image in the f/ckeditor in webkit, opera browsers?

    How to append text after last css class

    How to make Css transition effect work on Safari and Chrome?

    How Can I Use CSS :after to Add a Glyphicon Element to an Input

    Mobile-Friendly CSS - How to hide a sidebar? [closed]

    How do I use pseudo-classes to select all children except first and last?

    How to define the width of a HTML element dynamically

    How to achieve this layout with div and css?

    How to show “next”, “previous” buttons on an image (on mouseover)?

    How to make an svg masked image compatible with Internet Explorer

    CSS: how to remove the top-gap for sub-menus?

    How do I put a horizontal line/border right in the middle of a table row?

    How To Apply jQuery CSS Selector

    How to change order of elements inside tables?

    How to make background fill or flush to the footer at the bottom of the window

    How do I modify a css element with Jquery after appended with Jquery to a div?