Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Changing CSS class using attr_ prefix?

September 28 (5 years ago)

Hi all,

Apologies for what might be a very simple "no";  I'm not much of a coder or web developer, so I apologize if there's an obvious answer to my question--

I'm working on a custom sheet for HeroClix. I'm not sure if you're familiar with the game, but each character has an array of stat values that are individually color-coded to describe special abilities.  

I've figured out how to build a table that holds the stats, allowing me to input numerical values in the sheet's attribute section which are then properly displayed within the grid. However, I'd also like to be able to use the attribute section of the sheet to color code each cell.

I've pasted a snippet of code below to help clarify.

<td class="attr_move_1_max"><span name="attr_move_1" type="text"/></td>

My hope is that I can create a CSS class for each color ("pink", "black", "green", etc.) and then input that into the attr_move_1_max field to change the background color of that cell. However, it doesn't seem to be pulling anything. My assumption is that the class tag doesn't know to call a value when it sees an attr_ prefix. 


Does anyone know if there's a simple way of getting the class tag to pull from the attribute? Hopefully I've provided enough information to help answer the question. 


Thanks for your time.

September 28 (5 years ago)
GiGs
Pro
Sheet Author
API Scripter

It would be helpful to post the css you've attempted.

CSS isn't my forte, but I think you should be using an input, not a span, here.

Also, putting the class directly on the input or span, not on its parent will make the css simpler.

Check out the css wizardry page in the wiki for examples of using an attribute value combined with a class to apply css.

September 28 (5 years ago)
Finderski
Pro
Sheet Author
Compendium Curator

Josh K. said:

Does anyone know if there's a simple way of getting the class tag to pull from the attribute? Hopefully I've provided enough information to help answer the question. 

If I'm understanding your question correctly, you're asking if the class can change based on the value of an attribute?  If so, not in Roll20, but there is a workaround.  You'd likely only need a single class that changes the background color based on the attribute value.  However, the attribute may need to be duplicated. That's not a terrible thing, just means you have to code the thing twice and make sure the one controlling the color is not displayed.

But as GiGs mentioned, seeing the HTML and CSS would be very helpful.

(I reserve the right to modify my answer based on what the actual code...) ;)



September 28 (5 years ago)

