Styling a vzk site
Use this guide when changing how a vzk site looks: the classes its markup
wears, the site’s stylesheet and tokens, and a file’s own <style>. Start
from describe_vocabulary topic=looks for a whole stylesheet.
Classes
Section titled “Classes”Every class a file writes out is compiled into the site’s stylesheet, so a
class name is one whole literal. A name joined from a value, such as
"text-" + size or class="text-{size}", is refused.
<article class={["card", lead && "card-lead"]}>class takes a literal, or a list whose missing and false entries drop
out. Where a class varies with a value, choose between whole names with a
lookup:
<h1 class={{ calm: "soft", bold: "loud" }[fields.tone]}>{fields.cta}</h1>A class whose names cannot be read before a page is drawn (a row’s value,
a function’s answer) is a warning, VZK0304: no rule is made for those
names, so the element may be drawn unstyled. A visitor’s text is never a
class.
A class given to a component lands on its root element:
<Frame class="aspect-square rounded-surface" alt="Dan beside his van" />.
Tokens and component classes
Section titled “Tokens and component classes”The site’s scale is its own stylesheet.css: read it with read_files.
Prefer its tokens to fixed numbers:
- spacing, used by utilities such as
gap-mdandpy-xl; - page rhythm such as
px-gutter,pt-band-topandpb-band-bottom; - measures such as
max-w-page,max-w-headlineandmax-w-lead; - colour roles such as
bg-surface,bg-raised,text-ink,text-bodyandtext-muted; - type registers such as
text-display,text-title,text-lead,font-headingandfont-strong.
A component class is a decision the look owns: btn-primary, btn-compact,
btn-outline, btn-block, link-underline, link-quiet, frame,
frame-empty and eyebrow. A file never branches on which look is active:
a new look changes the stylesheet while the markup keeps the same tokens and
component classes. The primary responsive breakpoint is md:.
<div id="prices" class="px-gutter md:px-gutter-lg pt-band-top md:pt-band-top-lg max-w-page mx-auto"> <p class="eyebrow text-muted">Prices</p> <h1 class="font-heading font-strong text-display md:text-display-lg text-ink text-balance">What it costs, before I start.</h1></div>The stylesheet
Section titled “The stylesheet”stylesheet.css is one whole file, replaced by write_files on a branch:
font imports, tokens in @theme, look-owned components in @utility, base
rules in @layer base, and any site-wide rule utilities cannot express.
@plugin, @config, @source, @reference and non-URL imports are refused, and so is
Tailwind’s built output. It must compile before the write is accepted.
A file’s own style
Section titled “A file’s own style”A file’s <style> is CSS for the markup of that file and nothing else. It
comes after the markup:
<script server> const { tone = "plain" } = props</script>
<div class={["callout", tone == "warm" && "callout-warm"]}> <p class="callout-title"><slot name="title">Note</slot></p> <p><slot /></p></div>
<style> .callout { border-left: 4px solid currentColor; padding: 0.5rem 1rem;
p { margin: 0; } }
.callout-warm { border-color: #b45309; }
.callout-title { font-weight: 700; }</style>- It is plain CSS, with nesting. A rule reaches only the markup written in
its own file, wherever that is drawn, so two files may both style
.card. - A component’s root is styled from the file that uses it by giving the
component a class:
<Callout class="wide" />and.wide { ... }. :global(...)is the way out..prose :global(p)reaches whatmarkdown(...)draws, and.menu:global(.open)a class a script adds.- It may hold style rules,
@media,@supports,@container,@layerwith a block,@starting-style,@keyframes, and@applyinside a rule.@import,@font-faceand@propertybelong instylesheet.css. - A selector that matches nothing in its file is a warning, and a style that cannot be read as CSS is an error.
Use a file’s style for a rule one file alone owns, and the stylesheet for
what several files share. style="width: {n}%" on an element takes a number
or plain text as each value, for a visual value one element alone owns.