I’m Ruby。 I’m roughly 20 apples tall
ルビーです。背がりんごを20つぐらいです。

I drew my profile pic and banner. The gameplay in the banner is from dragon quest 1 for game boy that I recorded myself.


YellowAfterlife
@YellowAfterlife

I bet you've already heard about details+summary trick, or maybe even fancier tricks.

But what if you want to make a visual novel or a text-based adventure?
Nesting a pile of elements is kind of high-effort, especially if you want multi-directional transitions between them.

Fortunately, there's a simpler solution: divs in a scrollable div. Take a look:

You are in a dungeon.
You are in a dungeon.
There's a painting on the wall, a cabinet, and a door.
A sturdy wooden door. It is locked.
It's an oil painting of eggbug. It is art.
A wooden cabinet. Something sparkles inside.
A golden key! You put it in your pocket.
You are in a dungeon.
There's a painting on the wall, a cabinet, and a door.
You have a key.
It's an oil painting of eggbug. Perhaps you will meet again...
A wooden cabinet. You already took the key from it.
A sturdy wooden door. It is locked, but you have a key now.
You did it! You escaped the dungeon!
:eggbug:
Click here to restart

Neat, yeah?

Here's how it works
  • We have a container div for our game. It should have a position: relative style.
    It'll be a point of reference for setting sizes for the rest of the stuff, basically.
  • Inside it, we have a div with overflow: hidden style.
    This will prevent a scrollbar from appearing and spoiling the whole game to the reader.
  • Inside that, we have a div with display: flex (so that elements stack horizontally inside) and width that's large enough to fit (number of pages * 100%).
    Here, I have 11 pages and I don't like weird numbers so I used 2000%.
  • Inside that, we have the actual pages, each of which should use width that comes out back to 100% after being multiplied by the width of the container (so, in this case, 5%).
  • Pages have id attributes.
    Cohost will prepend your id with user-content-.
    I also suggest prepending your id with something unique so that different games don't fight each other on a page.
  • Links point at those ids - for example, href="#user-content-mygame-start" for a page with id="mygame-start".

As result, when you click on a link, the browser tries to bring the linked element into view, which scrolls the container to the said page. Since each page is exactly container-sized, there isn't much ambiguity as to what to do.

We do, however, have to account for the header's height (always 4rem tall?), which I added as padding to pages here. I bet there's a better solution.

This is simple enough that it can be written by hand, though I still recommend using prechoster so that you don't have to copy-paste your page style.

Thanks for reading!


You must log in to comment.

in reply to @YellowAfterlife's post:

Thank you (and congrats on the coquest chost! That's way beyond what I thought to be doable with current tools)

The most obvious combination of two would be to make it so that picking up an item (summary) displays it in inventory and any interactive objects together with it, though this is easier to use for a (visual) point-and-click adventure than a text-based one.

Should we ever get inline styles, labels and selectors like a-checkbox:checked ~ game #something would allow for fairly convenient state management.

pseudoclasses and pseudoelements my beloved... it would be super neat to see things explode if we got access to those but it would also be bittersweet to not see how far we can push pure inline css! id be pretty surprised if we ever got them anyway, i can't imagine something like that is a very high priority feature ^^

Interactive fiction is a nice blanket term for all of them, including walking sims, rpgs and so on. But i do appreciate a good old text-based one.

Even if enhanced with voiceover and visuals, like Ryan North's To Be Or Not To Be in game form (it's adapted from physical game book).

Speaking of which, it's probably doable in chost format with your approach (with illustrations or not), but it would sink the page under its weight if adapted 1:1

! this is so clever! i wonder if the fixed header padding issue could be circumvented by setting a fixed height, padding, and scroll padding on the overflow: hidden scroll container, and then using that same fixed height (rather than width) on the pages too. (edit: wait. the page height would be the same, minus the header padding? ok this is pretty much the same as setting the padding on each element whoops 🙃)) then you might need to overflow: auto the pages themselves in case that content overflowed... 🤔

Thank you! I tinkered with it a little more and the best I can think of is this:

<div style="position: relative;">
<div style="overflow-x: hidden;">
<div style="width: 2000%; display: flex;>
<div style="width: 5%;">
  <div id="yal22-11-19-start" style="margin-top: -5rem; height: 5rem"></div>
  <div style="padding: 5px;">
    You are in a dungeon.<br>
    <ul>
      <li><a href="#user-content-yal22-11-19-look">Look around</a></li>
    </ul>
  </div>
</div>
...

so the clipping container no longer controls vertical clip, and links lead to an invisible element that's above the page "content"; if you want to use max-height, you put it on the flexbox container instead.

As an obvious caveat, if you want padding around your text, you now have to wrap it in another div - else the browser will scroll to the padded element.