Simplistic, single input view form.
http://tympanus.net/codrops/2014/04/01/minimal-form-interface/
Forked from Code Stuff's Pen Minimal Form Interface.
A Pen by Seth Calkins on CodePen.
<div class="container"> | |
<header class="codrops-header"> | |
<h1>Minimal Form Interface <span>Simplistic, single input view form</span></h1> | |
</header> | |
<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> |
Simplistic, single input view form.
http://tympanus.net/codrops/2014/04/01/minimal-form-interface/
Forked from Code Stuff's Pen Minimal Form Interface.
A Pen by Seth Calkins on CodePen.
/*! | |
* 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; } | |
} |