Learning CSS and HTML can be daunting. And yet, if you want to [[Building Character Sheets|create a character sheet]] for Roll20, both are required.

Learning CSS and HTML can be daunting. And yet, if you want to [[Building Character Sheets|create a character sheet]] for Roll20, both are required.

Line 4:

Line 6:

Many of these tips also include links to a live demo on [http://jsfiddle.net JSFiddle], so you can see them in action.

Many of these tips also include links to a live demo on [http://jsfiddle.net JSFiddle], so you can see them in action.

+

+

== Show/Hide Areas ==

+

[[File:Charsheet-show-hide-checkbox.gif|500px|thumbnail|right]]

+

[https://jsfiddle.net/1kt28rhL/ Live Demo]

+

+

You can show or hide areas on the character sheet based on the state of a checkbox. Instead of the adjacent sibling selector (<code>+</code>) used by [[#Styling Checkboxes and Radio Buttons|custom checkboxes]], you should use the sibling selector (<code>~</code>).

+

+

On the 'toggle-show' checkbox, the following 'body' is hidden when the toggle is not checked.

+

+

On the 'toggle-hide' checkbox, the following 'body' is hidden when the toggle is checked.

+

<pre data-language="html" style="margin-bottom: 5px">

+

<div class="columns">

+

<div>

+

<input type="checkbox" class="toggle-show" />

+

<span>Show</span>

+

<div class="body">You found me!</div>

+

</div>

+

<div>

+

<input type="checkbox" class="toggle-hide" />

+

<span>Hide</span>

+

<div class="body">Hey, a little privacy here?!</div>

+

</div>

+

</div>

+

</pre>

+

<pre data-language="css" style="margin-top: 5px">

+

.columns {

+

display: flex;

+

justify-content: space-between;

+

width: 400px;

+

}

+

.columns > * {

+

flex: 1;

+

}

+

+

input.toggle-show:not(:checked) ~ div.body,

+

input.toggle-hide:checked ~ div.body {

+

display: none;

+

}

+

</pre>

+

+

=== Swap Visible Areas ===

+

[http://jsfiddle.net/yodb4b5w/ Live Demo]

+

+

You can apply the [[#Hide Areas|hide areas]] logic to multiple elements based on the same checkbox, and get swappable behavior:

+

<pre data-language="html" style="margin-bottom:5px"><div>

+

<input type="checkbox" class="sheet-block-switch">

+

<div class="sheet-block-a">

+

Lorem ipsum dolor sit amet

+

</div>

+

<div class="sheet-block-b">

+

consectetur adipiscing elit

+

</div>

+

</div></pre>

+

<pre data-language="css" style="margin-top:5px">.sheet-block-a,

+

.sheet-block-switch:checked ~ .sheet-block-b {

+

display: block;

+

}

+

+

.sheet-block-b,

+

.sheet-block-switch:checked ~ .sheet-block-a {

+

display: none;

+

}</pre>

+

+

=== Tabs ===

+

[[File:Tabs-example.gif|500px|thumbnail|right]]

+

May paper-versions of character sheets have more than one page, and among the best ways to implement this in Roll20 sheets is to create tabs for each page, swapping the visible area with some form of buttons. The following examples are the main two ways this can be done, where the first one is more streamlined than the older example, and is using much more of an modern approach, leading to less problems on older/less used browsers.

+

+

'''Button-based tabs'''

+

+

This is a short and simple example of implementing tabs on a character sheet, created by [https://app.roll20.net/forum/post/7879593/tabs-on-your-custom-character-sheet/?pageforid=7885202#post-7885202 Finderski & GiGs].

'''Note:''' This example/method of creating tabs on a character sheet does not work out of the box, contains lots of unnecessary code, and is far less intuitive than the new tab example. This example is generally not recommended to use, but is left here just for the sake of continuity, and those who might need troubleshoot their implementation. [https://github.com/Roll20/roll20-character-sheets/tree/master/Ambition_Avarice Ambition & Avarice] and [https://github.com/Roll20/roll20-character-sheets/tree/master/Hc%20Svnt%20Dracones%20Second%20Edition Hc Svnt Dracones 2E] are two sheets that base their tabs on this example, and bot needed manual adjustment on at least the position of the tabs to actually work.

+

+

{| role="presentation" class="wikitable mw-collapsible mw-collapsed"

+

| Old Tab example(Doesn't work as-is, lots of redundant code, not intuitive)

+

|-

+

|

+

[http://jsfiddle.net/z866duoa/ Live demo]

+

A tabbed layout is essentially an extension of hidden areas, using radio inputs instead of checkbox inputs.

The key to take away from this is that we have a set of radio buttons which are '''siblings''' to the divs that contain each tab's content. Then, we hide all of the tabs' content and use the sibling selector along with the <code>:checked</code> property to show the tab content associated with that particular radio button.

+

+

The rest of this example shows off means to make your tabs look pretty, such as using <code>content: attr(title)</code> to set the text of the tab, giving them colors and borders, and even making certain tabs different from the others in some fashion.

+

|}

== Four Ways to Use an Attribute ==

== Four Ways to Use an Attribute ==

Line 35:

Line 263:

=== Attribute-Backed &lt;span&gt;s ===

=== Attribute-Backed &lt;span&gt;s ===

−

A <code>&lt;span&gt;</code> element can be given an "attr_" name, just like one of the form elements, above. This will cause the span to behave similarly to a readonly field in that the user cannot modify it directly, and sheet worker scripts have no trouble doing so. There are two main differences with an attribute backed span; 1) the default styling: the span will look just like the surrounding text, and 2) when using attribute backed spans in a repeating section, you should always make a hidden input version of the attribute as attribute backed spans in repeating sections cannot be called without the full repeating section syntax (e.g. @{repeating_SECTIONNAME_$X_attribute_name}).

+

A <code>&lt;span&gt;</code> element can be given an "attr_" name, just like one of the form elements, above. This will cause the span to behave similarly to a readonly field in that the user cannot modify it directly, and sheet worker scripts have no trouble doing so. There are two main differences with an attribute backed span:

+

+

# The default styling: the span will look just like the surrounding text

+

# When using attribute backed spans in a repeating section, you should always make a hidden input version of the attribute as attribute backed spans in repeating sections cannot be called without the full repeating section syntax (e.g. @{repeating_SECTIONNAME_$X_attribute_name}).

== Styling Checkboxes and Radio Buttons ==

== Styling Checkboxes and Radio Buttons ==

+

+

Checkboxes and radio buttons don't like getting changed much. Instead, it can be easier to use a hidden attribute and present a button to update the attribute.

+

+

{| role="presentation" class="wikitable mw-collapsible mw-collapsed"

+

| Old Checkbox / Radio example (pure html+css, but less intuitive and difficult to align)

+

|-

+

|

+

'''Note:''' This example/method of creating styled checkboxes or radios on a character sheet does not work out of the box, contains lots of unnecessary code, and is far less intuitive than the new button example. This example is generally not recommended to use, but is left here just for the sake of continuity, and those who might need troubleshoot their implementation.

[http://jsfiddle.net/waNSL/ Live Demo]

[http://jsfiddle.net/waNSL/ Live Demo]

−

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 a pure html+css approach with no sheet worker scripts, you can make the checkbox/radio invisible (but still clickable!) and overlay it on top of a more cooperative element.

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.

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.

+

+

{| role="presentation" class="wikitable mw-collapsible mw-collapsed"

+

| Old example (pure html+css)

+

|-

+

|

+

[http://jsfiddle.net/su9ac/ Live Demo]

<pre data-language="css">/* Fake checkbox */

<pre data-language="css">/* Fake checkbox */

input[type="checkbox"] + span::before {

input[type="checkbox"] + span::before {

Line 124:

Line 502:

content: "►";

content: "►";

}</pre>

}</pre>

−

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 <code>content: url(<nowiki>http://i.imgur.com/90HuQPr.png</nowiki>);</code>

+

You can also use an image instead of a string, such as <code>content: url(<nowiki>http://i.imgur.com/90HuQPr.png</nowiki>);</code>

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 hide/display any other html content based on the hidden attribute value.

=== Fill Radio Buttons to the Left ===

=== Fill Radio Buttons to the Left ===

+

+

A number of games use a set of bubbles, filled in from left to right, to represent various traits. For example, selecting the third bubble in "Strength" to indicate a Strength value of 3 should also fill in bubbles 1 and 2.

+

+

{| role="presentation" class="wikitable mw-collapsible mw-collapsed"

+

| Old example (pure html+css)

+

|-

+

|

[http://jsfiddle.net/sqaz6/ Live Demo]

[http://jsfiddle.net/sqaz6/ Live Demo]

−

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: <code>@{Strength_1} * 1 + @{Strength_2} * 1 + ...</code>

+

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: <code>@{Strength_1} * 1 + @{Strength_2} * 1 + ...</code>

However, with the radio button styling, we can solve this problem and use a radio button anyway, and only have one value.

However, with the radio button styling, we can solve this problem and use a radio button anyway, and only have one value.

Line 180:

Line 607:

{{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.}}

{{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.}}

/* Configure the button styling. This example makes it look like a radio. */

+

button.sheet-dot {

+

padding: 0;

+

border: solid 1px #a8a8a8;

+

cursor: pointer;

+

width: 14px;

+

height: 14px;

+

border-radius: 50%;

+

display: flex;

+

justify-content: center;

+

align-items: center;

+

}

+

+

button.sheet-dot > span {

+

width: 6px;

+

height: 6px;

+

border-radius: 50%;

+

background: buttontext;

+

}

+

+

/* Hide the "checked" section of the radio if the hidden attribute value is greater than the button value */

+

input.sheet-dot[value="1"] ~ button.sheet-gt-1 > span.sheet-checked {

+

display: none;

+

}

+

input.sheet-dot[value="2"] ~ button.sheet-gt-2 > span.sheet-checked {

+

display: none;

+

}

+

input.sheet-dot[value="3"] ~ button.sheet-gt-3 > span.sheet-checked {

+

display: none;

+

}

+

input.sheet-dot[value="4"] ~ button.sheet-gt-4 > span.sheet-checked {

+

display: none;

+

}

+

</pre>

+

+

Here, the "gt-*" classes are used to indicate "greater than" a particular value. This doesn't use any kind of math, so all distinct "gt-*" classes have to be included. For example, dot 3 has classes "gt-1" ''and'' "gt-2" because 3 is greater than both 1 and 2. Dot 1 does not have any "gt-*" classes because it is not greater than any of the other options. (If a zero option is possible, then all of these buttons will need a "gt-0" class.)

+

+

Each possible value of the attribute needs a corresponding CSS rule to hide all values greater than that value. (The value of "5" doesn't need a rule here because there are no options greater than 5.)

+

+

This example uses a subtractive approach, meaning a that by default the button will indicate it is checked unless a CSS rule hides the "checked" span.

=== Circular Layouts ===

=== Circular Layouts ===

Line 567:

Line 1,067:

</pre>

</pre>

The relevant part of the css looks like this.

The relevant part of the css looks like this.

−

<pre data-language="html" style="margin-bottom:5px">

+

<pre data-language="css" style="overflow:auto; width:auto;">

div.sheet-section-sp-list {

div.sheet-section-sp-list {

max-height: 999999px;

max-height: 999999px;

Line 633:

Line 1,133:

* If you want the user to only add or modify items in one place, you can get rid of the Add/Modify buttons in the other places by simply adding display: none: to a set of tags similar to this: fieldset.sheet-filtershortlist~.repcontrol where of course the .sheet tag is whatever tag you specify in your html.

* If you want the user to only add or modify items in one place, you can get rid of the Add/Modify buttons in the other places by simply adding display: none: to a set of tags similar to this: fieldset.sheet-filtershortlist~.repcontrol where of course the .sheet tag is whatever tag you specify in your html.

−

== Hide Areas ==

−

[http://jsfiddle.net/LTnd7/ Live Demo]

−

You can hide areas on the character sheet based on the state of a checkbox. Instead of the adjacent sibling selector (<code>+</code>) used by [[#Styling Checkboxes and Radio Buttons|custom checkboxes]], you should use the sibling selector (<code>~</code>).

The key to take away from this is that we have a set of radio buttons which are '''siblings''' to the divs that contain each tab's content. Then, we hide all of the tabs' content and use the sibling selector along with the <code>:checked</code> property to show the tab content associated with that particular radio button.

−

−

The rest of this example shows off means to make your tabs look pretty, such as using <code>content: attr(title)</code> to set the text of the tab, giving them colors and borders, and even making certain tabs different from the others in some fashion.

== Hexagons ==

== Hexagons ==

Line 974:

Line 1,310:

== Cycling Button ==

== Cycling Button ==

+

It is sometimes useful to have a single control that the user can click to cycle through a series of values.

+

+

{| role="presentation" class="wikitable mw-collapsible mw-collapsed"

+

| Old example (pure html+css)

+

|-

+

|

[http://jsfiddle.net/ecttk61s/ Live Demo]

[http://jsfiddle.net/ecttk61s/ Live Demo]

Line 1,026:

Line 1,368:

One fancy option would be to combine this with the technique to style your radio buttons. Hide the radios with <code>opacity: 0</code>, and display an image in the same location as the radio button (make sure the image is at a lower z-index than the invisible buttons!) so that the user is apparently clicking on the displayed image to change it.

One fancy option would be to combine this with the technique to style your radio buttons. Hide the radios with <code>opacity: 0</code>, and display an image in the same location as the radio button (make sure the image is at a lower z-index than the invisible buttons!) so that the user is apparently clicking on the displayed image to change it.

+

|}

+

This uses the same approach described in [[#Styling Checkboxes and Radio Buttons]]: it uses a hidden attribute to store the value and a styled button to update the value.

−

== Sheet Settings ==

+

The key distinction here is incrementing the numeric value by 1 each time the button is clicked and using the [https://www.computerhope.com/jargon/m/modulo.htm Modulo Operator] to cycle the value back to 0 once it reaches 4. This makes it cycle through 0, 1, 2, and 3 before going back to 0.

Roll20 supports five fonts (Arial, Patrick Hand, Contrail One, Shadows Into Light and Candal). It's still possible to use custom fonts, but it's not guaranteed to work and requires the user who want to see them to disable browser brower security to allow "unsecure scripts" to either allow Roll20 to search for locally installed fonts or import a font from an URL.

+

+

[https://github.com/Roll20/roll20-character-sheets/tree/master/Starfinder%20HUD Starfinder HUD] is an example of a sheet using custom font, and having a fallback font if the user doesn't allow unsafe scripts.

Many official sheets like [https://wiki.roll20.net/GUMSHOE_Official_Sheet GUMSHOE] have a "Sheet Settings" that can be accessed through a cog icon, which have many options to introduce changes to the sheet at will.

+

In the segment above, <code>@font-face</code> defines the name and source of the font. It first asks the broswer if the font exists locally, and if it isn't locally installed, the url gives a location to download the url from.

−

The options are [https://github.com/Roll20/roll20-character-sheets/blob/master/Gumshoe%20Official/sheet.json documented] in the game's .json file under "useroptions" tag and the rest of course in html/css.

+

[https://www.cssfontstack.com/ Here] is a list of Web-safe fonts that comes preinstalled on most operating systems, which helps avoiding the need to find a source where the font is hosted online.

+

[https://github.com/Roll20/roll20-character-sheets/search?q=ttf&unscoped_q=ttf This search through Roll20's sheet repository] shows other sheet that also use custom fonts.

== Icon Fonts ==

== Icon Fonts ==

Line 1,719:

Line 2,175:

The following are constants in JavaScript, so there's no reason to not have them as constants if you happen to need them.

The following are constants in JavaScript, so there's no reason to not have them as constants if you happen to need them.

If <code>x < 0</code>, the result is -1, while if <code>x > 0</code>, the result is 1 and if <code>x = 0</code>, the result is 0. Unfortunately, because of the nature of the calculation, we cannot correctly calculate the final possibility. This works for all values of <code>x</code> other than 0, however.

If <code>x < 0</code>, the result is -1, while if <code>x > 0</code>, the result is 1 and if <code>x = 0</code>, the result is 0. Unfortunately, because of the nature of the calculation, we cannot correctly calculate the final possibility. This works for all values of <code>x</code> other than 0, however.

Revision as of 17:10, 4 April 2020

This page gives a number of examples for creative way to leverage the character sheet system. Most of these tips involve CSS and were pulled from the CSS Wizardry thread in the Character Sheets forum, but some tips don't necessarily involve CSS at all.

Many of these tips also include links to a live demo on JSFiddle, so you can see them in action.

Tabs

May paper-versions of character sheets have more than one page, and among the best ways to implement this in Roll20 sheets is to create tabs for each page, swapping the visible area with some form of buttons. The following examples are the main two ways this can be done, where the first one is more streamlined than the older example, and is using much more of an modern approach, leading to less problems on older/less used browsers.

Button-based tabs

This is a short and simple example of implementing tabs on a character sheet, created by Finderski & GiGs.

Note: This example/method of creating tabs on a character sheet does not work out of the box, contains lots of unnecessary code, and is far less intuitive than the new tab example. This example is generally not recommended to use, but is left here just for the sake of continuity, and those who might need troubleshoot their implementation. Ambition & Avarice and Hc Svnt Dracones 2E are two sheets that base their tabs on this example, and bot needed manual adjustment on at least the position of the tabs to actually work.

Old Tab example(Doesn't work as-is, lots of redundant code, not intuitive)

Live demo
A tabbed layout is essentially an extension of hidden areas, using radio inputs instead of checkbox inputs.

The key to take away from this is that we have a set of radio buttons which are siblings to the divs that contain each tab's content. Then, we hide all of the tabs' content and use the sibling selector along with the :checked property to show the tab content associated with that particular radio button.

The rest of this example shows off means to make your tabs look pretty, such as using content: attr(title) to set the text of the tab, giving them colors and borders, and even making certain tabs different from the others in some fashion.

Four Ways to Use an Attribute

Standard

Create one of: <input> (with a type attribute of "text", "number", "checkbox", "radio", or "hidden"), <select>, or <textarea>, and set the element's name attribute to a value beginning with "attr_"

The value of the form element will be stored as the value of an attribute with the same name as the form element, except the "attr_" prefix will be removed. So, an element named "attr_example" will be stored in the attribute "example".

Text inputs, number inputs, and textareas will not update the backing attribute until they lose focus, for example when you click elsewhere on the sheet or hit the [tab] key.

Hidden inputs are, as you might guess, hidden to the user. They cannot be interacted with, and so they are prime candidates for intermediate calculations of autocalc or storing things the user doesn't need to see or change for Sheet Worker Scripts.

If you have multiple radio inputs with the same name, only one of those radios will be checked at any given time. If you have multiple other kinds of elements with the same name, their values will be synchronized. This can be used, for example, if you have a tab layout with the same field present in two tabs. Give them both the same name, and they will always have the same value.

Autocalc Fields

If a field has the disabled attribute, the user will be unable to modify its value and its value will be treated as a mathematical equation (which can reference other attributes of the character). The result of that formula will be what the user sees. Errors in the formula (for example, @{a} + @{b} + @{c} when attribute b has no value) will result in no output.

When using sheet worker scripts, the value of the autocalc field you get from the getAttrs function will be its formula, and you cannot set its value to something else. See sheetworker-autocalc for a utility to resolve autocalc fields to their calculated value in a sheet worker script. Note: sheetworker-autocalc has not been tested with repeating fields.

Readonly Fields

If a field has the readonly attribute, the user will be unable to modify its value, and its default styling will be the same as if it were disabled. However, sheet worker scripts will be able to modify its value, and if its value is some kind of equation, it won't be automatically calculated. Note: If for some reason a readonly field is an equation, sheetworker-autocalc will be able to resolve it to a value just fine.

Attribute-Backed <span>s

A <span> element can be given an "attr_" name, just like one of the form elements, above. This will cause the span to behave similarly to a readonly field in that the user cannot modify it directly, and sheet worker scripts have no trouble doing so. There are two main differences with an attribute backed span:

The default styling: the span will look just like the surrounding text

When using attribute backed spans in a repeating section, you should always make a hidden input version of the attribute as attribute backed spans in repeating sections cannot be called without the full repeating section syntax (e.g. @{repeating_SECTIONNAME_$X_attribute_name}).

Styling Checkboxes and Radio Buttons

Checkboxes and radio buttons don't like getting changed much. Instead, it can be easier to use a hidden attribute and present a button to update the attribute.

Old Checkbox / Radio example (pure html+css, but less intuitive and difficult to align)

Note: This example/method of creating styled checkboxes or radios on a character sheet does not work out of the box, contains lots of unnecessary code, and is far less intuitive than the new button example. This example is generally not recommended to use, but is left here just for the sake of continuity, and those who might need troubleshoot their implementation.
Live Demo

For a pure html+css approach with no sheet worker scripts, you can make the checkbox/radio invisible (but still clickable!) and overlay it on top of a more cooperative element.

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.

Note: 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.

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 hide/display any other html content based on the hidden attribute value.

Fill Radio Buttons to the Left

A number of games use a set of bubbles, filled in from left to right, to represent various traits. For example, selecting the third bubble in "Strength" to indicate a Strength value of 3 should also fill in bubbles 1 and 2.

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.

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:

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.

Here, the "gt-*" classes are used to indicate "greater than" a particular value. This doesn't use any kind of math, so all distinct "gt-*" classes have to be included. For example, dot 3 has classes "gt-1" and "gt-2" because 3 is greater than both 1 and 2. Dot 1 does not have any "gt-*" classes because it is not greater than any of the other options. (If a zero option is possible, then all of these buttons will need a "gt-0" class.)

Each possible value of the attribute needs a corresponding CSS rule to hide all values greater than that value. (The value of "5" doesn't need a rule here because there are no options greater than 5.)

This example uses a subtractive approach, meaning a that by default the button will indicate it is checked unless a CSS rule hides the "checked" span.

Styling Select Dropdowns

<select> elements are notoriously difficult to apply most styles to. However, using :hover pseudo-selectors and radio buttons, you can create something approximating a dropdown with whatever style you like.

Styling Repeating Sections

It's possible to style your repeating sections in a variety of ways. However, you can't just write your CSS as though the <fieldset> that's in your HTML source is what the user is viewing. After writing the code for your repeating section, here is how it will look when rendered to the user:

When you click the Modify button, the Add button is is set to display: none and the text of the Modify button is changed to "Done". When you click Done, the Add button is set to display: inline-block and the text of the Done button is changed to "Modify". While modifying repitems, the repcontainer gains the class "editmode".

Armed with this knowledge, you can do numerous things to alter how your repeating sections are displayed on the final character sheet. For example, you can have multiple repeating items per row:

Remember to use the [data-groupname="repeating_..."] attribute selector if you want to only apply the style to a single repeating section. Of course, if you want the style to affect all of your repeating sections, that's not needed.

What Can't You Do?

You cannot:

Change the "display" property of the original <fieldset>.

Change the text of the Add, Modify/Done, Delete, or Move buttons.

However, you could set their opacity to 0 and display something in their place, much like styling checkboxes and radios, as well as add ::before or ::after pseudo-elements to them.

Change the "display" property of the Add button after the user has pressed Modify once.

Filter Repeating section displays according to criteria within the repeating items itself

Assume you want a tabbed section to organize/display spells. All the 1st circle spells are displayed under tab 1, all the 2nd circle spells under tab 2, Etc. One way to do this is to duplicate the html code for each spell level. You have 10 lists, and the tabs choose which of the 10 lists to display. The following code shows how to have one list, but to filter the list so it only displays certain spells.

So basically what this does is it makes a filterbox look exactly like a repitem.
By default, no filterboxes are displayed.
The last css entries basically say where tab X above the repeating field is checked, and the same radio button inside a specific repitem is checked, then display that item.

Duplicate a repeating section name to display the same data on more than one tab.or present a summary of the data elsewhere

I am not certain that this trick is recommended by the developers, but as of this writing, it works.

You can put the same repeating section name in your html more than once in order to display the same information in multiple styles. You can have individual items displayed one way in one instance of the section (for example as a list of select/options) and a different way (for example as a read only text field) elsewhere. It is extremely useful to combine this trick with the previous section (filtering), so that only a select subset are displayed in different places, but you can do this with the convenience of having the data stored once in one list.

For example, on one tab you can have lots of fiddly options and choices, but on another tab you can display the same list of data pared down to it's minimalist essentials. If the user needs the full list, he can go to the details tab. But the items he uses most frequently fit compactly in a section of another tab. In ether case he is looking at, and manipulating the same list of data, not a list and a separate copy.

Here are the rules:

You can repeat repeating section names. Each repeated section will share the same rows and items, but each can present the data in a different way. For example : <fieldset class="repeating_weapons sheet-filtershortlist sheet-filtersummarylist"> the additional class tags can be used to differentiate how this section is to be styled as opposed to other repeating_weapons lists display the data.

Not all items must be present or displayed in all lists. However each item must be present in every list in which it is used. For example, if you have an auto-calc field, or a button that uses a field, All the fields used in the autocalc, or passed by the button, must be present in the same instance of the repeating section, it will not go looking for it in other instances of the repeating section. The referenced field may be hidden, but must be present.

You can change how fields are presented. For example they can be editable in one instance, but readonly in another.

If you change repitem to inline-block, it will float "rows" up so that it can display more than one per line.

If you want the user to only add or modify items in one place, you can get rid of the Add/Modify buttons in the other places by simply adding display: none: to a set of tags similar to this: fieldset.sheet-filtershortlist~.repcontrol where of course the .sheet tag is whatever tag you specify in your html.

Cycling Button

You can't make a button that rotates through a list, changing a displayed value. However, you can fake it!

The trick lies in layering the radio buttons on top of one another, and changing the z-index based on which input is checked.

First, set all of the inputs to some baseline z-index.

Set the first radio input of the group to a z-index higher than the rest.

For each input, when it is checked, set the z-index of the next input to something higher than the first input. You don't need to do anything for when the last input is selected, as they'll all be back at their default z-index (which means the first one is on top).

When the first input is selected, only the second one will be visible, so you can't click on any other value. When the second is clicked, the third will become the only one you can click on, and so on. The user can also navigate back and forth using arrow keys, or a combination of the tab key (or shift+tab) and the space bar.

As you can see, this uses the show/hide areas technique to display a span with some text for each radio input. You could also display an image, an input field, an entire section of the charactersheet, whatever you like.

One fancy option would be to combine this with the technique to style your radio buttons. Hide the radios with opacity: 0, and display an image in the same location as the radio button (make sure the image is at a lower z-index than the invisible buttons!) so that the user is apparently clicking on the displayed image to change it.

The key distinction here is incrementing the numeric value by 1 each time the button is clicked and using the Modulo Operator to cycle the value back to 0 once it reaches 4. This makes it cycle through 0, 1, 2, and 3 before going back to 0.

Custom Fonts

Roll20 supports five fonts (Arial, Patrick Hand, Contrail One, Shadows Into Light and Candal). It's still possible to use custom fonts, but it's not guaranteed to work and requires the user who want to see them to disable browser brower security to allow "unsecure scripts" to either allow Roll20 to search for locally installed fonts or import a font from an URL.

Starfinder HUD is an example of a sheet using custom font, and having a fallback font if the user doesn't allow unsafe scripts.

In the segment above, @font-face defines the name and source of the font. It first asks the broswer if the font exists locally, and if it isn't locally installed, the url gives a location to download the url from.

Here is a list of Web-safe fonts that comes preinstalled on most operating systems, which helps avoiding the need to find a source where the font is hosted online.
This search through Roll20's sheet repository shows other sheet that also use custom fonts.

Icon Fonts

An icon font is a font which has pictures instead of letters. You can specify one of the icon fonts below with the font-family property. For example, something like:

<p>A Gem: <span style="font-family: 'Pictos Three'">a</span></p>

Would produce:

A Gem: a

Pictos

Character

Icon

Character

Icon

Character

Icon

Character

Icon

!

!

:

:

S

S

l

l

"

"

;

;

T

T

m

m

#

#

<

<

U

U

n

n

$

$

=

=

V

V

o

o

%

%

>

>

W

W

p

p

&

&

?

?

X

X

q

q

'

'

@

@

Y

Y

r

r

(

(

A

A

Z

Z

s

s

)

)

B

B

[

[

t

t

*

*

C

C

\

\

u

u

+

+

D

D

]

]

v

v

,

,

E

E

^

^

w

w

-

-

F

F

_

_

x

x

.

.

G

G

`

`

y

y

/

/

H

H

a

a

z

z

0

0

I

I

b

b

{

{

1

1

J

J

c

c

|

|

2

2

K

K

d

d

}

}

3

3

L

L

e

e

~

~

4

4

M

M

f

f

5

5

N

N

g

g

6

6

O

O

h

h

7

7

P

P

i

i

8

8

Q

Q

j

j

9

9

R

R

k

k

Pictos Custom

Character

Icon

[

[

a

a

e

e

i

i

o

o

p

p

q

q

r

r

t

t

u

u

w

w

y

y

Pictos Three

Character

Icon

a

a

b

b

c

c

d

d

e

e

f

f

g

g

h

h

i

i

j

j

k

k

l

l

dicefontd4

Character

Icon

Character

Icon

0

0

a

a

@

@

b

b

A

A

c

c

B

B

d

d

C

C

e

e

D

D

f

f

E

E

g

g

F

F

h

h

G

G

i

i

H

H

j

j

I

I

k

k

J

J

l

l

K

K

m

m

L

L

n

n

M

M

o

o

N

N

p

p

O

O

P

P

dicefontd6

Character

Icon

Character

Icon

0

0

a

a

@

@

b

b

A

A

c

c

B

B

d

d

C

C

e

e

D

D

f

f

E

E

g

g

F

F

h

h

G

G

i

i

H

H

j

j

I

I

k

k

J

J

l

l

K

K

m

m

L

L

n

n

M

M

o

o

N

N

p

p

O

O

q

q

P

P

r

r

Q

Q

R

R

dicefontd8

Character

Icon

Character

Icon

0

0

a

a

@

@

b

b

A

A

c

c

B

B

d

d

C

C

e

e

D

D

f

f

E

E

g

g

F

F

h

h

G

G

H

H

dicefontd10

Character

Icon

Character

Icon

0

0

a

a

@

@

b

b

A

A

c

c

B

B

d

d

C

C

e

e

D

D

f

f

E

E

g

g

F

F

h

h

G

G

i

i

H

H

j

j

I

I

k

k

J

J

l

l

K

K

m

m

L

L

n

n

M

M

o

o

N

N

p

p

O

O

q

q

P

P

r

r

Q

Q

s

s

R

R

t

t

S

S

T

T

dicefontd12

Character

Icon

Character

Icon

0

0

a

a

@

@

b

b

A

A

c

c

B

B

d

d

C

C

e

e

D

D

f

f

E

E

g

g

F

F

h

h

G

G

i

i

H

H

j

j

I

I

k

k

J

J

l

l

K

K

L

L

dicefontd20

Character

Icon

Character

Icon

0

0

a

a

@

@

b

b

A

A

c

c

B

B

d

d

C

C

e

e

D

D

f

f

E

E

g

g

F

F

h

h

G

G

i

i

H

H

j

j

I

I

k

k

J

J

l

l

K

K

m

m

L

L

n

n

M

M

o

o

N

N

p

p

O

O

q

q

P

P

r

r

Q

Q

s

s

R

R

t

t

S

S

T

T

dicefontd30

Character

Icon

Character

Icon

Character

Icon

0

0

L

L

g

g

1

1

M

M

h

h

2

2

N

N

i

i

3

3

O

O

j

j

4

4

P

P

k

k

5

5

Q

Q

l

l

6

6

R

R

m

m

7

7

S

S

n

n

8

8

T

T

o

o

@

@

U

U

p

p

A

A

V

V

q

q

B

B

W

W

r

r

C

C

X

X

s

s

D

D

Y

Y

t

t

E

E

Z

Z

u

u

F

F

a

a

v

v

G

G

b

b

w

w

H

H

c

c

x

x

I

I

d

d

y

y

J

J

e

e

z

z

K

K

f

f

fontello

Character

Icon

&#xe800;



&#xe801;



&#xe802;



&#xe803;



&#xe804;



&#xe805;



&#xe806;



&#xe807;



&#xe808;



&#xe809;



&#xe80a;



&#xe80b;



&#xe80c;



&#xe80d;



&#xe80e;



&#xe80f;



&#xe810;



&#xe811;



&#xe812;



&#xe813;



&#xf008;



Styling Roll Buttons

Want a roll button that doesn't have a d20 image in it? Simple!

button[type=roll].sheet-blank-roll-button::before { content: ''; }

The d20 is a single character with the dicefontd20 font-family in the button's ::before pseudo-element. Setting the content to an empty string removes it. If you want to put something other than a d20 in its place, you'll have to change the font-family as well.

Replicating the JavaScript Math Library

Note: With the advent of Sheet Worker Scripts, the value of these tricks is diminished, as you can use the Math library directly with a sheet worker. However, they are kept here for legacy purposes, and because they still work.

It is possible to replicate most of the functionality of JavaScript's Math library with autocalc fields. While this isn't technically CSS Wizardry, it is included in this article for ease of discovery. Functions with an asterisk (*) produce approximate results; you can increase their accuracy by adding iterations to the computation.

Some functions below may reference other functions below.

Constants

The following are constants in JavaScript, so there's no reason to not have them as constants if you happen to need them.

E

E is Euler's constant, the base for the natural logarithm. The exact value is Sum[1 / n!, {n, 0, Infinity}]. Math.log(Math.E) is 1.

<input type="hidden" name="attr_cE" value="2.718281828459045">

LN2

LN2 is the value of Math.log(2).

<input type="hidden" name="attr_cLN2" value="0.6931471805599453">

LN10

LN10 is the value of Math.log(10).

<input type="hidden" name="attr_cLN10" value="2.302585092994046">

LOG2E

LOG2E is the base-2 logarithm of E. In other words, the value of Math.log2(Math.E), or 1 / Math.log(2).

<input type="hidden" name="attr_cLOG2E" value="1.4426950408889634">

LOG10E

LOG10E is the base-10 logarithm of E. In other words, the value of Math.log10(Math.E), or 1 / Math.log(10).

<input type="hidden" name="attr_cLOG10E" value="0.4342944819032518">

PI

PI is the radio between the circumference and diameter of a circle.

<input type="hidden" name="attr_cPI" value="3.141592653589793">

SQRT1_2

SQRT1_2 is the square root of 1/2 (0.5).

<input type="hidden" name="attr_cSQRT1_2" value="0.7071067811865476">

SQRT2

SQRT2 is the square root of 2.

<input type="hidden" name="attr_cSQRT2" value="1.4142135623730951">

Trivially Represented

The following functions you can use in autocalc fields easily, either because they're simple or because they're directly available.

x^y, this is x multiplied by itself y times; fractional values for y are permissible.

<input type="number" name="attr_pow" value="(@{x}**@{y})" disabled>

round(x)

Round towards the nearest integer. If the fractional part is 0.5, it will round towards positive infinity.

<input type="hidden" name="attr_round" value="round(@{x})" disabled>

sign(x)

If x < 0, the result is -1, while if x > 0, the result is 1 and if x = 0, the result is 0. Unfortunately, because of the nature of the calculation, we cannot correctly calculate the final possibility. This works for all values of x other than 0, however.