zink-css
v0.1.1
Published
Paper, tape and marker. A small, framework-free CSS kit for handmade-looking websites.
Maintainers
Readme
zink-css
Paper, tape, marker. A small CSS kit for websites that look handmade.
No JavaScript, framework or runtime dependency. One stylesheet, scoped under .zk. Textures use CSS gradients. Your existing reset stays yours.
Start
npm i zink-cssWith a CSS-aware bundler (Vite, webpack, Parcel):
import 'zink-css';
// Explicit file export also works:
// import 'zink-css/zink.css';Plain HTML, using your locally copied stylesheet:
<link rel="stylesheet" href="./zink.css">
<section class="zk zk-paper">
<article class="zk-card zk-card--rough zk-taped">
<h2 class="zk-heading">Hello, ink.</h2>
<p>Your words go here.</p>
<a class="zk-button" href="/about">Meet the maker ↗</a>
</article>
</section>Keep every component inside a .zk ancestor. The wrapper can be body or a small section in an existing app. Add .zk-paper to that same wrapper for the textured page background. Card backgrounds use the paper token, not a raster image. No global selector changes elements outside .zk.
Pieces
| Piece | Classes | Notes |
| --- | --- | --- |
| Layout | zk-wrap, zk-grid, zk-row, zk-stack, zk-section, zk-flow | Fluid wrapper, auto-fit columns, wrapping rows, rhythm, sections, text measure |
| Paper | zk-paper, zk-graph, zk-lined, zk-ink | Grain, graph, ruled paper, dark ink |
| Type | zk-title, zk-heading, zk-label, zk-muted, zk-scribble | Display, headings, labels, secondary text, margin notes |
| Marks | zk-mark, zk-mark--pink, zk-mark--mint, zk-underline | Markers wrap across lines; default highlight is yellow |
| Cards | zk-card, zk-card--rough, zk-clipping | Ink border, hard shadow, organic border radius, cut-paper clipping |
| Tape | zk-taped, zk-taped--pink | Decorative pseudo-element; combine with positioned card |
| Notes | zk-note, zk-note--pink, zk-note--mint | Sticky-note colour variants |
| Angles | zk-tilt-left, zk-tilt-right | Small rotation, removed on narrow screens and in print |
| Buttons | zk-button, zk-button--pink, zk-button--plain, zk-button--ink | Use a real button or link, not a div |
| Small bits | zk-badge, zk-badge--pink, zk-stamp, zk-kbd, zk-rule | Badges, dashed stamp, keycaps, dashed divider |
| Navigation | zk-nav, zk-brand | Wraps when space runs out; does not add a JS menu |
| Quotes | zk-quote | Use blockquote with p and cite |
| Feedback | zk-alert, zk-alert--warning, zk-alert--error | Native content blocks; use ARIA only when appropriate |
| Forms | zk-field, zk-input, zk-help, zk-check | Labels, native fields, hints, checkbox rows |
| Disclosure | zk-details | Use native details and summary |
| Tables | zk-table-wrap, zk-table | Horizontally scrolling wrapper when needed |
| Code | zk-code | Use pre/code; no syntax highlighter |
| Assistive | zk-sr-only | Visually hidden accessible text |
zk-taped uses ::before. Avoid combining it with another component that needs the same pseudo-element. Prefer an outer wrapper. Rotations can overlap neighbours, so leave space around tilted cards. Tape is decorative and must not carry essential content.
Examples
Marker heading
<h1 class="zk-title">Less polish.<br><span class="zk-mark zk-mark--pink">More person.</span></h1>A pinned note
<div class="zk-note zk-note--mint zk-tilt-left">
<h2 class="zk-heading">Remember this.</h2>
<p>Something worth putting on paper.</p>
</div>Form field
<div class="zk-field">
<label for="email">Email</label>
<input id="email" class="zk-input" type="email" autocomplete="email" aria-describedby="email-help">
<span class="zk-help" id="email-help">Used only for your reply.</span>
</div>Add aria-invalid="true" for an invalid field, provide a visible error message and link it with aria-describedby. CSS does not validate or submit anything. Use real labels and actual consent wording.
Disclosure
<details class="zk-details">
<summary>What comes in the box?</summary>
<p>A stylesheet and a little personality.</p>
</details>React
import 'zink-css';
export function Note() {
return <section className="zk"><article className="zk-card zk-taped">
<h2 className="zk-heading">Made by a person.</h2>
<p>No special React component needed.</p>
</article></section>;
}Vue, Svelte, Astro and plain HTML use the same class names. There is no component runtime or package-specific API.
Make it yours
Override tokens on your wrapper, after importing the stylesheet:
.my-zine.zk {
--zk-paper: #fff4df;
--zk-pink: #ff8ab4;
--zk-yellow: #f7cf31;
--zk-ink: #211b18;
--zk-font: Georgia, serif;
--zk-display: 'Permanent Marker', cursive;
--zk-space: 1.25rem;
--zk-measure: 60ch;
--zk-shadow: 3px 5px 0 var(--zk-ink);
}Full defaults are at the top of dist/zink.css. Colours, font stacks, space, text measure, border and shadow are custom properties. Changes inherit through your .zk area. Test contrast after changing tokens.
Fonts
The library makes no network requests and bundles no fonts. System monospace and a system handwritten/cursive fallback work out of the box. For the same marker/typewriter feel as the demo, optionally load the open-source Google Fonts Permanent Marker and Courier Prime:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Courier+Prime:wght@400;700&family=Permanent+Marker&display=swap">.zk { --zk-display: 'Permanent Marker', cursive; --zk-font: 'Courier Prime', monospace; }You can self-host fonts instead, subject to their own licences. The optional Google Fonts request is your choice, not a dependency of the CSS kit. The demo's exact appearance depends on those fonts; fallback faces differ by OS.
Accessibility and browser support
Native HTML, visible keyboard focus, 44px button/input targets, wrapped text and responsive layouts. Reduced-motion preference removes button movement/transition. Forced-colour mode removes decorative backgrounds/tape where needed. Print rules remove texture/rotation/shadows. Disabled buttons stay disabled. No flashing effects or automatic animation.
Modern evergreen browsers are the target. Uses CSS custom properties, :where, :focus-visible, clamp, grid, min() and gradient backgrounds. Functional graceful degradation is expected where decorative clip paths or box-decoration-break are unavailable. Visual tests run in Chrome; Firefox/Safari are not independently verified in this release candidate. This kit is not a WCAG compliance guarantee. Site authors still own semantics, colour customisation, validation and behaviour.
Local demo and checks
npm test
npm run pack:check
python3 -m http.server 8080
# open http://localhost:8080/demo/No build needed. dist/zink.css is the canonical, readable production stylesheet. Test scripts use Node's built-in runner; there are no dev dependencies. examples/components.html shows the remaining elements.
Publishing checklist (owner-run)
- Confirm
zink-cssis still available and npm account has permission. This name is not reserved. - Review package identity, MIT licence, optional font terms and screenshots. Add author/repository metadata if desired; none is guessed.
- Run tests and inspect
npm pack --dry-run.demo/andtests/stay out of the published tarball; examples/docs/CSS are included. - Authenticate in the owner's terminal, with 2FA as required. Never put tokens in files or chat.
- Publish only after owner approval.
Licence
MIT for the original CSS, docs and demo code. Third-party fonts are not included in the library and retain their own licences. No artwork or quote collection from Siva's portfolio is bundled.
