Skip to content

Instantly share code, notes, and snippets.

@Benard
Created May 27, 2014 18:40
Show Gist options
  • Save Benard/8c54fe2cad178fa6fb36 to your computer and use it in GitHub Desktop.
Save Benard/8c54fe2cad178fa6fb36 to your computer and use it in GitHub Desktop.
A Pen by Aiwan.
<div class="container">
<section>
<form id="theForm" class="simform" autocomplete="off">
<div class="simform-inner">
<ol class="questions">
<li>
<span><label for="q1">What's your favorite movie?</label></span>
<input id="q1" name="q1" type="text"/>
</li>
<li>
<span><label for="q2">Where do you live?</label></span>
<input id="q2" name="q2" type="text"/>
</li>
<li>
<span><label for="q3">What time do you got to work?</label></span>
<input id="q3" name="q3" type="text"/>
</li>
<li>
<span><label for="q4">How do you like your veggies?</label></span>
<input id="q4" name="q4" type="text"/>
</li>
<li>
<span><label for="q5">What book inspires you?</label></span>
<input id="q5" name="q5" type="text"/>
</li>
<li>
<span><label for="q6">What's your profession?</label></span>
<input id="q6" name="q6" type="text"/>
</li>
</ol><!-- /questions -->
<button class="submit" type="submit">Send answers</button>
<div class="controls">
<button class="next fa fa-long-arrow-right""></button>
<div class="progress"></div>
<span class="number">
<span class="number-current"></span>
<span class="number-total"></span>
</span>
<span class="error-message"></span>
</div><!-- / controls -->
</div><!-- /simform-inner -->
<span class="final-message"></span>
</form><!-- /simform -->
</section>
</div>
/*!
* classie - class helper functions
* from bonzo https://github.com/ded/bonzo
*
* classie.has( elem, 'my-class' ) -> true/false
* classie.add( elem, 'my-new-class' )
* classie.remove( elem, 'my-unwanted-class' )
* classie.toggle( elem, 'my-class' )
*/
/*jshint browser: true, strict: true, undef: true */
/*global define: false */
( function( window ) {
'use strict';
// class helper functions from bonzo https://github.com/ded/bonzo
function classReg( className ) {
return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
}
// classList support for class management
// altho to be fair, the api sucks because it won't accept multiple classes at once
var hasClass, addClass, removeClass;
if ( 'classList' in document.documentElement ) {
hasClass = function( elem, c ) {
return elem.classList.contains( c );
};
addClass = function( elem, c ) {
elem.classList.add( c );
};
removeClass = function( elem, c ) {
elem.classList.remove( c );
};
}
else {
hasClass = function( elem, c ) {
return classReg( c ).test( elem.className );
};
addClass = function( elem, c ) {
if ( !hasClass( elem, c ) ) {
elem.className = elem.className + ' ' + c;
}
};
removeClass = function( elem, c ) {
elem.className = elem.className.replace( classReg( c ), ' ' );
};
}
function toggleClass( elem, c ) {
var fn = hasClass( elem, c ) ? removeClass : addClass;
fn( elem, c );
}
var classie = {
// full names
hasClass: hasClass,
addClass: addClass,
removeClass: removeClass,
toggleClass: toggleClass,
// short names
has: hasClass,
add: addClass,
remove: removeClass,
toggle: toggleClass
};
// transport
if ( typeof define === 'function' && define.amd ) {
// AMD
define( classie );
} else {
// browser global
window.classie = classie;
}
})( window );
/**
* stepsForm.js v1.0.0
* http://www.codrops.com
*
* Licensed under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright 2014, Codrops
* http://www.codrops.com
*/
;( function( window ) {
'use strict';
var transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
support = { transitions : Modernizr.csstransitions };
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
function stepsForm( el, options ) {
this.el = el;
this.options = extend( {}, this.options );
extend( this.options, options );
this._init();
}
stepsForm.prototype.options = {
onSubmit : function() { return false; }
};
stepsForm.prototype._init = function() {
// current question
this.current = 0;
// questions
this.questions = [].slice.call( this.el.querySelectorAll( 'ol.questions > li' ) );
// total questions
this.questionsCount = this.questions.length;
// show first question
classie.addClass( this.questions[0], 'current' );
// next question control
this.ctrlNext = this.el.querySelector( 'button.next' );
// progress bar
this.progress = this.el.querySelector( 'div.progress' );
// question number status
this.questionStatus = this.el.querySelector( 'span.number' );
// current question placeholder
this.currentNum = this.questionStatus.querySelector( 'span.number-current' );
this.currentNum.innerHTML = Number( this.current + 1 );
// total questions placeholder
this.totalQuestionNum = this.questionStatus.querySelector( 'span.number-total' );
this.totalQuestionNum.innerHTML = this.questionsCount;
// error message
this.error = this.el.querySelector( 'span.error-message' );
// init events
this._initEvents();
};
stepsForm.prototype._initEvents = function() {
var self = this,
// first input
firstElInput = this.questions[ this.current ].querySelector( 'input' ),
// focus
onFocusStartFn = function() {
firstElInput.removeEventListener( 'focus', onFocusStartFn );
classie.addClass( self.ctrlNext, 'show' );
};
// show the next question control first time the input gets focused
firstElInput.addEventListener( 'focus', onFocusStartFn );
// show next question
this.ctrlNext.addEventListener( 'click', function( ev ) {
ev.preventDefault();
self._nextQuestion();
} );
// pressing enter will jump to next question
document.addEventListener( 'keydown', function( ev ) {
var keyCode = ev.keyCode || ev.which;
// enter
if( keyCode === 13 ) {
ev.preventDefault();
self._nextQuestion();
}
} );
// disable tab
this.el.addEventListener( 'keydown', function( ev ) {
var keyCode = ev.keyCode || ev.which;
// tab
if( keyCode === 9 ) {
ev.preventDefault();
}
} );
};
stepsForm.prototype._nextQuestion = function() {
if( !this._validade() ) {
return false;
}
// check if form is filled
if( this.current === this.questionsCount - 1 ) {
this.isFilled = true;
}
// clear any previous error messages
this._clearError();
// current question
var currentQuestion = this.questions[ this.current ];
// increment current question iterator
++this.current;
// update progress bar
this._progress();
if( !this.isFilled ) {
// change the current question number/status
this._updateQuestionNumber();
// add class "show-next" to form element (start animations)
classie.addClass( this.el, 'show-next' );
// remove class "current" from current question and add it to the next one
// current question
var nextQuestion = this.questions[ this.current ];
classie.removeClass( currentQuestion, 'current' );
classie.addClass( nextQuestion, 'current' );
}
// after animation ends, remove class "show-next" from form element and change current question placeholder
var self = this,
onEndTransitionFn = function( ev ) {
if( support.transitions ) {
this.removeEventListener( transEndEventName, onEndTransitionFn );
}
if( self.isFilled ) {
self._submit();
}
else {
classie.removeClass( self.el, 'show-next' );
self.currentNum.innerHTML = self.nextQuestionNum.innerHTML;
self.questionStatus.removeChild( self.nextQuestionNum );
// force the focus on the next input
nextQuestion.querySelector( 'input' ).focus();
}
};
if( support.transitions ) {
this.progress.addEventListener( transEndEventName, onEndTransitionFn );
}
else {
onEndTransitionFn();
}
}
// updates the progress bar by setting its width
stepsForm.prototype._progress = function() {
this.progress.style.width = this.current * ( 100 / this.questionsCount ) + '%';
}
// changes the current question number
stepsForm.prototype._updateQuestionNumber = function() {
// first, create next question number placeholder
this.nextQuestionNum = document.createElement( 'span' );
this.nextQuestionNum.className = 'number-next';
this.nextQuestionNum.innerHTML = Number( this.current + 1 );
// insert it in the DOM
this.questionStatus.appendChild( this.nextQuestionNum );
}
// submits the form
stepsForm.prototype._submit = function() {
this.options.onSubmit( this.el );
}
// TODO (next version..)
// the validation function
stepsForm.prototype._validade = function() {
// current questionВґs input
var input = this.questions[ this.current ].querySelector( 'input' ).value;
if( input === '' ) {
this._showError( 'EMPTYSTR' );
return false;
}
return true;
}
// TODO (next version..)
stepsForm.prototype._showError = function( err ) {
var message = '';
switch( err ) {
case 'EMPTYSTR' :
message = 'Please fill the field before continuing';
break;
case 'INVALIDEMAIL' :
message = 'Please fill a valid email address';
break;
// ...
};
this.error.innerHTML = message;
classie.addClass( this.error, 'show' );
}
// clears/hides the current error message
stepsForm.prototype._clearError = function() {
classie.removeClass( this.error, 'show' );
}
// add to global namespace
window.stepsForm = stepsForm;
})( window );
var theForm = document.getElementById( 'theForm' );
new stepsForm( theForm, {
onSubmit : function( form ) {
// hide form
classie.addClass( theForm.querySelector( '.simform-inner' ), 'hide' );
/*
form.submit()
or
AJAX request (maybe show loading indicator while we don't have an answer..)
*/
// let's just simulate something...
var messageEl = theForm.querySelector( '.final-message' );
messageEl.innerHTML = 'Thank you! We\'ll be in touch.';
classie.addClass( messageEl, 'show' );
}
} );
@import url(http://fonts.googleapis.com/css?family=Lato:400,700,400italic);
.simform {
position: relative;
margin: 0 auto;
padding: 2em 0;
max-width: 860px;
width: 100%;
text-align: left;
font-size: 2.5em;
}
.simform .submit {
display: none;
}
/* Question list style */
.simform ol {
margin: 0;
padding: 0;
list-style: none;
position: relative;
-webkit-transition: height 0.4s;
transition: height 0.4s;
}
.simform ol:before {
content: '';
background-color: rgba(0,0,0,0.1);
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 2.35em;
}
.questions li {
z-index: 100;
position: relative;
visibility: hidden;
height: 0;
-webkit-transition: visibility 0s 0.4s, height 0s 0.4s;
transition: visibility 0s 0.4s, height 0s 0.4s;
}
.questions li.current,
.no-js .questions li {
visibility: visible;
height: auto;
-webkit-transition: none;
transition: none;
}
/* Labels */
.questions li > span {
display: block;
overflow: hidden;
}
.questions li > span label {
display: block;
-webkit-transition: -webkit-transform 0.4s;
transition: transform 0.4s;
-webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
.questions li.current > span label,
.no-js .questions li > span label {
-webkit-transition: none;
transition: none;
-webkit-transform: translateY(0);
transform: translateY(0);
}
.show-next .questions li.current > span label {
-webkit-animation: moveUpFromDown 0.4s both;
animation: moveUpFromDown 0.4s both;
}
@-webkit-keyframes moveUpFromDown {
from { -webkit-transform: translateY(100%); }
to { -webkit-transform: translateY(0); }
}
@keyframes moveUpFromDown {
from { transform: translateY(100%); }
to { transform: translateY(0); }
}
/* Input field */
.questions input {
display: block;
margin: 0.3em 0 0 0;
padding: 0.5em 1em 0.5em 0.7em;
width: calc(100% - 2em);
border: none;
background: transparent;
color: rgba(0,0,0,0.8);
font-size: 1em;
line-height: 1;
opacity: 0;
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
}
.questions .current input,
.no-js .questions input {
opacity: 1;
}
.questions input:focus,
.simform button:focus {
outline: none;
}
/* Next question button */
.next {
position: absolute;
right: 0;
bottom: 2.15em; /* padding-bottom of form plus progress bar height */
display: block;
padding: 0;
width: 2em;
height: 2em;
border: none;
background: none;
color: rgba(0,0,0,0.4);
text-align: center;
opacity: 0;
z-index: 100;
cursor: pointer;
-webkit-transition: -webkit-transform 0.3s, opacity 0.3s;
transition: transform 0.3s, opacity 0.3s;
-webkit-transform: translateX(-20%);
transform: translateX(-20%);
pointer-events: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
.next:hover {
color: rgba(0,0,0,0.5);
}
.next::after {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
text-transform: none;
font-weight: normal;
font-style: normal;
font-variant: normal;
line-height: 2;
speak: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.next.show {
opacity: 1;
-webkit-transform: translateX(0);
transform: translateX(0);
pointer-events: auto;
}
/* Progress bar */
.simform .progress {
width: 0%;
height: 0.15em;
background: rgba(0,0,0,0.3);
-webkit-transition: width 0.4s ease-in-out;
transition: width 0.4s ease-in-out;
}
.simform .progress::before {
position: absolute;
top: auto;
width: 100%;
height: inherit;
background: rgba(0,0,0,0.05);
content: '';
}
/* Number indicator */
.simform .number {
position: absolute;
right: 0;
overflow: hidden;
margin: 0.4em 0;
width: 3em;
font-weight: 700;
font-size: 0.4em;
}
.simform .number:after {
position: absolute;
left: 50%;
content: '/';
opacity: 0.4;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.simform .number span {
float: right;
width: 40%;
text-align: center;
}
.simform .number .number-current {
float: left;
}
.simform .number-next {
position: absolute;
left: 0;
}
.simform.show-next .number-current {
-webkit-transition: -webkit-transform 0.4s;
transition: transform 0.4s;
-webkit-transform: translateY(-100%);
transform: translateY(-100%);
}
.simform.show-next .number-next {
-webkit-animation: moveUpFromDown 0.4s both;
animation: moveUpFromDown 0.4s both;
}
/* Error and final message */
.simform .error-message,
.simform .final-message {
position: absolute;
visibility: hidden;
opacity: 0;
-webkit-transition: opacity 0.4s;
transition: opacity 0.4s;
}
.simform .error-message {
padding: 0.4em 3.5em 0 0;
width: 100%;
color: rgba(0,0,0,0.7);
font-style: italic;
font-size: 0.4em;
}
.final-message {
top: 50%;
left: 0;
padding: 0.5em;
width: 100%;
text-align: center;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
.error-message.show,
.final-message.show {
visibility: visible;
opacity: 1;
}
.final-message.show {
-webkit-transition-delay: 0.5s;
transition-delay: 0.5s;
}
/* Final hiding of form / showing message */
.simform-inner.hide {
visibility: hidden;
opacity: 0;
-webkit-transition: opacity 0.3s, visibility 0s 0.3s;
transition: opacity 0.3s, visibility 0s 0.3s;
}
/* No JS Fallback */
.no-js .simform {
font-size: 1.75em;
}
.no-js .questions li {
padding: 0 0 2em;
}
.no-js .simform .submit {
display: block;
float: right;
padding: 10px 20px;
border: none;
background: rgba(0,0,0,0.3);
color: rgba(0,0,0,0.4);
}
.no-js .simform .controls {
display: none;
}
/* Remove IE clear cross */
input[type=text]::-ms-clear {
display: none;
}
/* Adjust form for smaller screens */
@media screen and (max-width: 44.75em) {
.simform {
font-size: 1.8em;
}
}
@media screen and (max-width: 33.5625em) {
.simform {
font-size: 1.2em;
}
}
*, *:after, *:before { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; }
.clearfix:before, .clearfix:after { content: ''; display: table; }
.clearfix:after { clear: both; }
body {
background: #26C281;
color: rgba(0,0,0,0.45);
font-size: 100%;
line-height: 1.25;
font-family: 'Lato', Arial, sans-serif;
}
a {
color: rgba(0,0,0,0.25);
text-decoration: none;
outline: none;
}
a:hover, a:focus {
color: rgba(0,0,0,0.6);
}
.codrops-header {
margin: 0 auto;
padding: 3em 1em;
text-align: center;
color: rgba(0,0,0,0.35);
}
.codrops-header h1 {
margin: 0;
font-weight: 400;
font-size: 2.5em;
}
.codrops-header h1 span {
display: block;
padding: 0 0 0.6em 0.1em;
font-size: 0.6em;
opacity: 0.7;
}
/* To Navigation Style */
.codrops-top {
width: 100%;
text-transform: uppercase;
font-weight: 700;
font-size: 0.69em;
line-height: 2.2;
}
.codrops-top a {
display: inline-block;
padding: 0 1em;
text-decoration: none;
letter-spacing: 1px;
}
.codrops-top span.right {
float: right;
}
.codrops-top span.right a {
display: block;
float: left;
}
section {
padding: 5em 2em 10em;
background: #2dcb89;
text-align: center;
}
section.related {
padding: 3em 1em 4em;
background: #465650;
color: rgba(0,0,0,0.4);
font-size: 1.5em;
}
.related > a {
max-width: 80%;
border: 2px solid rgba(0,0,0,0.3);
display: inline-block;
text-align: center;
margin: 20px 10px;
padding: 25px;
-webkit-transition: color 0.3s, border-color 0.3s;
transition: color 0.3s, border-color 0.3s;
}
.related a:hover {
border-color: rgba(0,0,0,0.6);
}
.related a img {
max-width: 100%;
opacity: 0.4;
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
}
.related a:hover img,
.related a:active img {
opacity: 1;
}
.related a h3 {
margin: 0;
padding: 0.5em 0 0.3em;
max-width: 300px;
font-weight: 400;
font-size: 0.75em;
text-align: left;
}
@media screen and (max-width: 44.75em) {
section { padding: 1em 2em; }
}
@media screen and (max-width: 25em) {
.codrops-header { font-size: 0.8em; }
section.related { font-size: 1.2em; }
.codrops-icon span { display: none; }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment