Submit your widget

Sliding up form labels with jquery and CSS3

Created 13 years ago   Views 16180   downloads 3026    Author moronicbajebus
Sliding up form labels with jquery and CSS3
View DemoDownload
289
Share |

A common problem for laying out a labels and their inputs is that the labels dangle out in what appears to be whitespace. Form labels can make a design aesthetically awkward. There are several paths to solving this, but here I will follow the path of placing the label inside the text input element.

efore showing demoing compact-labels, a recap of the issues:

  1. Awkward placement of the label with extra whitespace
  2. The label disappears before the user gets to read it
  3. The label is gone once a value is inputted

The CSS

  .compactlabel-wrapper {
   display: inline-block;
   position: relative;
  }
  
  .compactlabel-wrapper-on {
   z-index: 5;
  }
  
  .compactlabel-wrapper label {
   position: absolute;
   z-index: 4;
  }
  
  .compactlabel-wrapper label.compactlabel-hide {
   z-index: 2;
  }
  
  .compactlabel-wrapper input {
   position: relative;
   z-index: 3;
  }
  
  .compactlabel-label-backing {
   position: absolute;
   z-index: 1;
  }
  
  /* personalized styles */
  .compactlabel-label-backing {
   padding: 2px 3px 4px 3px;
   border-style: solid;
   border-width: 2px 2px 0 2px;
   -moz-border-radius-topleft: 3px;
   -moz-border-radius-topright: 3px;
   background-color: #e0e0e0;
   -webkit-transition: 1s background-color;
   
  }
  
  .compactlabel-wrapper label {
   font-family: "Lucida Sans Unicode", "Lucida Sans", "Lucida Grande", Arial, sans-serif;
   color: #999;
   padding: 4px;
   font-size: 80%;
   font-size: 12px;
  }
  
  
  .compactlabel-wrapper-on,
  .compactlabel-wrapper-on .compactlabel-label-backing {
   -moz-box-shadow: SkyBlue 0 0 5px;
   -webkit-box-shadow: SkyBlue 0 0 5px;
   box-shadow: SkyBlue 0 0 5px;
  }
  
  input[type=text] {
   padding: 3px;
   margin: 0;
   border: solid #ddd 2px;
   background-color: #e0e0e0;
   font-family: "Lucida Sans Unicode", "Lucida Sans", "Lucida Grande", Arial, sans-serif;
   font-size: 12px;
   -moz-border-radius: 1px;
   -webkit-border-radius: 1px;
   border-radius: 1px;
   background-image: -moz-linear-gradient( 270deg, rgba(255,255,255,0), rgba(100,100,100,.15)  );
   -webkit-transition: 1s background-color, 1s border-color;
  }
  
  input[type=text] {
   background-image: -webkit-gradient(linear, left bottom, left top, to(rgba(255,255,255,0)), from(rgba(100,100,100,.15)));
   outline: none;
  }
  
  input[type=text]:hover,
  input[type=text]:focus,
  .compactlabel-wrapper-on input,
  .compactlabel-wrapper-on .compactlabel-label-backing {
   background-color: #fff;
   border-color: #fff;
  }
  
  form {
   position: absolute;
   left: 50%;
   top: 0px;
   bottom: 0;
   width: 360px;
   margin: 0 10px;
   padding: 150px 30px;
   background-color: #555;
   
   /*-moz-box-shadow: 0 0 50px #252525;
   -webkit-box-shadow: 0 0 5px rgba( 0, 0, 0, .5 );
   box-shadow: 0 0 5px rgba( 0, 0, 0, .5 );*/
   border: inset 2px rgba( 99, 99, 99, .02 );
  }
  
  form {
   background-color: rgba( 55, 55, 55, .01 );
   background-image: -moz-linear-gradient( 270deg, rgba( 55, 55, 55, 0 ), rgba( 55, 55, 55, .1 ) ), -moz-repeating-linear-gradient(top left 45deg, rgba(255,255,255,.008), rgba(255,255,255,.008) 15px, rgba(0,0,0,0) 15px, rgba(0,0,0,0) 30px);
  }
  form {
   background: -webkit-gradient(linear, left top, left bottom, from(rgba( 55, 55, 55, 0 )), from(rgba( 55, 55, 55, .1 )));
  }
  
  h1 {
   font-family: "Lucida Sans Unicode", "Lucida Sans", "Lucida Grande";
   font-weight: normal;
   color: #dddde0;
   font-size: 50px;
   text-shadow: -1px -1px 0 #111;
   line-height: 70%;
   position: absolute;
   right: 50%;
   top: 0;
   bottom: 0;
   padding: 130px 10px;
   text-shadow: rgba( 221, 221, 224, .5 ) 0 0 3px;
   border-right: solid rgba( 225,255,255,.02) 1px;
   border-left: solid rgba( 225,255,255,.02) 1px;
   background-color: rgba( 45,45,51,.1);
   margin: 0;
  }
  
  h1 a {
   display: block;
   font-size: 18px;
   color: #dddde0;
   text-decoration: none;
   opacity: .2;
   text-transform: lowercase;
   -webkit-transition: 2s opacity;

  }
  h1 a:hover {
   opacity: 1;
  }
  
  body {
   background-color: #222226;
   background-image: -moz-linear-gradient( 270deg, rgba(255,255,255,.05), rgba(255,255,255,0) );
   background-repeat: no-repeat;

   padding: 0;
   margin: 0;
   min-height: 100%;
   
   min-width: 900px;
   position: relative;
   
   -moz-box-shadow: inset 0 0 40px rgba(57,57,64,.5);

  }
  
  body {
   background-image: -webkit-gradient(linear, left top, left bottom, to(rgba(255,255,255,0)), from(rgba(255,255,255,.05)));
  }

  
  html {
   height: 100%;
  }
  
  #first-name,
  #last-name {
   width: 150px;
  }
  
  #street {
   width: 314px;
  }
  
  #city {
   width: 136px;
  }
  
  #state,
  #zip {
   width: 75px;
  }
  
  p {
   margin: 5px;
  }

