Styling buttons

Hey all. I have a few buttons at the top of a passage that I would like to be styled differently once clicked. To my knowledge, there is no pseudo class of a button that can be styled in CSS once the mouse leaves the button, it reverts to its original styling. So I believe I’ll need the <<addclass>> macro, I’m just not sure how to target the buttons separately. Any ideas?
Sugarcube 2.36

<span class="tabs">\
<<button "Tools" "Inventory Tools">>\
<</button>>\
</span>\
<span class="tabs">\
<<button "Consumables" "Inventory Consumables">>\
<</button>>\
</span>\
<span class="tabs">\
<<button "Magazines" "Inventory Magazines">>\
<</button>>\
</span>\

you can use the :visited pseudoclass for links that are clicked. Use a link tag and style it like a button

Additional to @pieartsy advice about using a link’s <a> element’s :visited pseudo-class.

A list of options should ideally be displayed within an ordered <ol> or unordered <ul> element structure, that way Accessibility tools will know its a list of such. An additional advantage of doing this, is SugarCube knows to automatically suppress any line-breaks between the list-items.

<ul class="tabs">
    <li><<button "Tools" "Inventory Tools">><</button>></li>
    <li><<button "Consumables" "Inventory Consumables">><</button>></li>
    <li><<button "Magazines" "Inventory Magazines">><</button>></li>
</ul>

note: A CSS Rule like the following, in the project’s Story Stylesheet area, can be used to display the link-items horizontally.

ul.tabs {
    list-style: none;

    & li {
        display: inline-block;
        margin-right: 1em; /* add spacing between items */
    }
}

Using your web-browser’s Web Developer Tools to inspect the HTML generated by the 1st of your <<button>> macros…

<<button "Tools" "Inventory Tools">><</button>>

…would reveal the following…

<button data-passage="Inventory Tools" class="link-internal macro-button" type="button" role="link" tabindex="0">Tools</button>

…which shows that Passage Transitioning <<button>> macros assign the Name of the Target Passage to the data-passage attribute of the generated <button> element.

Combining the above information with a little knowledge of CSS Selectors, allows that 1st <button> to be targeted using button[data-passage="Inventory Tools"].

While <button> elements don’t have the equivalent of the <a> element’s :visited pseudo-class, there is no reason you can’t use macro’s like <<addclass>> or <<toggleclass>> to apply a visited CSS Class to the button…

<<addclass 'button[data-passage="Inventory Tools"]' "visited">>

…and then use a CSS Rule to apply styling to such classed buttons…

ul.tabs {
    list-style: none;
    
    & li {
        display: inline-block;
        margin-right: 1em; /* add spacing between items */
    }
    
    & button[data-passage="Inventory Tools"].visited {
        background-color: green;
    }
}

But how do you know when to apply that visited CSS Class, and the answer to that depends on a number of things:

  • should the styling only be applied while the related Target Passage is being visited? In this case the passage() function could be used to determine if that’s true.
  • should that styling be applied if that Passage has been visited before at any point during the play-through? In this case the hasVisited() function could be used instead.
  • can multiple buttons have a visited state at the same time?

Either way, one or more <<if>> family of macros will need to be used to determine if the visited class needs to be applied…

/* if styling is only applied when the related Passage is being visited. */
<<if passage() is "Inventory Tools">>
    <<addclass 'button[data-passage="Inventory Tools"]' "visited">>
<<elseif passage() is "Inventory Consumables">>
    <<addclass 'button[data-passage="Inventory Consumables"]' "visited">>
<<elseif passage() is "Inventory Magazines">>
    <<addclass 'button[data-passage="Inventory Magazines"]' "visited">>
<</if>>

Now that we know how to determine if the class should be applied, and how to apply it, we need to determine where & when in the code to do that.

Your original question left out what technique you are using to show those buttons “at the top of a passage”. And there are a number of methods you could be using, some of them being:

  • adding that code to each Passage that requires those buttons.
  • using a PassageHeader special Passage.

And the answer to that could influence where to include the <<done>> macro call that will likely be required to delay the potential updating of the generated <button> elements, so that updating occurs after those elements have actually been added to the page.

<<done>>
	/* if styling is only applied when the related Passage is being visited. */
    <<if passage() is "Inventory Tools">>
        <<addclass 'button[data-passage="Inventory Tools"]' "visited">>
    <<elseif passage() is "Inventory Consumables">>
        <<addclass 'button[data-passage="Inventory Consumables"]' "visited">>
    <<elseif passage() is "Inventory Magazines">>
        <<addclass 'button[data-passage="Inventory Magazines"]' "visited">>
    <</if>>
<</done>>
1 Like

Thank you for that detailed explanation Greyelf. Targeting buttons (and other elements when using Sugarcube macros to create them) is not well documented so this should help people in the future too.