cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
              <div class="pageFrame">

  
<div class="pageInfo" style="display:none;">
  <h2>Information About This Crazy Page:</h2>
<div class="pageInfoPort">This page is a crazy experiment where I want
  to break of the words in a paragraph into<br>
  separate <b>&lt;span&gt;</b> blocks for each letter.
  And, have each letter absolutely positioned so that<br>
  the letters appear on the page just as if these span blocks
  did <i>not</i> exist!<br>&nbsp;<br>
  Why? I have this nutzo idea of making it so that by using
  CSS Animation, 
  <br>I can have letters flying in from who-knows-where...
  and come together to form nice looking paragraphs!<br>&nbsp;<br>
  Or, the other way around, the letters in the sentences of
  the paragraphs could be animated <br>to break apart and
  swirl away possibly in some interesting patterns!<br>&nbsp;<br>
  Well, the part to split the paragraphs into spans seems to
  be working okay. 

  <br>&nbsp;<br><b>WOOT!!</b><br>
  I got a basic fly-in and fly-out animation working! <br>
  That worked out much better than I expected it would!
  <br><br>
  Clicking the Fly-In and Fly-Out buttons will show you 
  the animations for those things.
  <br><br>
  Clicking the Auto Play ON button will cause the 
  animations to play over and over again automatically
  (until you click the button again)!
  </div>
  <div class="footerInfo">
    <hr>
    <center>
    <button onclick="hideInfo()">Close Info Panel</button>
    </center>
  </div><!-- footerInfo -->
</div><!-- pageInfo -->

<div class="pageInfoSpacer">.</div>

<span id="runningAnimations"><b>Running Animation</b></span>
<button onclick="flyInStart()" id="btnFlyIn" style="display:none;">Animate Fly-In of David Cooperfield Text</button>

<button onclick="flyOutStart()" id="btnFlyOut">Animate Fly-Out of David Cooperfield Text</button>

<button id="btnAutoPlay" onclick="toggleAutoPlay()">Turn Auto Play ON</button>

<div class="pageContent">
<p>Whether I shall turn out to be the hero of my own life, or whether that station will be held by anybody else, these pages must show. To begin my life with the beginning of my life, I record that I was born (as I have been informed and believe) on a Friday, at twelve o’clock at night. It was remarked that the clock began to strike, and I began to cry, simultaneously.</p>

<p>In consideration of the day and hour of my birth, it was declared by the nurse, and by some sage women in the neighbourhood who had taken a lively interest in me several months before there was any possibility of our becoming personally acquainted, first, that I was destined to be unlucky in life; and secondly, that I was privileged to see ghosts and spirits; both these gifts inevitably attaching, as they believed, to all unlucky infants of either gender, born towards the small hours on a Friday night.</p>
  <p>I need say nothing here, on the first head, because nothing can show better than my history whether that prediction was verified or falsified by the result. On the second branch of the question, I will only remark, that unless I ran through that part of my inheritance while I was still a baby, I have not come into it yet. But I do not at all complain of having been kept out of this property; and if anybody else should be in the present enjoyment of it, he is heartily welcome to keep it.</p>
</div>

<div id="outputTitle">Markup Generated By prepPage() JavaScript function:</div>
<textarea id="markupOutput" rows="18" cols="100"></textarea>

<div style="position:absolute;left:70px;top:10px;">
Sample text derived from:  <a href="http://www.gutenberg.org/files/766/766-h/766-h.htm">David Copperfield Gutenberg.org Text</a><br>
  <span class="specialLink" onclick="showInfo()">Click Here</span> for more information.
</div>

</div><!-- pageFrame-->
<style id="dynamicAnimatedCss_keyframes">
</style>

<style id="dynamicAnimatedCss">
</style>
            
          
!
            
              button {
	background-color:lightblue;
	cursor:pointer;
}

h2 {
  margin-top:2px;
}



.specialLink {
  cursor:pointer;
  color:blue;
  font-weight:bold;
  background-color:yellow;
}

.pageFrame {
	position:absolute;
	left:0px;
	top:0px;
	border: solid red 1px;
	width:700px;
	height:850px;
	overflow:hidden;
}

.pageContent{
  width:600px;
  height:400px;
  padding-left:60px;
  padding-top:50px;
  overflow:hidden;
  background-color:white;
  border:solid gray 1px;
}

