EDIT: THE TRICKS IN THIS THREAD ARE NOW AVAILABLE ON THE WIKI . I'd like to share some cool things I've done with CSS for the Character Sheets (mine and others), and I'm sure other people have accomplished cool things as well. Hopefully, a repository of tricks will be able to make everyone's sheets better! Note: In my sample code that follows, I'm not using character sheet-specific stuff, like naming inputs "attr_*" or prefixing classes with "sheet-". These samples are meant to be illustrative of techniques, not snippets to blindly copy. Each sample comes with a link to a JSFiddle copy, so you can fiddle around with the code and better learn how it works. Styling Checkboxes and Radio Buttons Checkboxes and radio buttons don't like getting changed much. Instead, it can be easier to hide the actual checkbox/radio and put a more cooperative element underneath. For example : <input type="checkbox" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
/* Hide actual radio/checkbox */
input[type="radio"],
input[type="checkbox"]
{
opacity: 0;
width: 16px;
height: 16px;
position: relative;
top: 5px;
left: 6px;
margin: -10px;
cursor: pointer;
z-index: 1;
}
/* Fake radio/checkbox */
input[type="radio"] + span::before,
input[type="checkbox"] + span::before
{
margin-right: 4px;
border: solid 1px #a8a8a8;
line-height: 14px;
text-align: center;
display: inline-block;
vertical-align: middle;
-moz-box-shadow: 0 0 2px #ccc;
-webkit-box-shadow: 0 0 2px #ccc;
box-shadow: 0 0 2px #ccc;
background: #f6f6f6;
background: -moz-radial-gradient(#f6f6f6, #dfdfdf);
background: -webkit-radial-gradient(#f6f6f6, #dfdfdf);
background: -ms-radial-gradient(#f6f6f6, #dfdfdf);
background: -o-radial-gradient(#f6f6f6, #dfdfdf);
background: radial-gradient(#f6f6f6, #dfdfdf);
}
/* Fake radio */
input[type="radio"] + span::before
{
content: "";
width: 12px;
height: 12px;
font-size: 24px;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
input[type="radio"]:checked + span::before
{
content: "•";
}
/* Fake checkbox */
input[type="checkbox"] + span::before
{
content: "";
width: 14px;
height: 14px;
font-size: 12px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
input[type="checkbox"]:checked + span::before
{
content: "✓";
}
The key here is the opacity: 0; set on the actual input, and then the width , height , and content set on the span::before immediately following the input. The checkbox/radio will be on top of the span: invisible, but still clickable. When the checkbox/radio is selected, then, the style on the span::before is changed. Do note that because of the way this is set up, if you do not have a span element immediately following your checkbox/radio button, the checkbox/radio button will not be visible. Alternative Checkboxes You're not restricted to a box with a check on it if you want a binary state (on or off). When styling your checkbox (or radio button!) you can use just about anything. For example : /* Fake checkbox */
input[type="checkbox"] + span::before
{
margin-right: 4px;
line-height: 14px;
text-align: center;
display: inline-block;
vertical-align: middle;
content: "▼";
width: 14px;
height: 14px;
font-size: 12px;
}
input[type="checkbox"]:checked + span::before
{
content: "►";
}
Now, instead of an empty box, or a box with a checkmark, you've got a right-pointing arrow or a down-pointing arrow. You can also use an image instead of a string, such as content: url(' <a href="http://i.imgur.com/90HuQPr.png" rel="nofollow">http://i.imgur.com/90HuQPr.png</a> ') Hide Areas In a similar fashion, you can hide areas on the character sheet based on the checkbox. Instead of the adjacent sibling selector ( + ), you should use the sibling selector ( ~ ). For example : <div>
<input type="checkbox" class="arrow" />
<h4>Stuff and Things</h4>
<div class="body">
<input type="text" placeholder="Name" /><br />
<input type="text" placeholder="Description" />
<input type="number" min="0" max="20" value="0" /><br />
<textarea placeholder="Fulltext"></textarea>
</div>
</div>
<div>
<input type="checkbox" class="arrow" />
<h4>More Stuff</h4>
<div class="body">
<input type="text" placeholder="Name" /><br />
<input type="text" placeholder="Description" />
<input type="number" min="0" max="20" value="0" /><br />
<textarea placeholder="Fulltext"></textarea>
</div>
</div>
<div>
<input type="checkbox" class="arrow" />
<h4>Other Things</h4>
<div class="body">
<input type="text" placeholder="Name" /><br />
<input type="text" placeholder="Description" />
<input type="number" min="0" max="20" value="0" /><br />
<textarea placeholder="Fulltext"></textarea>
</div>
</div>
input.arrow
{
float: left;
}
input.arrow:checked ~ div.body
{
display: none;
}
Whenever one of the checkboxes in this example is checked, the following div becomes hidden. Fill Radio Buttons to the Left This is one I'm particularly proud of; a number of games use a set of bubbles, filled in from left to right, to represent various traits. Radio buttons can only have one selected value, however, and if we used a set of checkboxes, it would be annoying to make the user click each and every one of them to set the character's attribute. Also, a set of checkboxes would make macros extremely ugly: @{Strength_1} * 1 + @{Strength_2} * 1 + ... However, with the radio button styling, we can solve this problem and use a radio button anyway, and only have one value. For example : <input type="radio" name="r" checked="checked" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
<input type="radio" name="r" /><span></span>
/* Hide actual radio */
input[type="radio"]
{
opacity: 0;
width: 16px;
height: 16px;
position: relative;
top: 5px;
left: 6px;
margin: -10px;
cursor: pointer;
z-index: 1;
}
/* Fake radio */
input[type="radio"] + span::before
{
margin-right: 4px;
border: solid 1px #a8a8a8;
line-height: 14px;
text-align: center;
display: inline-block;
vertical-align: middle;
-moz-box-shadow: 0 0 2px #ccc;
-webkit-box-shadow: 0 0 2px #ccc;
box-shadow: 0 0 2px #ccc;
background: #f6f6f6;
background: -moz-radial-gradient(#f6f6f6, #dfdfdf);
background: -webkit-radial-gradient(#f6f6f6, #dfdfdf);
background: -ms-radial-gradient(#f6f6f6, #dfdfdf);
background: -o-radial-gradient(#f6f6f6, #dfdfdf);
background: radial-gradient(#f6f6f6, #dfdfdf);
content: "•";
width: 12px;
height: 12px;
font-size: 24px;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
}
/* Remove dot from all radios _after_ selected one */
input[type="radio"]:checked ~ input[type="radio"] + span::before
{
content: "";
}
Here, all radio buttons are styled by default to appear as though they're checked. The radio buttons after the one that's actually checked then have the dot removed. The result is that the checked radio button and all of the ones to the left are "filled in," while the ones to the left are empty. You can invert this behavior (right of the checked radio are filled, checked and left of checked are empty) by swapping the two content lines. To reverse this behavior (checked radio and right of checked radio are filled, left of checked radio are empty), swap the two content lines and change the last selector to this: input[type="radio"]:checked ~ input[type="radio"] + span::before,
input[type="radio"]:checked + span::before
Note: If no radio button is selected, all of them will appear filled in (or all will appear empty if you've reversed/inverted the CSS). Therefore, it is wise to include checked="checked" on one of the radio buttons. That said, you may desire a "zero" value for the trait in question. I recommend having an extra radio button with value="0" checked="checked" and without the span element immediately following it. This will give you an initial value of 0, your radio button group will appear as intended, and the "zero" value will not show up to the user. Note: All radio buttons which are siblings will be affected by the selection of one of the radios. It is therefore recommended that you wrap the button group in some element, such as span or div. Circular Layouts Some character sheets have rather interesting layouts. Mage: the Ascension , for example, has a pair of traits called Quintessence and Paradox that are both mapped onto a wheel of checkboxes. While I'm not the author of the Mage sheet, I did help get a proper "wheel" look for the Q/P. For example : <div>
<div>
<input type="checkbox" class="wheel wheel9 middle left-1" /><span></span>
<input type="checkbox" class="wheel wheel27 mid-three-eighth left-2" /><span></span>
<input type="checkbox" class="wheel wheel45 mid-quarter left-3" /><span></span>
<input type="checkbox" class="wheel wheel63 mid-eighth left-4" /><span></span>
<input type="checkbox" class="wheel wheel81 top left-5" /><span></span>
<input type="checkbox" class="wheel wheel99 top left-6" /><span></span>
<input type="checkbox" class="wheel wheel117 mid-eighth left-7" /><span></span>
<input type="checkbox" class="wheel wheel135 mid-quarter left-8" /><span></span>
<input type="checkbox" class="wheel wheel153 mid-three-eighth left-9" /><span></span>
<input type="checkbox" class="wheel wheel171 middle left-10" /><span></span>
</div>
<div>
<input type="checkbox" class="wheel wheel171 middle-2 left-1" /><span></span>
<input type="checkbox" class="wheel wheel153 mid-five-eighth left-2" /><span></span>
<input type="checkbox" class="wheel wheel135 mid-three-quarter left-3" /><span></span>
<input type="checkbox" class="wheel wheel117 mid-seven-eighth left-4" /><span></span>
<input type="checkbox" class="wheel wheel99 bottom left-5" /><span></span>
<input type="checkbox" class="wheel wheel81 bottom left-6" /><span></span>
<input type="checkbox" class="wheel wheel63 mid-seven-eighth left-7" /><span></span>
<input type="checkbox" class="wheel wheel45 mid-three-quarter left-8" /><span></span>
<input type="checkbox" class="wheel wheel27 mid-five-eighth left-9" /><span></span>
<input type="checkbox" class="wheel wheel9 middle-2 left-10" /><span></span>
</div>
<div class="marker">•</div>
</div>
/* Hide actual checkbox */
input[type="checkbox"]
{
position: absolute;
opacity: 0;
width: 15px;
height: 15px;
cursor: pointer;
z-index: 1;
margin-top: 6px;
}
/* Fake checkbox */
input[type="checkbox"] + span::before
{
border: solid 1px #a8a8a8;
line-height: 14px;
text-align: middle;
display: inline-block;
vertical-align: middle;
-moz-box-shadow: 0 0 2px #ccc;
-webkit-box-shadow: 0 0 2px #ccc;
box-shadow: 0 0 2px #ccc;
background: #f6f6f6;
background: -moz-radial-gradient(#f6f6f6, #dfdfdf);
background: -webkit-radial-gradient(#f6f6f6, #dfdfdf);
background: -ms-radial-gradient(#f6f6f6, #dfdfdf);
background: -o-radial-gradient(#f6f6f6, #dfdfdf);
background: radial-gradient(#f6f6f6, #dfdfdf);
position: relative;
content: "";
width: 14px;
height: 14px;
font-size: 12px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
}
/* Styles unique to fake checkbox (checked) */
input[type="checkbox"]:checked + span::before
{
content: "✓";
color: #a00;
-moz-box-shadow: 0 0 2px transparent;
-webkit-box-shadow: 0 0 2px transparent;
box-shadow: 0 0 2px transparent;
}
/* Position checkboxes vertically in circle */
input.top { margin-top: 5px; }
input.top + span::before { top: 0px; }
input.mid-eighth { margin-top: 12px; }
input.mid-eighth + span::before { top: 7px; }
input.mid-quarter { margin-top: 27px; }
input.mid-quarter + span::before { top: 22px; }
input.mid-three-eighth { margin-top: 45px; }
input.mid-three-eighth + span::before { top: 40px; }
input.middle { margin-top: 67px; }
input.middle + span::before { top: 62px; }
input.middle-2 { margin-top: 73px; }
input.middle-2 + span::before { top: 68px; }
input.mid-five-eighth { margin-top: 95px; }
input.mid-five-eighth + span::before { top: 90px; }
input.mid-three-quarter { margin-top: 113px; }
input.mid-three-quarter + span::before { top: 108px; }
input.mid-seven-eighth { margin-top: 127px; }
input.mid-seven-eighth + span::before { top: 122px; }
input.bottom { margin-top: 135px; }
input.bottom+ span, input.bottom+ span::before { top: 130px; }
/* Position checkboxes horizontally in circle */
input.left-1 { margin-left: 14px; }
input.left-1 + span::before { left: 14px; }
input.left-2 { margin-left: 1px; }
input.left-2 + span::before { left: 1px; }
input.left-3 { margin-left: -4px; }
input.left-3 + span::before { left: -4px; }
input.left-4 { margin-left: -5px; }
input.left-4 + span::before { left: -5px; }
input.left-5 { margin-left: -2px; }
input.left-5 + span::before { left: -2px; }
input.left-6 { margin-left: 1px; }
input.left-6 + span::before { left: 1px; }
input.left-7 { margin-left: 3px; }
input.left-7 + span::before { left: 3px; }
input.left-8 { margin-left: 2px; }
input.left-8 + span::before { left: 2px; }
input.left-9 { margin-left: -4px; }
input.left-9 + span::before { left: -4px; }
input.left-10 { margin-left: -16px; }
input.left-10 + span::before { left: -16px; }
/* Rotate checkboxes */
input.wheel9,
input.wheel9 + span::before
{
transform:rotate(9deg);
-ms-transform:rotate(9deg);
-webkit-transform:rotate(9deg);
}
input.wheel27,
input.wheel27 + span::before
{
transform:rotate(27deg);
-ms-transform:rotate(27deg);
-webkit-transform:rotate(27deg);
}
input.wheel45,
input.wheel45 + span::before
{
transform:rotate(45deg);
-ms-transform:rotate(45deg);
-webkit-transform:rotate(45deg);
}
input.wheel63,
input.wheel63 + span::before
{
transform:rotate(63deg);
-ms-transform:rotate(63deg);
-webkit-transform:rotate(63deg);
}
input.wheel81,
input.wheel81 + span::before
{
transform:rotate(81deg);
-ms-transform:rotate(81deg);
-webkit-transform:rotate(81deg);
}
input.wheel99,
input.wheel99 + span::before
{
transform:rotate(99deg);
-ms-transform:rotate(99deg);
-webkit-transform:rotate(99deg);
}
input.wheel117,
input.wheel117 + span::before
{
transform:rotate(117deg);
-ms-transform:rotate(117deg);
-webkit-transform:rotate(117deg);
}
input.wheel135,
input.wheel135 + span::before
{
transform:rotate(135deg);
-ms-transform:rotate(135deg);
-webkit-transform:rotate(135deg);
}
input.wheel153,
input.wheel153 + span::before
{
transform:rotate(153deg);
-ms-transform:rotate(153deg);
-webkit-transform:rotate(153deg);
}
input.wheel171,
input.wheel171 + span::before
{
transform:rotate(171deg);
-ms-transform:rotate(171deg);
-webkit-transform:rotate(171deg);
}
div.marker
{
margin: 36px 0px 0px 5px;
font-size: 20px;
}
Getting the exact positioning and rotation was difficult for this one, but it looks darn cool! Share your techniques! What tricky stuff have you done with the HTML & CSS to make your character sheets beautiful?