blackle

talkative fishy

@blackle

blackle is a shark

also on twitter and mastodon.


in this tutorial I'll show how to make a button that switches between two images:


step 1: the details tag

the linchpin of this operation is the <details> tag. this tag was originally designed to show collapsible information in a document.

<details>
    <summary>summary tag</summary>
    <div>hidden content</div>
</details>
summary tag
hidden content

when the summary tag is pressed, the other content within the details tag is shown. we will use this behaviour to make our button.

step 2: sizing

the first step is to choose a size for our button. to do this, we set the "width" and "height" properties of the "details" tag.

<details style="
    width:100px;
    height:100px;">
    <summary>summary tag</summary>
    <div>hidden content</div>
</details>
summary tag
hidden content

now the details tag is 100x100 pixels in size. next, we would like the summary and div tags to match the exact position and size of the details tag. to do this, we'll use a trick based on the "position" property.

step 3: position hacking

the "position" propery has two relevant values for cohost: relative and absolute. "relative" allows you to tweak the position of a tag using the "top" and "left" properties. these properties will add to the x and y coordiates of the element.

"absolute" is a little more complicated. it allows you to set the absolute position of an element, relative to the closest ancestor who has "position: absolute" or "position: relative" set. the "top", "left", "right", and "bottom" properties lets you set the position of the element relative to the top, left, right, and bottom edges of this ancestor, respectively.

here's an example of a div that has been placed in the bottom right corner of its parent using the "position" properties.

<div style="
    position:relative;
    width:100px;
    height:100px;
    background:red">
    <div style="
        position:absolute;
        width:50px;
        height:50px;
        right:0;
        bottom:0;
        background:blue">
    </div>
</div>

now here's a question, what if we set "top", "left", "right", and "bottom" all to zero? the result is a little counter-intuitive: the element gets the exact dimensions and location of its parent element.

<div style="
    position:relative;
    width:100px;
    height:100px;
    background:red">
    <div style="
        position:absolute;
        top:0;
        left:0;
        right:0;
        bottom:0;
        background:blue">
    </div>
</div>

we'll use this on the "summary" and "div" tag inside the "details" element, but as a small optimization we'll use "inset:0;" instead of "top:0;left:0;right:0;bottom:0;".

<details style="
    position:relative;
    width:100px;
    height:100px;">
    <summary style="
        position:absolute;
        inset:0;">summary tag</summary>
    <div style="
        position:absolute;
        inset:0;">hidden content</div>
</details>
summary tag
hidden content

step 4: background images

now that the summary and hidden content overlap each other, we can give them background images for the "off" and "on" states of the button. the "summary" tag will get the "off" image, and the "div" tag will get the "on" image. we will also use the property "background-size: cover" so that the background images scale to fit.

<details style="
    position:relative;
    width:100px;
    height:100px;">
    <summary style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/f4e82b02-9cce-4da5-a768-9b9e90271b7b/panel1.png');
        background-size:cover;">summary tag</summary>
    <div style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/91402e8b-ad9b-4bc2-a710-9f4b411b1229/panel2.png');
        background-size:cover;">hidden content</div>
</details>
summary tag
hidden content

we can get rid of the "summary tag" and "hidden content" text now. we'll also add the property "font-size:0;" to the summary tag so that the right-pointing arrow isn't shown.

<details style="
    position:relative;
    width:100px;
    height:100px;">
    <summary style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/f4e82b02-9cce-4da5-a768-9b9e90271b7b/panel1.png');
        background-size:cover;
        font-size:0;"></summary>
    <div style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/91402e8b-ad9b-4bc2-a710-9f4b411b1229/panel2.png');
        background-size:cover;"></div>
</details>

step 5: pointer-events

things are very close to working, the only problem is that the button can't be turned back off. this happens because the "div" tag covers the "summary" tag, blocking any click events. to allow an element to pass events through to the element underneath, we can use the "pointer-events:none;" property.

<details style="
    position:relative;
    width:100px;
    height:100px;">
    <summary style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/f4e82b02-9cce-4da5-a768-9b9e90271b7b/panel1.png');
        background-size:cover;
        font-size:0;"></summary>
    <div style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/91402e8b-ad9b-4bc2-a710-9f4b411b1229/panel2.png');
        background-size:cover;
        pointer-events:none;"></div>
</details>

step 6: the right cursor

normally, clickable web elements use a cursor that depicts a hand pointing. to use this cursor, we'll use the property "cursor:pointer;" on the "details" element:

<details style="
    position:relative;
    width:100px;
    height:100px;
    cursor:pointer;">
    <summary style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/f4e82b02-9cce-4da5-a768-9b9e90271b7b/panel1.png');
        background-size:cover;
        font-size:0;"></summary>
    <div style="
        position:absolute;
        inset:0;
        background-image:url('https://staging.cohostcdn.org/attachment/91402e8b-ad9b-4bc2-a710-9f4b411b1229/panel2.png');
        background-size:cover;
        pointer-events:none;"></div>
</details>

and we're done! happy cohosting! be sure to use the #interactable tag on the things you make<3

more tutorials


in reply to @blackle's post:

thank you so much for the style of this guide!!! i wanted functionality exactly like this for a post in my mind and I haven't dabbled much in styling, so following the step by step was really helpful in getting my footing when i wanted to tinker with some other elements!! thank you thank you thank you :eggbug::eggbug: