nucliweb
12/22/2013 - 4:19 PM

CSS States

CSS States

{"view":"split-vertical","fontsize":"100","seethrough":"","prefixfree":"1","page":"all"}
<div class="wrapper">
	<h1>Maintaining CSS Style States using "Infinite" Transition Delays</h1>
	
	<div class="device">
		<button class="up"></button>
		<button class="down"></button>
		<button class="left"></buton>
		<button class="right"></button>
	
		<div class="screen">
			<div class="char"></div>
			<div class="overlay"></div>
		</div>
	</div>
	
	<section>
	<p>
		This demo is <strong>completely JavaScript-free</strong>. 
		Feel free to move the character around with the D-pad, and notice how it always
		keeps its position after you stop moving. 
	</p>
	<p>
		This is made possible by using a virtually infinite transition delay, so that the
		CSS rules never return to their default state. The character will always be stuck 
		in a transition and only moves when you hold down a button.
	</p>
	
	<p>
		I've written a 
	<a target="_blank" href="http://joelb.me/blog/2012/maintaining-css-style-states-using-infinite-transition-delays/"> blog post </a> explanining how 
		this all works, but please keep in mind that things like this should ideally be handled 
		with Javascript. After all, this is a dirty hack, not a CSS feature.
	</p>
	</section>
	
	<small>Credit goes to to <a target="_blank" href="http://www.tekepon.net/fsm/">First Seed Material</a> for the 
	character sprite, and <a target="_blank" href="http://vxresource.wordpress.com/2010/03/17/the-real-macks-tileset/">
	Mack</a> for the map tileset.
	 </small>
</div>
/* CSS States */
body {
	background: url(http://dabblet.com/img/noise.png);
	background-color: #F5F2F0;
	font-family: Georgia, serif;
	font-size: 18px;
	line-height: 1.6em;
	text-shadow: 0 2px 0 white;
	color: #222;
}
.wrapper {
	width: 900px;
	margin: 70px auto; 
}
h1 {
	font-family: Helvetica, Arial, sans-serif;
	text-align: center;
	font-size: 1.6em;
}
a {
	text-decoration: none;
	color: #B46919;
}
a:visited {
	color: #834B0F;
}
a:hover {
	color: #E9A051;
}
.device {
	display: inline-block;
	position: relative;
	background:#AD0F0F;
	width: 230px;
	height: 450px;
	padding: 20px 15px;
	margin: 20px;
	border-radius: 20px;
	border: 1px solid #410707;
	border-bottom-width: 8px;
	box-shadow: 0 2px 5px rgba(0,0,0,0.7),
		    inset 0 0 10px rgba(255,255,255,0.5),
		    inset 0 2px 2px rgba(255,255,255,0.25);
}
section {
	display: inline-block;
	vertical-align: top;
	padding: 30px;
	width: 500px;

}
small {
	display: block;
	margin-top: 20px;
	opacity: 0.3;
	text-align: center;
	padding: 
	20px;
	transition: opacity 0.5s;
}
small:hover {
	opacity: 1;
}
.up, .down, .left, .right {
	position: absolute;
	z-index: 1001;
	margin-left: 50%;
	font-size: 40px;
	width: 50px;
	height: 50px;
	background: #FFA03A;
	border: 1px solid #915515;
	box-shadow: 0 3px 0 #52300E,
		    inset 0 0 10px rgba(255,255,255,0.3);

	appearance: none;
	border-radius: 50px;
	cursor: pointer;
}


.up:active, .down:active, .left:active, .right:active {
	margin-top: 3px;
	box-shadow: inset 0 1px 1px rgba(0,0,0,0.3);
}

.up:before, .down:before, .left:before, .right:before {
	display: block;
	position: absolute;
	content: "";
	width: 15px;
	height: 15px;
	border-radius: 15px;
	background: #E4923D;
	box-shadow: 0 2px 2px rgba(255,255,255,0.25),
		    inset 0 1px 0 rgba(0,0,0,0.5);

}

.up:after, .down:after, .left:after, .right:after {
	display: block;
	position: absolute;
	content: "";
	top: -5px;
	left: -6px;
	width: 60px;
	height: 60px;
	border-radius: 60px;
	box-shadow: 0 2px 2px rgba(255,255,255,0.25),
		    inset 0 2px 2px rgba(0,0,0,0.5);
}

.up:active:after, .down:active:after, .left:active:after, .right:active:after {
	top: -8px;
}

.up {
	top: 300px;
	left: -25px;	
}
.up:before {
	top: 5px;
	left: 17px;
}
.down {
	top: 400px;
	left: -25px;
}
.down:before {
	bottom: 5px;
	left: 17px;
}
.left {
	top: 350px;
	left: -75px;
}
.left:before {
	top: 17px;
	left: 5px;
}

.right {
	top: 350px;
	left: 25px;
}
.right:before {
	top: 17px;
	right: 5px;
}

.up:active ~ .screen .char, .down:active ~ .screen .char, .left:active ~ .screen .char, .right:active ~ .screen .char {
	transition: margin-top 2s linear, 
	            margin-left 2s linear;          
}

.up:active ~ .screen .char {	
	margin-top: -84px;
	background-position: 0 -144px;
	animation: walk-up 0.65s infinite;	
}

.down:active ~ .screen .char {
	margin-top: 90px;
	background-position: 0 0;
	animation: walk-down 0.65s infinite;
}

.left:active ~ .screen .char {	
	margin-left: -88px;
	background-position: 0 -48px;
	animation: walk-left 0.65s infinite;
}

.right:active ~ .screen .char {
	margin-left: 88px;
	background-position: 0 -96px;
	animation: walk-right 0.65s infinite;
}

.screen {
	position: relative;
	margin: 0 auto;
	padding: 128px 112px;
	box-sizing: border-box;
	width: 224px;
	height: 256px;
	overflow:hidden;
	box-shadow: 0 0 20px rgba(255,255,255,0.25),
		    0 2px 1px rgba(255,255,255,0.15);
	background: url("http://joelb.me/extassets/sprites/home-layer-1.png") no-repeat;
}

.overlay {
	position: absolute;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	background: url("http://joelb.me/extassets/sprites/home-layer-2.png") no-repeat;
	box-shadow: inset 0 0 50px rgba(0,0,0,0.5);
	z-index: 1000;
}

.char {
	position: relative;
	left: -16px;
	background-image: url("http://joelb.me/extassets/sprites/old-man.png");
	background-position: -32px 0;
	width: 32px;
	height: 48px;
	transition-property: margin-top, margin-left, background-position;
	transition-duration: 0;
	transition-delay: 999999s;
	transition-timing-function: linear;
}

@keyframes walk-up {
	0%, 32.99% { background-position: 0 -144px; }
	33%, 65.99% { background-position: 32px -144px; }
	66%, 100% { background-position: -32px -144px; }
}

@keyframes walk-down {
	0%, 32.99% { background-position: 0 0; }
	33%, 65.99% { background-position: 32px 0; }
	66%, 100% { background-position: -32px 0; }
}

@keyframes walk-left {
	0%, 32.99% { background-position: 0 -48px; }
	33%, 65.99% { background-position: 32px -48px; }
	66%, 100% { background-position: -32px -48px; }
}

@keyframes walk-right {
	0%, 32.99% { background-position: 0 -96px; }
	33%, 65.99% { background-position: 32px -96px; }
	66%, 100% { background-position: -32px -96px; }
}