.charBit {
  padding:0;
  margin:0;
}

.pageInfo {
  position:absolute;
  top: 30px;
  left: 30px;
  z-index:100;
  width:640px;
  height:400px;
  color:navy;
  background-color:lightyellow;
  border:solid navy 1px;
  padding-top:0px;
  padding-left:20px;
}

.pageInfoPort {
  position:absolute;
  top:35px;
  left:20px;
  width:620px;
  height:300px;
  border:solid silver 1px;
  overflow:scroll;
  padding-left:8px;
  padding-top:8px;
  background-color:white;
}

.footerInfo {
  position:absolute;
  left:20px;
  top:340px;
  width:620px;
}

.pageInfoSpacer {
  margin-left:60px;
  padding-left: 20px;
  padding-top: 20px;
  padding-bottom: 20px;
  margin-top:40px;
  z-index:101;
  color:white;
  display:none;
} 

#runningAnimations {
   display:none;
   color:red;
   position:absolute;
   left:60px;
   top:400px;
}

#outputTitle {
  position:absolute;
  left:760px;
  top:20px;
  display:none;
}

#markupOutput {
  position:absolute;
  top: 40px;
  left:760px;
  color:blue;
  display:none;
}

#btnFlyIn {
  position:absolute;
  left:60px;
  top:400px;
}

#btnFlyOut {
  position:absolute;
  left:60px;
  top:400px;
}

