Skip to content

Adaptive Content

Alexander Refsum Jensenius edited this page Jul 4, 2026 · 4 revisions

How to author pages that adapt to different readers. For the thinking behind this, see Web Philosophy; for how the levels map to typical readers and tone, see the communication strategy.

The pieces

File Role
site/_data/audiences.yml Defines the reading levels (key, labels EN/NB, description) and the default level
site/assets/css/adaptive.css Visibility rules (generated from the data file via Liquid), switcher and stretchtext styling
site/assets/js/adaptive.js Applies the chosen level, wires the switcher buttons and stretchtext toggles
site/_includes/audience-switcher.html The "Reading level:" control shown at the top of adaptive pages
site/_includes/stretch.html Inline stretchtext include
site/_layouts/default.html Loads all of the above when a page sets adaptive: true

The chosen level is stored in localStorage under mishmash-audience and applied as a data-audience attribute on <html> by an inline script in the layout head (before paint, so there is no flash of the wrong variant). Everything else is CSS.

Reading levels

Defined in site/_data/audiences.yml — currently simple, standard (default), advanced. The levels describe text complexity only; reader roles are deliberately kept out of the ladder (who typically reads at which level lives in the communication strategy). Add or change levels only in the data file; the CSS and switcher are generated from it.

Making a page adaptive

  1. Set adaptive: true in the page front matter. This loads the assets and shows the switcher.
  2. Wrap each variant in an adaptive block. markdown="1" makes kramdown process the markdown inside:
<div class="adaptive" data-for="simple" markdown="1">
Machines can now make pictures, music, and stories. …
</div>

<div class="adaptive" data-for="standard" markdown="1">
Computers can now produce images, music, and text …
</div>

<div class="adaptive" data-for="advanced" markdown="1">
Human creativity has both shaped and been shaped by …
</div>

Rules of the game:

  • data-for is space-separated: one block can serve several levels (data-for="simple standard").
  • Every level must be covered by each set of variant blocks — a level with no matching block sees nothing for that section.
  • Content outside adaptive blocks is shown to everyone. Use this for headings, images, and anything that does not need adapting (the ## Why? headings on the about page work like this).
  • Without JavaScript, only the default level's blocks are shown.

Stretchtext and the glossary

Inline terms that unfold an explanation in place. Definitions live in site/_data/glossary.yml, which also renders the site-wide glossary pages (/about/glossary/ and /no/about/glossary/) — write a definition once and it appears both inline and in the list:

{% include stretch.html term="creative-ai" %}
{% include stretch.html term="work-package" text="work packages" %}
{% include stretch.html text="LCA" more="life-cycle assessment of environmental impact" %}
  • term — key in glossary.yml; the visible text and definition follow the page language.
  • text — overrides the visible text (plural, case), or with more defines a one-off explanation that does not belong in the glossary.
  • The toggle renders with a dotted underline only (no extra markers).
  • Requires adaptive: true on the page (that is what loads the CSS/JS).
  • Without JavaScript, the extra detail is simply shown.

Use stretchtext most in the simple and standard variants — it lets plain-language text carry its own glossary. Keep the more text to a phrase or a sentence; anything longer deserves its own paragraph or page.

Writing the variants

Level Aim for
simple Short sentences, concrete examples, direct address, zero jargon; explain any unavoidable term with stretchtext
standard Plain language (klarspråk); why it matters to society; introduce key terms with stretchtext
advanced Full precision and detail, including academic references; nothing simplified away

Keep variants factually identical — same claims, different depth. When you update one variant, update them all; drift between variants is the main failure mode of this approach.

CI runs python3 scripts/check_readability.py (non-blocking): it reports a LIX readability score per level per page, warns when a simpler level reads harder than a more advanced one, and warns when a heading section covers some levels but not all.

Current adaptive pages

The mechanism is language-independent: level labels come from audiences.yml per language, and the switcher label follows page.lang.

Clone this wiki locally