Javascript

 jQuery( document ).ready( function( ){
  
  // For all the inputs that are text inputs
  jQuery( 'input:text' ).each( function( ){
   var $this = jQuery( this );
   
   // get the label
   var label = jQuery( 'label[for='+this.id+']' );
   
   // If no label, then return to avoid errors
   if( label.size( ) == 0 ){
    return;
   }
   
   // create wrapper element
   var wrapper = jQuery( '<div class="compactlabel-wrapper"></div>' );
   $this.wrap( wrapper );
   
   // move the label to before the the input
   $this.before( label );
   
   // create label backing
   var backing = jQuery( '<div class="compactlabel-label-backing"></div>' )
    .insertBefore( $this )
    .height( label.height( ) )
    .width( label.width( ) );
   
   // basic style information
   var labelOffset = label.position( ), inputOffset = $this.position( ), labelHeight = label.outerHeight( );
   
   // flag for if on or off
   var isHover = false, isFocus = false;
   
   // a jQuery object of the backing and label to animate both together
   var animatedElements = jQuery( backing.get( ) ).add( label.get( ) );
   
   
   // common functionality for hover on and focus on
   var on = function( event ){
    $this.parent( ).addClass( 'compactlabel-wrapper-on' );
    animatedElements.stop( ).animate( { "top": '-'+(labelHeight - inputOffset.top)+'px' } );
    
   };
   
   // common functionality for hover off and focus off
   var off = function( event ){
    if( isHover || isFocus ){
     return;
    }
    if( inputEmpty ){
     label.removeClass( 'compactlabel-hide' );
    } else {
     label.addClass( 'compactlabel-hide' );
    }
    
    if( !inputEmptyChange ){
     animatedElements.stop( );
    }
    
    animatedElements.animate( 
     { "top": labelOffset.top + 'px' }, 
     function( ){ 
      $this.parent( ).removeClass( 'compactlabel-wrapper-on' ) 
     } );
   };
   
   var onHover = function( event ){
    isHover = true;
    on( event );
   };
   
   var offHover = function( event ){
    isHover = false;
    off( event );
   };
   
   var onFocus = function( event ){
    isFocus = true;
    on( event );
   };
   
   var offFocus = function( event ){
    isFocus = false;
    off( event );
   };
   
   // The pieces for keeping track if the value of the input is empty
   var inputEmpty = false, inputEmptyStart = false, inputEmptyChange = false;
   var checkInputEmpty = function( ){
    inputEmpty = $this.val( ) == '';
   };
   checkInputEmpty( );
   // ID for setTimeout for checkInputEmpty
   var checkInputEmptyFnID = null;
   
   
   
   if( !inputEmpty ){
    label.addClass( 'compactlabel-hide' );
   }
   
   // add the events
   // events to track if the value changed empty state 
   $this.focus( function( ){
    inputEmptyStart = inputEmpty;
    inputEmptyChange = false;
    checkInputEmptyFnID = setInterval( checkInputEmpty, 50 );
   } );
   
   $this.blur( function( ){
    clearInterval( checkInputEmptyFnID );
    checkInputEmpty( );
    inputEmptyChange = inputEmptyStart != inputEmpty;
   } );
   
   // animation events
   $this.focus( onFocus );
   $this.blur( offFocus );
   $this.hover( onHover, offHover );
   label.hover( onHover, offHover );
   
  } );
 } );