Profile Material Design Animation

HTML
<body ng-app="mdApp"> <section ng-controller="mdController as Ctrl"> <ul> <li ng-repeat="user in Ctrl.users"> <a ng-click="Ctrl.showProfile($event, $index)"> <div class="imageWrapper"> <img src="{{user.avatar}}" > </div> <div class="info"> <h3>{{user.name}}</h3> <p>{{user.title}}</p> </div> </a> </li> </ul> <div class="profile"> <header ng-style="{backgroundColor:Ctrl.user.color}"> <h3>{{Ctrl.user.name}}</h3> <small>{{Ctrl.user.title}}</small> </header> <ul> <li> <quote>{{Ctrl.user.description}}</quote> </li> <li> <h4>Address:</h4> <p>{{Ctrl.user.address}}</p> </li> <li> <h4>Phone:</h4> <p>{{Ctrl.user.phone}}</p> </li> <li> <h4>Email:</h4> <p>{{Ctrl.user.email}}</p> </li> </ul> <a class="close-button" ng-style="{backgroundColor:Ctrl.user.color}" ng-click="Ctrl.closeProfile($event)">x</a> </div> </section> </body>
SCSS
* { box-sizing: border-box; } body, h3, h4, p, ul { list-style: none; margin: 0; padding: 0; } body { background-color: #232323; color: #333; font-family: 'Roboto', sans-serif; } a { background-color: ghostwhite; cursor: pointer; display: flex; flex-direction: row; padding: 10px; text-decoration: none; &:active { background-color: whitesmoke; } } .floating-item { display: block; padding: 10px; position: fixed; width: 100%; z-index: 2; &, .imageWrapper, .info { position: absolute; transition: all 400ms cubic-bezier(0.785, 0.135, 0.150, 0.860); will-change: left, top; } .imageWrapper { height: 100px; left: -15px; top: -15px; width: 100px; transform: scale(0.5); img { height: 100%; width: 100%; } } .info { left: 70px; right: 0; } h3, p { transition: all 100ms ease-in; } &.centered { .imageWrapper { left: 50%; transform: translate3d(-50%, 0, 0) scale(1); } h3, p { opacity: 0; } } } .imageWrapper { flex-grow: 0; flex-shrink: 0; margin-right: 10px; overflow: hidden; img { border-radius: 50%; height: 50px; width: 50px; } } .info { flex: 1; } .profile { background-color: ghostwhite; bottom: 0; left: 0; opacity: 0; position: absolute; right: 0; top: 0; transition: all 400ms cubic-bezier(0.785, 0.135, 0.150, 0.860); transform: translate3d(0,100%,0); z-index: -1; &.show { opacity: 1; transform: translate3d(0,0,0); } .close-button { bottom: 1em; border: none; border-radius: 50%; box-shadow: 2px 2px 2px rgba(0,0,0,0.3); color: ghostwhite; display: block; font-family: sans-serif; font-weight: 300; height: 40px; position: absolute; right: 1em; text-align: center; width: 40px; } header { background-color: #efefef; height: 200px; overflow: hidden; h3, small { color: ghostwhite; left: 0; position: absolute; text-align: center; width: 100%; } h3 { font-weight: 400; top: 140px; } small { font-weight: 300; top: 165px; } } li { opacity: 0; transition: all 200ms ease-out; transform: translateY(20px); &.show { opacity: 1; transform: translateY(0); } h4 { border-bottom: 1px solid #ddd; font-weight: 400; margin-bottom: .3em; } p { color: #666; font-weight: 300; margin: 0 0 1em 0; } } quote { color: #444; display: block; font-weight: 300; margin-bottom: 1.5em; padding: 0 0 0 2.2em; position: relative; &:before { color: #666; content: '"'; font-size: 4.5em; font-family: 'Passion One', cursive; left: -.3rem; position: absolute; top: -.5rem; } } ul { display: block; font-size: 0.9em; padding: 1.5em; } } section { background-color: whitesmoke; border-radius: 15px; border: 2px solid #999; box-shadow: 4px 4px 3px rgba(0,0,0,0.3); height: 480px; left: 50%; max-width: 100%; overflow: hidden; position: absolute; top: 50%; transform: translate(-50%,-50%); width: 320px; > ul { bottom: 0; left: 0; overflow-y: scroll; -webkit-overflow-scrolling: touch; -webkit-tap-highlight-color: rgba(0, 0, 0, 0); position: absolute; right: 0; top: 0; z-index: 0; &::-webkit-scrollbar { display: none; } li { display: block; border-bottom: 1px solid rgba(0,0,0,0.1); } } }
JAVASCRIPT
(function() { "use strict"; angular.module("mdApp", []); // Api angular.module("mdApp") .factory("MdApi", MdApi); function MdApi($http, $q) { var fn = {}, baseUrl = 'https://gist.githubusercontent.com/ivillamil/e10ca31afcd136a5a7c7/raw/240a27e8c34b5bec7edfa19ee42efad909a85401/demo-users-db.json'; fn.query = query; function query() { return $http.get(baseUrl); } return fn; } // Controller angular.module("mdApp") .controller('mdController', mdController); function mdController(MdApi) { var vm = this, $itemFloat, $itemSelected, $profile = document.querySelector('.profile'), $section = $profile.parentNode, $list = $section.querySelector('ul'), pos, contentSpeed = 50; vm.closeProfile = closeProfile; vm.showProfile = showProfile; vm.user = null; vm.users = []; MdApi.query() .then(function(response) { vm.users = response.data.users; }); function closeProfile(e) { e.preventDefault(); var $profile = document.querySelector('.profile'), $section = $profile.parentNode; _animateInfo(false) .then(function() { setTimeout(function() { $profile.classList.remove('show'); $itemFloat.style.top = pos + 'px'; $itemFloat.classList.remove('centered'); }, contentSpeed * 2); setTimeout(function() { $itemSelected.style.opacity = 1; }, 500); setTimeout(function() { $section.removeChild($itemFloat); }, 600); }); } function showProfile(e, i) { e.preventDefault(); var $selectedItem = e.target.closest('a'), $floatingItem = document.createElement('div'); pos = ($selectedItem.offsetTop - $list.scrollTop); $floatingItem.innerHTML = $selectedItem.innerHTML; $floatingItem.classList.add('floating-item'); $floatingItem.style.height = $selectedItem.offsetHeight + 'px'; $floatingItem.style.top = pos + 'px'; $floatingItem.style['will-change'] = 'left, top'; $section.appendChild($floatingItem); $itemFloat = $floatingItem; $itemSelected = $selectedItem; $selectedItem.style.opacity = 0; vm.user = vm.users[i]; setTimeout(function() { var $imageWrapper = $floatingItem.querySelector('.imageWrapper'); $profile.style.zIndex = 1; $profile.classList.add('show'); $floatingItem.style.top = '50px'; $floatingItem.classList.add('centered'); }, 50); setTimeout(function() { _animateInfo(true); }, 600); } function _animateInfo(show) { return new Promise(function(resolve, reject) { var $contentItems = document.querySelectorAll('.profile li'), i = 0, length = $contentItems.length, arr = []; if (length === 0) return; for (i = 0; i < length; i++) { arr.push($contentItems[i]); } i = show ? 0 : length; arr.forEach(function(item) { var delay = (show ? i++ : i--) * contentSpeed; setTimeout(function() { if (show) item.classList.add('show'); else item.classList.remove('show'); hasFinished(delay); }, delay); }); function hasFinished(d) { if (d === ((length - 1) * contentSpeed)) resolve(); } }); } } }());
Expand for more options Login