#btnAutoPlay {
  position:absolute;
  left:400px;
  top:400px;
}
            
          
!
            
              	var demo={};

	demo.animationInfo = {};

	prepPageParagraphAnimations(demo.animationInfo);


   /*************************************************************
	*************************************************************/
	function prepPageParagraphAnimations(dta) {
	  var pars = document.getElementsByTagName("P");
	  var nMax = pars.length;
	  var n,par;
  
	  dta.charsByIndex = [];
  
	  for (n=0;n<nMax;n++) {
		par = pars[n];
		prepPar(par, n);
	  } // next n
  
	  procCharsPart1(dta);
	  procCharsPart2(dta);
	} // end of function prepPageParagraphAnimations()


   /*
	  process the content of a paragraph <p> tag
	*/
	function prepPar(par, nParaNum) {
	  var sContent = par.innerHTML;
	  var s = [];
	  var nMax = sContent.length;
	  var n;
	  var sLet;
	  var Q='"';
	  var sId;
  
	  for (n=0;n<nMax;n++) {
	  	sId = "l"+nParaNum+"_"+n;
		sLet = "<span id="+Q+sId+Q;
		sLet = sLet + " class='charBit "+sId+"'";
		sLet = sLet + ">";
		sLet = sLet + sContent.substr(n,1);
		sLet = sLet + "</span>"
		s[s.length] =sLet;
	  } // next n
  
	  par.innerHTML = s.join("");  // swap out the content
	} // end of function prepPar()


   /*************************************************************
	*************************************************************/
	function checkIt() {
	  var pageContent = $(".pageContent")[0];
	  var outputTitle = $("#outputTitle")[0];
	  var markupOutput = $("#markupOutput")[0];

	  markupOutput.value = pageContent.innerHTML;
	  outputTitle.style.display = "block";
	  markupOutput.style.display = "block";
	} // end of function checkIt()


	//https://stackoverflow.com/questions/1480133/how-can-i-get-an-objects-absolute-position-on-the-page-in-javascript
	
   /*************************************************************
	*************************************************************/	
	function cumulativeOffset(element) {
	  var top = 0, left = 0;
	    
		do {
			top += element.offsetTop  || 0;
			left += element.offsetLeft || 0;
			element = element.offsetParent;
		} while(element);

      return {
        top: top,
        left: left
      };
   } // end of function cumulativeOffset()


	/*
		Find position of each character in each paragraph.
		Save info about character into an Object.
		Setup placeholder properties on each of these objects.
		Add to array
	*/
	function procCharsPart1(dta) {
	  var charObj;
	  var chars = $(".charBit");
	  var char;
	  var nMax = chars.length;
	  var n,pos;
	  var nOffDir=0;
	  var nXOffset,nYOffset;
	  var nMinY=10000;
	  var nMaxY=-10000;
	  var nMinX=10000;
	  var nMaxX=-10000;
  
	  for (n=0;n<nMax;n++) {
		char = chars[n];
		charObj = {};
		charObj.char = char.innerHTML;
		charObj.id = char.id;
		pos = cumulativeOffset(char);
		charObj.origTop = pos.top;
		charObj.origLeft = pos.left;
		charObj.animationCss = "";
		charObj.offScreenTop = -1;  // placeholder value
		charObj.offScreenLeft = -1;  // placeholder value
	
		if (pos.top < nMinY) {
			nMinY = pos.top;
		} // end if
	
		if (pos.top > nMaxY) {
			nMaxY = pos.top;
		} // end if    
	
		if (pos.left < nMinX) {
			nMinX = pos.left;
		} // end if   
	
		if (pos.left > nMaxX) {
			nMaxX = pos.left;
		} // end if      
	
		charObj.domElement = char;
		charObj.idx = n;
		dta.charsByIndex[n] = charObj;
	
		char.style.left = pos.left+"px";
		char.style.top = pos.top+"px";
	  } // next n
  
  	  dta.minX = nMinX;
  	  dta.maxX = nMaxX;
  	  dta.minY = nMinY;
  	  dta.maxY = nMaxY;
  	  dta.toggle = 0;
  	  dta.animationTotal = 0;
  	  dta.runningAnimation = -1;  // place holder
  	  dta.lastRunningAnimation = -1;  // place holder
  	  dta.autoMode = false;
  	  
	  // need to do this AFTER finding all the positions!
	  for (n=0;n<nMax;n++) {
		char = chars[n];
		char.style.position = "absolute";
		
		// fires each time an animation ends on this item.
		char.addEventListener("animationend", handleNextAnimation, false);

	  } // next n
	} // end of function procCharsPart1()




	function toggleAutoPlay() {
		var dta = demo.animationInfo;
		var btnAutoPlay = $("#btnAutoPlay")[0];
		var btnFlyIn =  $("#btnFlyIn")[0];
		var btnFlyOut =  $("#btnFlyOut")[0];
		var runningAnimations = $("#runningAnimations")[0];
					
		if (dta.autoMode) {
			dta.autoMode = false;
			btnAutoPlay.innerHTML = "Turn Auto Play ON";
			runningAnimations.style.display = "none";
		} else {
			dta.autoMode = true;
			btnAutoPlay.innerHTML = "Turn Auto Play OFF";
			
			btnFlyIn.style.display = "none";
			btnFlyOut.style.display = "none";
			runningAnimations.innerHTML = "Running Animation Automatically";
			runningAnimations.style.display = "block";
						
			if (dta.runningAnimation === -1) {
				dta.runningAnimation = 1;
				flyOut();
			} // end if			
		} // end if/else
		
	} // end of function toggleAutoPlay()
	
	

	function handleNextAnimation() {
	//	console.log("handleNextAnimation() called. ");
		var dta = demo.animationInfo;
		var runningAnimations = $("#runningAnimations")[0];
		
		
	//	console.log("dta.animationTotal="+dta.animationTotal);
		if (dta.animationTotal > 1) {
			dta.animationTotal = dta.animationTotal - 1;
		} else {
	//		console.log("all of animations finished");
			var btnFlyIn =  $("#btnFlyIn")[0];
			var btnFlyOut =  $("#btnFlyOut")[0];
			var runningAnimations =  $("#runningAnimations")[0];
			var btnAutoPlay = $("#btnAutoPlay")[0];
			
			btnAutoPlay.style.cursor = "pointer";
			
			runningAnimations.style.display = "none";
			
			if (dta.runningAnimation !== -1) {
				dta.lastRunningAnimation = dta.runningAnimation;
			} // end if
			
		//		debugger;
			if (!dta.autoMode) {
				runningAnimations.style.display = "none";
				switch(dta.runningAnimation) {
					case 0:
						btnFlyIn.style.display = "none";
						btnFlyOut.style.display = "block";
						dta.runningAnimation = -1;
						break;
					case 1:
						btnFlyIn.style.display = "block";
						btnFlyOut.style.display = "none";
						dta.runningAnimation = -1;
						break;						
				} // end switch
			} else {
			   // auto mode
			   runningAnimations.innerHTML = "Running Animation Automatically";
			   runningAnimations.style.display = "block";
				switch(dta.runningAnimation) {
					case 0:
						dta.runningAnimation = 1;
						flyOut();
						break;
					case 1:
						dta.runningAnimation = 0;
						flyIn();
						break;						
				} // end switch			   
			} // end if/else
		} // end if
	} // end of function handleNextAnimation()
	
	

	/*
	Using info generated from part 1, generate info to be used in doing CSS
	animations.  This will NOT DO the animation, just build the data that can
	be used to do the animation later on.
	*/
	function procCharsPart2(dta) {
		var nMax = dta.charsByIndex.length;
		var nAngle,x1,y1,x2,y2,nLength;
		
		nLength = dta.maxX;
		
		if (nLength < dta.maxY) {
			nLength = dta.maxY;
		} // end if
		
		// trying to invent a length that will make the point
		// off-screen:
		nLength = nLength * 1.5;  
		
		for (n=0;n<nMax;n++) {
			charObj = dta.charsByIndex[n];
			
			// figure where the character is coming from off screen...
			nAngle = Math.floor(Math.random() * 360); // angle in degrees
			nRadAngle = nAngle * (Math.PI / 180); // angle in radians
			x1 = charObj.origLeft;
			y1 = charObj.origTop;
			x2 = x1 + Math.cos(nRadAngle) * nLength; 
			y2 = y1 + Math.sin(nRadAngle) * nLength; 
			charObj.offScreenLeft = x2;
			charObj.offScreenTop = y2;
			
		} // next n
	} // end of function procCharsPart2()



	function flyInStart() {
		var btnFlyIn = $("#btnFlyIn")[0];
		var runningAnimations = $("#runningAnimations")[0];
		
		runningAnimations.innerHTML ="Running Animation";
		
		btnFlyIn.style.display = "none";
		runningAnimations.style.display = "block";
		
		setTimeout("flyIn()",10);
	} // end of function flyInStart()
	
	
	
	
	function flyIn() {
		var pageInfo = $(".pageInfo")[0];
		var pageInfoSpacer = $(".pageInfoSpacer")[0];
		var dynamicAnimatedCss_keyframes = $("#dynamicAnimatedCss_keyframes")[0];
		var dynamicAnimatedCss = $("#dynamicAnimatedCss")[0];
		var btnAutoPlay = $("#btnAutoPlay")[0];
		
	//	pageInfo.style.display = "none";
	//	pageInfoSpacer.style.display = "block";

		var dta = demo.animationInfo;
		var n;
		var nMax = dta.charsByIndex.length;
		var sAnimationSteps = [];
		var sAnimationClasses = [];
		var sAnimation;
		
		btnAutoPlay.style.cursor = "wait";
		
		dta.runningAnimation = 0; // for fly-in
		dta.animationTotal = 0;
		dta.toggle = dta.toggle + 1;
		if (dta.toggle === 2) {
			dta.toggle = 0;
		} //
		
		for (n=0;n<nMax;n++) {
			charObj = dta.charsByIndex[n];
			ch = charObj.domElement;
			sAnimation = [];
		//	ch.style.left = charObj.offScreenLeft+"px";
		//	ch.style.top = charObj.offScreenTop+"px";
			sAnimation[sAnimation.length] = "@keyframes "+charObj.id+"_ani_"+dta.toggle+" {";
				sAnimation[sAnimation.length] = "from {";
					sAnimation[sAnimation.length] = "left:"+charObj.offScreenLeft+"px;";	
					sAnimation[sAnimation.length] = "top:"+charObj.offScreenTop+"px;";
				sAnimation[sAnimation.length] = "}";
				sAnimation[sAnimation.length] = "to {";
					sAnimation[sAnimation.length] = "left:"+charObj.origLeft+"px;";	
					sAnimation[sAnimation.length] = "top:"+charObj.origTop+"px;";				
				sAnimation[sAnimation.length] = "}";
			sAnimation[sAnimation.length] = "}";
			sAnimationSteps[sAnimationSteps.length] = sAnimation.join("\n");			
			
			// the other part...
			sAnimation = [];
			sAnimation[sAnimation.length] = "."+charObj.id+" {";
				sAnimation[sAnimation.length] = "animation-name:"+charObj.id+"_ani_"+dta.toggle+";";
				
				if (dta.autoMode) {
					sAnimation[sAnimation.length] = "animation-delay: 2s;";
				} // end if
				
				sAnimation[sAnimation.length] = "animation-duration: 2s;";
				sAnimation[sAnimation.length] = "animation-fill-mode: both;";
			sAnimation[sAnimation.length] = "}";
			sAnimationClasses[sAnimationClasses.length] = sAnimation.join("\n");
			dta.animationTotal = dta.animationTotal + 1;
		} // next n
		
		dynamicAnimatedCss.innerHTML = ""; // clear out any previous stuff
		dynamicAnimatedCss_keyframes.innerHTML = sAnimationSteps.join("\n");	
		dynamicAnimatedCss.innerHTML = sAnimationClasses.join("\n");
	} // end of function  flyIn()




	function flyOutStart() {
		var btnFlyOut = $("#btnFlyOut")[0];
		var runningAnimations = $("#runningAnimations")[0];
		
		runningAnimations.innerHTML ="Running Animation";
		btnFlyOut.style.display = "none";
		runningAnimations.style.display = "block";
		
		setTimeout("flyOut()",10);
	} // end of function flyOutStart()



	function flyOut() {
		var pageInfo = $(".pageInfo")[0];
		var pageInfoSpacer = $(".pageInfoSpacer")[0];
		var dynamicAnimatedCss_keyframes = $("#dynamicAnimatedCss_keyframes")[0];
		var dynamicAnimatedCss = $("#dynamicAnimatedCss")[0];
		var btnAutoPlay = $("#btnAutoPlay")[0];
		
//		pageInfo.style.display = "none";
//		pageInfoSpacer.style.display = "block";

		var dta = demo.animationInfo;
		var n;
		var nMax = dta.charsByIndex.length;
		var sAnimationSteps = [];
		var sAnimationClasses = [];
		var sAnimation;
		
		btnAutoPlay.style.cursor = "wait";
		
		dta.runningAnimation = 1; // for fly-out
		dta.animationTotal = 0;
		dta.toggle = dta.toggle + 1;
		if (dta.toggle === 2) {
			dta.toggle = 0;
		} //
		
		for (n=0;n<nMax;n++) {
			charObj = dta.charsByIndex[n];
			ch = charObj.domElement;
			sAnimation = [];
		//	ch.style.left = charObj.offScreenLeft+"px";
		//	ch.style.top = charObj.offScreenTop+"px";
			sAnimation[sAnimation.length] = "@keyframes "+charObj.id+"_ani_"+dta.toggle+" {";
				sAnimation[sAnimation.length] = "from {";
					sAnimation[sAnimation.length] = "left:"+charObj.origLeft+"px;";	//offScreenLeft
					sAnimation[sAnimation.length] = "top:"+charObj.origTop+"px;";      //offScreenTop
				sAnimation[sAnimation.length] = "}";
				sAnimation[sAnimation.length] = "to {";
					sAnimation[sAnimation.length] = "left:"+charObj.offScreenLeft+"px;";	
					sAnimation[sAnimation.length] = "top:"+charObj.offScreenTop+"px;";				
				sAnimation[sAnimation.length] = "}";
			sAnimation[sAnimation.length] = "}";
			sAnimationSteps[sAnimationSteps.length] = sAnimation.join("\n");			
			
			// the other part...
			sAnimation = [];
			sAnimation[sAnimation.length] = "."+charObj.id+" {";
				sAnimation[sAnimation.length] = "animation-name:"+charObj.id+"_ani_"+dta.toggle+";";
				
				if (dta.autoMode) {
					sAnimation[sAnimation.length] = "animation-delay: 2s;";
				} // end if
				
				sAnimation[sAnimation.length] = "animation-duration: 2s;";
				sAnimation[sAnimation.length] = "animation-fill-mode: both;";
			sAnimation[sAnimation.length] = "}";
			sAnimationClasses[sAnimationClasses.length] = sAnimation.join("\n");
			dta.animationTotal = dta.animationTotal + 1;
		} // next n
		
		dynamicAnimatedCss.innerHTML = ""; // clear out any previous stuff
		dynamicAnimatedCss_keyframes.innerHTML = sAnimationSteps.join("\n");	
		dynamicAnimatedCss.innerHTML = sAnimationClasses.join("\n");
	} // end of function 

function showInfo() {
  var pageInfo = $(".pageInfo")[0];
  
  pageInfo.style.display = "block";
} // end of function

function hideInfo() {
  var pageInfo = $(".pageInfo")[0];
  
  pageInfo.style.display = "none";
}
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console