Edited September 28 (5 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Finderski's got the right of it. The only addendum is that the controller input has to be a type='hidden' as that's the only type of input whose value actually changes in the DOM. I'll demonstrate using some radio buttons to control the display of a span:

HTML

<input type='hidden' class='controller' name='attr_controller' value='one'>
<div class='container'>
    <h4>Controllers</h4>
    <label class='control1-label'><input type='radio' name='attr_controller' value='one' checked><span>Option 1</span></label>
    <label class='control2-label'><input type='radio' name='attr_controller' value='two'><span>Option 2</span></label>
    <label class='control3-label'><input type='radio' name='attr_controller' value='three'><span>Option 3</span></label>
</div>
<div class='container'>
    <h4>Receivers</h4>
    <span class='receiver'>This text changes based on which option you've chosen</span>
</div>

CSS

.charsheet{
    --receiver-font:"Times New Roman";
    --receiver-color:Black;
    --receiver-deco:none;
    --receiver-size:1em;
    --control1-bg:Red;
    --control2-bg:Red;
    --control3-bg:Red;
}
.sheet-controller[value*="one"] ~ *{
    --receiver-font:"Contrail One";
    --receiver-color:Red;
    --receiver-deco:line-through;
    --receiver-size:3em;
    --control1-bg:#65c77f99;
    --control2-bg:none;
    --control3-bg:none;
}
.sheet-controller[value*="two"] ~ *{
    --receiver-font:"Patrick Hand";
    --receiver-color:#2dcfbc;
    --receiver-deco:overline;
    --receiver-size:1em;
    --control1-bg:none;
    --control2-bg:#65c77f99;
    --control3-bg:none;
}
.sheet-controller[value*="three"] ~ *{
    --receiver-font:Arial;
    --receiver-color:Black;
    --receiver-deco:none;
    --receiver-size:2em;
    --control1-bg:none;
    --control2-bg:none;
    --control3-bg:#65c77f99;
}
.sheet-receiver{
    font-family:var(--receiver-font);
    color:var(--receiver-color);
    text-decoration:var(--receiver-deco);
    font-size:var(--receiver-size);
}
.sheet-control1-label{
    background-color:var(--control1-bg);
}
.sheet-control2-label{
    background-color:var(--control2-bg);
}
.sheet-control3-label{
    background-color:var(--control3-bg);
}

And gives behavior like this:


You don't need to use css variables as I did above, but it allowed me to avoid having to do a multiple child selector (e.g. .sheet-controller ~ .sheet-container > .sheet-receiver) and set both the receiver and label styles with a single css declaration instead of having to do a css declaration for each affected element. Both of these are important; the single declaration because really complex styles might affect multiple elements and having to keep track of a declaration for each of them is a good way to get lost in your code. Reducing the number of multiple child selectors is important because the more complex your child selector (and the less specific it is), the worse your sheet's performance will be.

And, if you don't mind a code critique, I'd really recommend not using html tables for your layout. They aren't very flexible, and are a PITA to style correctly. Additionally, if you plan to release your sheet to the Roll20 repo it can't use tables for styling and will not be approved for the repo. Instead of using tables, I highly recommend using CSS Grid and/or CSS flexbox. Together they give you all the power of tables, plus a great deal of flexibility.

Hope that helps,

Scott


Edit: Also, how exactly you set the hisden controller and whether it's just a clone of an already existing attribute or a different attribute will depend on what kind of styling you want to do and the possible values of the attributes involved

September 28 (5 years ago)

Thank you all for the awesome feedback. Candidly, most of it is totally over my head, but I will continue to play around a bit and circle back with questions.  I don't really understand the CSS variables, hidden controllers, or selectors, but I'll try to read more on it throughout the day.


My initial thought process was to use <span> to represent the numerical values so that they couldn't be changed on the sheet, only through the attributes. Since these values are static, I don't want players accidentally adjusting them.  However, if this is limiting my functionality, I will definitely switch over to <input>.

I'll also play around with CSS Flexbox and Grids a bit more so that I can better implement the tables.


Visually, here's the effect I'm trying to produce:


As you'll see in the HTML snippet pasted below, I've created this using an attribute for each cell.  Unfortunately, the only way I've found to color code the cells is to use a CSS class within the <td> tag, which would prevent me from dynamically changing individual sheets based on a called attribute. Ideally, I'd like for the attribute and attribute_max to define the numerical value and the color.  For example, on this character, attr_move1 would have an input of 8 and an attr_move1_max of "gray". 


HTML

This section sets the rules for cell spacing, font style, font position, and font weight.  It also holds the little icons that sit at the front of each row.

<table cellspacing="0" border="0" cellpadding="0" class="units_dial">
    <tbody><tr>
	<td>
	<table cellspacing="1" border="0" cellpadding="1" width="20" class="icons">
		<tbody><tr><td><img src="https://i.imgur.com/jA9soaU.gif"></td></tr>
			<tr><td><img src="https://i.imgur.com/5ymwZlG.gif"></td></tr>
			<tr><td><img src="https://i.imgur.com/PFyhNhC.gif"></td></tr>
			<tr><td><img src="https://i.imgur.com/cNs6uvx.gif"></td></tr>
			<tr><td style="background:white; font-size:8px; color:green;">SLOT</td></tr>
		</tbody></table>
		</td>


This section holds the data values.

<td bgcolor="#FFFFFF" style="color: #000000;">
<table cellspacing="1" border="0" cellpadding="1" style="border-left:2px solid #00AA00; width: 26px;">
<tbody><tr>
         <td class="gray"><span name="attr_move_1" type="text"/></td>
</tr>
<tr>
<td class="pink"><span name="attr_attack_1" type="text"></td>
</tr>
</tbody></table> </td>


CSS

.sheet-pink {
    background-color:pink;
}

.sheet-brown {
    background-color:darkgoldenrod;
}

.sheet-black {
    background-color:black;
    color:white;
}
.sheet-special {
    background-color:white;
    border:2px solid black;
}
.sheet-gray {
    background-color:darkgray;
    color: white;

}
.sheet-units_dial {
    text-align:center;
    font:10pt verdana, geneva, lucida, 'lucida grande', arial, helvetica, sans-serif;
    font-weight: bold;
}


Thank you again for all of your guidance.  I appreciate you taking the time.


September 28 (5 years ago)

Edited September 28 (5 years ago)

Josh K. said:

My initial thought process was to use <span> to represent the numerical values so that they couldn't be changed on the sheet, only through the attributes. Since these values are static, I don't want players accidentally adjusting them.  However, if this is limiting my functionality, I will definitely switch over to <input>.

FYI, you can mark inputs as "readonly" to help prevent them from being messed up by players typing incorrect values. They can still be modified by sheetworkers when readonly, if you need to do so..

<input type="text" class="inputbox" name="attr_str" title="str" value="0" readonly>


September 28 (5 years ago)

Edited September 28 (5 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Josh, can you more fully explain how the ability score entry works in the system? That's going to affect how you approach this.

Also, as long as you don't want the users to have any direct input on the attributes that you have as spans, then spans are fine. They do have fewer default styles which can make them easier to work with than inputs (even readonly ones); from a sheetworker perspective spans work the exact same as readonly inputs.

September 28 (5 years ago)

Edited September 28 (5 years ago)

Sure thing, and thanks for the clarity on <span> vs <input>.

Each cell needs to represent two different values-- a number and a color.

All of the character data will need to be pre-loaded before anyone plays the game.  HeroClix is a boardgame; players are not generating their own characters.

Initially I thought I'd be able to use one attribute field per cell, with the first field being the numerical value and the _max field being the color.  With 48 cells per character and two values per cell, it'll obviously be a lot of data entry to manage all of this, especially for sets with 50+ characters. The game uses fourteen different colors to represent a character's ability (or lack there of), so being able to manage and organize this efficiently is key.

Each row represents a specific in-game attribute, Speed, Attack, Defense, or Damage, which helps me to keep things in order.  Additionally, each column represents an independent "click" on a radial dial, thus I can organize my cells by combining the row-attribute and the click-column;  move_1, move_2, move_3, attack_1, attack_2, attack_3, etc..  Someone--most likely me--will go in and create a character by filling out the appropriate numerical and color state for each cell.  

Hopefully this answers the question.  

September 29 (5 years ago)

Edited September 29 (5 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Ah, there were several pieces I was missing there.

There are a couple different ways to handle this in a broad "sheet design" way. They've each got their pros and cons.

  • Hard code each character into the sheet, then have a drop down on the sheet to set what character that sheet represents

Pros: Easy to play, pretty much just plug and play

Cons: A lot of work to code.
Also, I don't know if Heroclix is still being published, but if it is and there's the possibility of new characters, it will be harder to input them since you'll have to go do all the coding.
May run into some copyright issues depending on the game's license

  • Make two views of the sheets - Creation & In Play

Pros: A little less coding. Can be made so it's adaptable to most conceivable system updates

Cons: Someone will have to setup characters each campaign (or vault/transmog them in)


Those are the extremes of design philosophy. And of course there's the option of going extremely bare bones which it doesn't look like you want to do anyways.

Now, for the specific task that you've been asking about. Here's how I'd handle the display aspect of it regardless of which design philosophy you decide to go with:

HTML

<!-- color controls-->
<!--end color controls-->
<div class='ability-container'>
    <input type='hidden' class='speed 1 color' name='attr_speed_1_color' value='red'></input>
    <span class='speed 1' name='attr_speed_1' value='8'>8</span>
    <input type='hidden' class='speed 2 color' name='attr_speed_2_color' value='grey'></input>
    <span class='speed 2' name='attr_speed_2' value='7'>7</span>
    <input type='hidden' class='speed 3 color' name='attr_speed_3_color' value='green'></input>
    <span class='speed 3' name='attr_speed_3' value='9'>9</span>
    <input type='hidden' class='speed 4 color' name='attr_speed_4_color' value='orange'></input>
    <span class='speed 4' name='attr_speed_4' value='10'>10</span>
    <input type='hidden' class='speed 5 color' name='attr_speed_5_color' value='yellow'></input>
    <span class='speed 5' name='attr_speed_5' value='11'>11</span>
    <input type='hidden' class='speed 6 color' name='attr_speed_6_color' value='blue'></input>
    <span class='speed 6' name='attr_speed_6' value='15'>15</span>
</div>

CSS

.sheet-ability-container{
    display:grid;
    grid-template-columns: repeat(6,2em);
    grid-gap:0.2em;
}
.sheet-ability-container > *{
    border:1px solid black;
    text-align:center;
}
.sheet-color[value=red] + .sheet-speed{
    background-color:red;
}
.sheet-color[value=grey] + .sheet-speed{
    background-color:grey;
}
.sheet-color[value=green] + .sheet-speed{
    background-color:green;
}
.sheet-color[value=orange] + .sheet-speed{
    background-color:orange;
}
.sheet-color[value=yellow] + .sheet-speed{
    background-color:yellow;
}
.sheet-color[value=blue] + .sheet-speed{
    background-color:blue;
}

The _color attributes could simply be hidden versions of a select drop down elsewhere on the sheet, or fully set via sheetworkers. The only requirement is that they have a defined list of colors that they can be since we don't have anyway to dynamically updated the color used.

Also, I'm sure I haven't named the attributes correctly, but this is supposed to show what the first six cells of your grid would look like (I thought the icon in your screencap might mean speed?)

September 29 (5 years ago)

This is great stuff.  Spending five minutes with your code, I think I can totally work with what you've provided to achieve what I'm looking for. 

Yes, I started using "move" in my code before I verified that the system refers to it as "speed".  I'll be updating this shortly to match the icon.