Last active
August 29, 2015 14:16
-
-
Save jasonkmccoy/fa3c0fcc8cf6207c2c4f to your computer and use it in GitHub Desktop.
A cool button effect where the button transitions from action to confirmation in a 3D rotation. Made by Hakim El Hattab. http://lab.hakim.se/flipside/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Flipside</title> | |
<meta name="description" content=""> | |
<meta name="author" content="Hakim El Hattab"> | |
<meta name="viewport" content="width=460, user-scalable=no" /> | |
<link href='http://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'> | |
<link href="style.css" rel="stylesheet" type="text/css" /> | |
</head> | |
<body> | |
<div class="btn"> | |
<div class="btn-back"> | |
<p>Are you sure you want to do that?</p> | |
<button class="yes">Yes</button> | |
<button class="no">No</button> | |
</div> | |
<div class="btn-front">Delete</div> | |
</div> | |
<p class="description">Try clicking different sides of the button</p> | |
<script src="script.js"></script> | |
<!-- Third party scripts and sharing UI --> | |
<p class="project-title">Flipside – A button that seamlessly transitions from action to confirmation</p> | |
<div class="credits"> | |
<a href="https://github.com/hakimel/css/tree/master/flipside">Source on GitHub</a> | |
<a href="https://twitter.com/share?text=Flipside%20%E2%80%93%20A%20button%20that%20seamlessly%20transitions%20from%20action%20to%20confirmation&url=http://lab.hakim.se/flipside&via=hakimel&related=hakimel" target="_blank">Tweet this</a> | |
<a href="http://twitter.com/hakimel">Follow @hakimel</a> | |
</div> | |
<style type="text/css" media="screen"> | |
.project-title { | |
position: absolute; | |
left: 25px; | |
bottom: 8px; | |
font-size: 16px; | |
color: #444; | |
} | |
.credits { | |
position: absolute; | |
right: 20px; | |
bottom: 25px; | |
font-size: 15px; | |
z-index: 20; | |
color: #444; | |
vertical-align: middle; | |
} | |
.credits * + * { | |
margin-left: 15px; | |
} | |
.credits a { | |
padding: 8px 10px; | |
color: #444; | |
border: 2px solid #999; | |
text-decoration: none; | |
} | |
.credits a:hover { | |
border-color: #555; | |
color: #222; | |
} | |
@media screen and (max-width: 1040px) { | |
.project-title { | |
display: none; | |
} | |
.credits { | |
width: 100%; | |
left: 0; | |
right: auto; | |
bottom: 0; | |
padding: 30px 0; | |
background: #ddd; | |
text-align: center; | |
} | |
.credits a { | |
display: inline-block; | |
margin-top: 7px; | |
margin-bottom: 7px; | |
} | |
} | |
</style> | |
<script> | |
var _gaq = [['_setAccount', 'UA-15240703-1'], ['_trackPageview']]; | |
(function(d, t) { | |
var g = d.createElement(t), | |
s = d.getElementsByTagName(t)[0]; | |
g.async = true; | |
g.src = ('https:' == location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |
s.parentNode.insertBefore(g, s); | |
})(document, 'script'); | |
</script> | |
<!-- Script.js code. Put in a separate file --> | |
<script> | |
window.onload = function() { | |
var btn = document.querySelector( '.btn' ); | |
var btnFront = btn.querySelector( '.btn-front' ), | |
btnYes = btn.querySelector( '.btn-back .yes' ), | |
btnNo = btn.querySelector( '.btn-back .no' ); | |
btnFront.addEventListener( 'click', function( event ) { | |
var mx = event.clientX - btn.offsetLeft, | |
my = event.clientY - btn.offsetTop; | |
var w = btn.offsetWidth, | |
h = btn.offsetHeight; | |
var directions = [ | |
{ id: 'top', x: w/2, y: 0 }, | |
{ id: 'right', x: w, y: h/2 }, | |
{ id: 'bottom', x: w/2, y: h }, | |
{ id: 'left', x: 0, y: h/2 } | |
]; | |
directions.sort( function( a, b ) { | |
return distance( mx, my, a.x, a.y ) - distance( mx, my, b.x, b.y ); | |
} ); | |
btn.setAttribute( 'data-direction', directions.shift().id ); | |
btn.classList.add( 'is-open' ); | |
} ); | |
btnYes.addEventListener( 'click', function( event ) { | |
btn.classList.remove( 'is-open' ); | |
} ); | |
btnNo.addEventListener( 'click', function( event ) { | |
btn.classList.remove( 'is-open' ); | |
} ); | |
function distance( x1, y1, x2, y2 ) { | |
var dx = x1-x2; | |
var dy = y1-y2; | |
return Math.sqrt( dx*dx + dy*dy ); | |
} | |
}; | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ---- | |
// Sass (v3.4.12) | |
// Compass (v1.0.3) | |
// ---- | |
$transition-duration: 0.8s; | |
$transition-easing: cubic-bezier(0.230, 1.000, 0.320, 1.000); | |
$bounce-easing: cubic-bezier(0.175, 0.885, 0.320, 1.275); | |
$closed-width: 200px; | |
$closed-height: 80px; | |
$opened-width: 400px; | |
$opened-height: 160px; | |
@import url(http://fonts.googleapis.com/css?family=Roboto:400,700); | |
html, body { | |
width: 100%; | |
height: 100%; | |
margin: 0; | |
user-select: none; | |
} | |
body { | |
display: flex; | |
font-family: Roboto, "Helvetica Neue", sans-serif; | |
font-size: 18px; | |
perspective: 1000px; | |
background-color: #f5f5f5; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
} | |
.description { | |
margin-top: 50px; | |
text-align: center; | |
color: #999; | |
transition: opacity 0.3s ease; | |
} | |
.description a { | |
color: #4A9DF6; | |
text-decoration: none; | |
} | |
.btn.is-open ~ .description { | |
opacity: 0; | |
} | |
.btn { | |
display: block; | |
position: relative; | |
width: $closed-width; | |
height: $closed-height; | |
transition: width $transition-duration $transition-easing, | |
height $transition-duration $transition-easing, | |
transform $transition-duration $bounce-easing; | |
transform-style: preserve-3d; | |
transform-origin: 50% 50%; | |
text-align: center; | |
} | |
.btn-front { | |
position: absolute; | |
display: block; | |
width: 100%; | |
height: 100%; | |
line-height: $closed-height; | |
background-color: #F44336; | |
color: #fff; | |
cursor: pointer; | |
backface-visibility: hidden; | |
-webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); | |
transition: background 0.15s ease, | |
line-height $transition-duration $transition-easing; | |
&:hover { | |
background-color: lighten(#F44336, 10%); | |
} | |
} | |
.btn-back { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
background-color: #eee; | |
color: #222; | |
transform: translateZ(-1px) rotateX(180deg); | |
overflow: hidden; | |
transition: box-shadow $transition-duration ease; | |
p { | |
margin-top: 27px; | |
margin-bottom: 25px; | |
} | |
button { | |
padding: 12px 20px; | |
width: 30%; | |
margin: 0 5px; | |
background-color: transparent; | |
border: 0; | |
border-radius: 2px; | |
font-size: 1em; | |
cursor: pointer; | |
-webkit-appearance: none; | |
-webkit-tap-highlight-color: rgba( 0, 0, 0, 0 ); | |
transition: background 0.15s ease; | |
} | |
button:focus { | |
outline: 0; | |
} | |
button.yes { | |
background-color: #2196F3; | |
color: #fff; | |
&:hover { | |
background-color: lighten(#2196F3, 10%); | |
} | |
} | |
button.no { | |
color: #2196F3; | |
&:hover { | |
background-color: #ddd; | |
} | |
} | |
} | |
.btn[data-direction="left"] .btn-back, | |
.btn[data-direction="right"] .btn-back { | |
transform: translateZ(-1px) rotateY(180deg); | |
} | |
.btn.is-open { | |
width: $opened-width; | |
height: $opened-height; | |
.btn-front { | |
pointer-events: none; | |
line-height: $opened-height; | |
} | |
.btn-back { | |
box-shadow: 0 8px 25px rgba(0,0,0,0.4); | |
} | |
} | |
.btn[data-direction="top"].is-open { | |
transform: rotateX(180deg); | |
} | |
.btn[data-direction="right"].is-open { | |
transform: rotateY(180deg); | |
} | |
.btn[data-direction="bottom"].is-open { | |
transform: rotateX(-180deg); | |
} | |
.btn[data-direction="left"].is-open { | |
transform: rotateY(-180deg); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url(http://fonts.googleapis.com/css?family=Roboto:400,700); | |
html, body { | |
width: 100%; | |
height: 100%; | |
margin: 0; | |
user-select: none; | |
} | |
body { | |
display: flex; | |
font-family: Roboto, "Helvetica Neue", sans-serif; | |
font-size: 18px; | |
perspective: 1000px; | |
background-color: #f5f5f5; | |
flex-direction: column; | |
justify-content: center; | |
align-items: center; | |
} | |
.description { | |
margin-top: 50px; | |
text-align: center; | |
color: #999; | |
transition: opacity 0.3s ease; | |
} | |
.description a { | |
color: #4A9DF6; | |
text-decoration: none; | |
} | |
.btn.is-open ~ .description { | |
opacity: 0; | |
} | |
.btn { | |
display: block; | |
position: relative; | |
width: 200px; | |
height: 80px; | |
transition: width 0.8s cubic-bezier(0.23, 1, 0.32, 1), height 0.8s cubic-bezier(0.23, 1, 0.32, 1), transform 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
transform-style: preserve-3d; | |
transform-origin: 50% 50%; | |
text-align: center; | |
} | |
.btn-front { | |
position: absolute; | |
display: block; | |
width: 100%; | |
height: 100%; | |
line-height: 80px; | |
background-color: #F44336; | |
color: #fff; | |
cursor: pointer; | |
backface-visibility: hidden; | |
-webkit-tap-highlight-color: transparent; | |
transition: background 0.15s ease, line-height 0.8s cubic-bezier(0.23, 1, 0.32, 1); | |
} | |
.btn-front:hover { | |
background-color: #f77066; | |
} | |
.btn-back { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
background-color: #eee; | |
color: #222; | |
transform: translateZ(-1px) rotateX(180deg); | |
overflow: hidden; | |
transition: box-shadow 0.8s ease; | |
} | |
.btn-back p { | |
margin-top: 27px; | |
margin-bottom: 25px; | |
} | |
.btn-back button { | |
padding: 12px 20px; | |
width: 30%; | |
margin: 0 5px; | |
background-color: transparent; | |
border: 0; | |
border-radius: 2px; | |
font-size: 1em; | |
cursor: pointer; | |
-webkit-appearance: none; | |
-webkit-tap-highlight-color: transparent; | |
transition: background 0.15s ease; | |
} | |
.btn-back button:focus { | |
outline: 0; | |
} | |
.btn-back button.yes { | |
background-color: #2196F3; | |
color: #fff; | |
} | |
.btn-back button.yes:hover { | |
background-color: #51adf6; | |
} | |
.btn-back button.no { | |
color: #2196F3; | |
} | |
.btn-back button.no:hover { | |
background-color: #ddd; | |
} | |
.btn[data-direction="left"] .btn-back, | |
.btn[data-direction="right"] .btn-back { | |
transform: translateZ(-1px) rotateY(180deg); | |
} | |
.btn.is-open { | |
width: 400px; | |
height: 160px; | |
} | |
.btn.is-open .btn-front { | |
pointer-events: none; | |
line-height: 160px; | |
} | |
.btn.is-open .btn-back { | |
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4); | |
} | |
.btn[data-direction="top"].is-open { | |
transform: rotateX(180deg); | |
} | |
.btn[data-direction="right"].is-open { | |
transform: rotateY(180deg); | |
} | |
.btn[data-direction="bottom"].is-open { | |
transform: rotateX(-180deg); | |
} | |
.btn[data-direction="left"].is-open { | |
transform: rotateY(-180deg); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.onload = function() { | |
var btn = document.querySelector( '.btn' ); | |
var btnFront = btn.querySelector( '.btn-front' ), | |
btnYes = btn.querySelector( '.btn-back .yes' ), | |
btnNo = btn.querySelector( '.btn-back .no' ); | |
btnFront.addEventListener( 'click', function( event ) { | |
var mx = event.clientX - btn.offsetLeft, | |
my = event.clientY - btn.offsetTop; | |
var w = btn.offsetWidth, | |
h = btn.offsetHeight; | |
var directions = [ | |
{ id: 'top', x: w/2, y: 0 }, | |
{ id: 'right', x: w, y: h/2 }, | |
{ id: 'bottom', x: w/2, y: h }, | |
{ id: 'left', x: 0, y: h/2 } | |
]; | |
directions.sort( function( a, b ) { | |
return distance( mx, my, a.x, a.y ) - distance( mx, my, b.x, b.y ); | |
} ); | |
btn.setAttribute( 'data-direction', directions.shift().id ); | |
btn.classList.add( 'is-open' ); | |
} ); | |
btnYes.addEventListener( 'click', function( event ) { | |
btn.classList.remove( 'is-open' ); | |
} ); | |
btnNo.addEventListener( 'click', function( event ) { | |
btn.classList.remove( 'is-open' ); | |
} ); | |
function distance( x1, y1, x2, y2 ) { | |
var dx = x1-x2; | |
var dy = y1-y2; | |
return Math.sqrt( dx*dx + dy*dy ); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Flipside</title> | |
<meta name="description" content=""> | |
<meta name="author" content="Hakim El Hattab"> | |
<meta name="viewport" content="width=460, user-scalable=no" /> | |
<link href='http://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'> | |
<link href="style.css" rel="stylesheet" type="text/css" /> | |
</head> | |
<body> | |
<div class="btn"> | |
<div class="btn-back"> | |
<p>Are you sure you want to do that?</p> | |
<button class="yes">Yes</button> | |
<button class="no">No</button> | |
</div> | |
<div class="btn-front">Delete</div> | |
</div> | |
<p class="description">Try clicking different sides of the button</p> | |
<script src="script.js"></script> | |
<!-- Third party scripts and sharing UI --> | |
<p class="project-title">Flipside – A button that seamlessly transitions from action to confirmation</p> | |
<div class="credits"> | |
<a href="https://github.com/hakimel/css/tree/master/flipside">Source on GitHub</a> | |
<a href="https://twitter.com/share?text=Flipside%20%E2%80%93%20A%20button%20that%20seamlessly%20transitions%20from%20action%20to%20confirmation&url=http://lab.hakim.se/flipside&via=hakimel&related=hakimel" target="_blank">Tweet this</a> | |
<a href="http://twitter.com/hakimel">Follow @hakimel</a> | |
</div> | |
<style type="text/css" media="screen"> | |
.project-title { | |
position: absolute; | |
left: 25px; | |
bottom: 8px; | |
font-size: 16px; | |
color: #444; | |
} | |
.credits { | |
position: absolute; | |
right: 20px; | |
bottom: 25px; | |
font-size: 15px; | |
z-index: 20; | |
color: #444; | |
vertical-align: middle; | |
} | |
.credits * + * { | |
margin-left: 15px; | |
} | |
.credits a { | |
padding: 8px 10px; | |
color: #444; | |
border: 2px solid #999; | |
text-decoration: none; | |
} | |
.credits a:hover { | |
border-color: #555; | |
color: #222; | |
} | |
@media screen and (max-width: 1040px) { | |
.project-title { | |
display: none; | |
} | |
.credits { | |
width: 100%; | |
left: 0; | |
right: auto; | |
bottom: 0; | |
padding: 30px 0; | |
background: #ddd; | |
text-align: center; | |
} | |
.credits a { | |
display: inline-block; | |
margin-top: 7px; | |
margin-bottom: 7px; | |
} | |
} | |
</style> | |
<script> | |
var _gaq = [['_setAccount', 'UA-15240703-1'], ['_trackPageview']]; | |
(function(d, t) { | |
var g = d.createElement(t), | |
s = d.getElementsByTagName(t)[0]; | |
g.async = true; | |
g.src = ('https:' == location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |
s.parentNode.insertBefore(g, s); | |
})(document, 'script'); | |
</script> | |
<!-- Script.js code. Put in a separate file --> | |
<script> | |
window.onload = function() { | |
var btn = document.querySelector( '.btn' ); | |
var btnFront = btn.querySelector( '.btn-front' ), | |
btnYes = btn.querySelector( '.btn-back .yes' ), | |
btnNo = btn.querySelector( '.btn-back .no' ); | |
btnFront.addEventListener( 'click', function( event ) { | |
var mx = event.clientX - btn.offsetLeft, | |
my = event.clientY - btn.offsetTop; | |
var w = btn.offsetWidth, | |
h = btn.offsetHeight; | |
var directions = [ | |
{ id: 'top', x: w/2, y: 0 }, | |
{ id: 'right', x: w, y: h/2 }, | |
{ id: 'bottom', x: w/2, y: h }, | |
{ id: 'left', x: 0, y: h/2 } | |
]; | |
directions.sort( function( a, b ) { | |
return distance( mx, my, a.x, a.y ) - distance( mx, my, b.x, b.y ); | |
} ); | |
btn.setAttribute( 'data-direction', directions.shift().id ); | |
btn.classList.add( 'is-open' ); | |
} ); | |
btnYes.addEventListener( 'click', function( event ) { | |
btn.classList.remove( 'is-open' ); | |
} ); | |
btnNo.addEventListener( 'click', function( event ) { | |
btn.classList.remove( 'is-open' ); | |
} ); | |
function distance( x1, y1, x2, y2 ) { | |
var dx = x1-x2; | |
var dy = y1-y2; | |
return Math.sqrt( dx*dx + dy*dy ); | |
} | |
}; | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment