XHTML/CSS Playing Cards

Monday, February 2, 2009 - Jerry Sievert

They say that a picture is worth a thousand words. Unfortunately, it's also worth 1000 bytes or more. In my quest to build the ultimate game of solitaire, I needed cards, 52 of them to be exact. That's a lot of bandwidth for something as simple as cards. I decided to try to fix this problem by making my cards using XHTML and CSS.

Cards are very simple; the combination of a number, a suit and a color depict all cards. This is a fairly simple set of conditions, and is very easy to lay out. A number or letter in the upper left and lower right corners can be used to convey the card value and color helps to convey the suit. A basic card shape can be thrown together very quickly and the color and designation very easily put into the left hand corner.

K
Style:
.black {
 color: black;
}

.card {
 background-color: white;
 width: 80px;
 height: 100px;
 margin: 1em;
 border-style: solid;
 border-width: thin;
 border-color: black;
}

HTML:
<div class="black card">
 K
</div>l
Example 1

Nice, but not quite there. Adding a copy of the designation to the lower right corner helps, but we still have no suit. Using HTML entities, a suit can be added, but adding this much complexity makes layout more challenging. Since the width and the height of the card are already known, it becomes possible to use absolute positioning. To prepare for this, an addition of a position: relative entry to the card class allows for some creative layout.

K
K
Style:
.card {
 background-color: white;
 width: 80px;
 height: 100px;
 margin: 1em;
 border-style: solid;
 border-width: thin;
 border-color: black;
 position: relative;
}

.black {
 color: black;
}

.suit {
 font-size: 3em;
 text-align: center;
 line-height: 100px;
 vertical-align: middle;
}

.bottom {
 position: absolute;
 bottom: 3px;
 right: 3px;
}

.top {
 position: absolute;
 top: 3px;
 left: 3px;
}

.number {
 font-size: 1em;
}
HTML:
K
K
Example 2
%PAGE%

Better, but not quite there. When the cards stack, the suit is lost. Adding the suit to the upper right corner would solve this, but look tacky at best. Instead, a simple opacity trick and more absolute positioning and the cards can stack and look stylish at the same time. For Internet Explorer, using a filter:alpha(opacity) property does a passable job. Finally, adding a subtle curve using partially-implemented CSS3 gives a tiny bit of round to the corners. Since the border-radius property is a mozilla specific property, -moz-border-radius, is used. Additionally, Safari's WebKit supports its own version of the same tag, -webkit-border-radius, but at the time of this writing, the shipping version of Safari did not include it.

A
A
Q
Q
3
3
Style:
.card {
 background-color: white;
 width: 80px;
 height: 100px;
 margin: 1em;
 border-style: solid;
 border-width: thin;
 border-color: black;
 position: relative;
 -moz-border-radius: 5px;
 -webkit-border-radius: 5px;
}

.black {
 color: black;
}

.red {
 color: red;
}

.suit {
 font-size: 3em;
 text-align: center;
 line-height: 100px;
 vertical-align: middle;
}

.bottom {
 position: absolute;
 bottom: 3px;
 right: 3px;
}

.top {
 position: absolute;
 top: 3px;
 left: 3px;
}

.number {
 font-size: 1em;
}

.undersuit {
 font-size: 1.5em;
 z-index: 0;
 opacity: 0.35;
 filter: alpha(opacity=35);
}
HTML:
K
K
Example 3

All in all, a pretty good card. Instead of loading images, a simple page with JavaScript can dynamically create and control cards. Very low transfer time, very light on bandwidth, and a pretty decent looking to boot.