
Show HN: Sumi.css – CSS Framework
A minimalist, classless-first CSS framework. Write plain, semantic HTML and it looks finished. Add a class only when you want something specific.
以下正文同步自 Hacker News,版权归原站所有,已转换为易读排版。
A minimalist, classless-first CSS framework. Write plain, semantic HTML and it looks finished. Add a class only when you want something specific.
Install
Quick start
What gets styled
Classes and attributes
Layout
Typography
Theming
Dark mode
Overriding styles
Browser support
Files
License
Install
Download. Copy sumi.min.css into your project and link it:
<link rel="stylesheet" href="sumi.min.css">CDN. Load it from this repository through jsDelivr.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/vladocar/Sumi.css/sumi.min.css">Use sumi.css (unminified) while you develop. Its comments explain every section.
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>My page</title> <link rel="stylesheet" href="sumi.min.css"> </head> <body> <header> <nav> <ul><li><strong>My site</strong></li></ul> <ul> <li><a href="/" aria-current="page">Home</a></li> <li><a href="/about">About</a></li> </ul> </nav> </header> <main> <hgroup> <h6>Welcome</h6> <h1>Hello, ink.</h1> </hgroup> <p class="lead">This page is styled by Sumi with almost no classes.</p> <a href="#start" role="button">Get started</a> </main> <footer> <p>© 2026 My site</p> </footer> </body> </html> <header>, <main> and <footer> center themselves when they are direct children of <body>. Keep the viewport meta tag for phones, and set lang so the browser can hyphenate long-form text correctly.Element Result
h1–h6, p, lists, blockquote, code, kbd, pre, mark Fluid type scale and consistent vertical spacing
<nav> with two <ul> Navigation bar, left and right groups. Vertical inside <aside><button>, [type=submit], <a role="button"> Buttons
<input>, <select>, <textarea>, <label>, <fieldset> Full-width fields with focus rings and helper text
type="checkbox", type="radio", type="range", type="file", type="color" Custom controls that match the theme
<table> Clean rules and tabular numbers <article> Card. A direct <header> and <footer> become shaded bands <details> / <summary> Accordion with an animated chevron <dialog> Modal with a blurred backdrop<progress>, <meter> Determinate and indeterminate bars
Classes and attributes
Everything Sumi responds to beyond plain HTML:
<!-- Buttons --><button>Save</button> <button class="secondary outline">Cancel</button> <button aria-busy="true">Saving</button>
<!-- Field with helper text and validation --><label>Email <input type="email" name="email" aria-invalid="true" aria-describedby="email-help"> <small id="email-help">Enter a valid email address.</small> </label>
<!-- Switch --><label><input type="checkbox" role="switch" checked> Email reminders</label>
<!-- Card --> <article> <header><strong>Six-week course</strong></header> <p>From first strokes to a finished hanging scroll.</p> <footer><a href="#book" role="button" class="full">€180</a></footer> </article> <!-- Dropdown --> <details class="dropdown"> <summary>Export as…</summary> <ul> <li><a href="#">PNG</a></li> <li><a href="#">SVG</a></li> </ul> </details> <!-- Modal: open with dialog.showModal(); the form closes it --> <dialog id="confirm"> <article> <header><h3>Delete this file?</h3></header> <p>This can't be undone.</p> <footer> <form method="dialog" class="row"> <button class="secondary outline">Keep</button> <button class="contrast">Delete</button> </form> </footer> </article> </dialog>Layout
<!-- As many columns as fit; stacks on phones --> <div class="grid"> <div>One</div> <div>Two</div> <div>Three</div> </div> <!-- 12-column layout from tablet width up --> <div class="grid cols-12"> <div class="span-8">Main</div> <div class="span-4">Sidebar</div> </div> <!-- Change the minimum column width for one grid --> <div class="grid" style="--s-grid-min: 10rem">…</div>Cards inside a .grid stretch to equal heights and keep their footers aligned at the bottom.
Headings follow a fluid scale. The ratio grows from 1.2 on phones to 1.28 on desktop, and the base size eases from 16px to 17px. No media queries are needed on your side. Line height and letter spacing tighten as headings get larger.
Every design decision is a custom property starting with --s-. Override them in a stylesheet that loads after Sumi:
:root { --s-primary: #0f766e; --s-radius: .25rem; --s-font-body: "Inter", system-ui, sans-serif; --s-font-heading: "Fraunces", Georgia, serif; --s-container: 64rem; }
Tokens also work on a single element:
<div class="row" style="--s-primary: #b4235a; --s-radius: 999px"> <button>Book now</button> <button class="outline">Gift card</button> </div>Main tokens
Token Controls
--s-primary, --s-on-primary Buttons, links, focus rings, checked controls, and text on them
--s-secondary, --s-contrast Secondary and contrast button colors
--s-bg, --s-surface, --s-card Page, shaded areas, cards
--s-text, --s-muted Body text, secondary text
--s-border, --s-border-strong Rules, card edges, field borders
--s-success, --s-warning, --s-danger Validation and callouts
--s-font-body, --s-font-heading, --s-font-mono, --s-font-serif Typefaces
--s-font-size, --s-line-height, --s-heading-weight Base size, leading, heading weight
--s-text-display, --s-text-h1 … --s-text-h4, --s-text-lead Type scale steps
--s-flow, --s-space Space after text blocks, space after forms and components
--s-container, --s-narrow, --s-measure, --s-gutter Page width, reading width, line length, side padding
--s-radius, --s-shadow, --s-shadow-lg Corners and elevation
The full list is at the top of sumi.css.
Sumi follows the visitor's system setting with no extra code. To force a mode, set data-theme on <html>:
<html lang="en" data-theme="dark">data-theme also works on any element, so one section can be dark inside a light page. A theme switch that remembers the visitor's choice:
const root = document.documentElement; const saved = localStorage.getItem('theme'); if (saved) root.dataset.theme = saved;
document.querySelector('#theme-toggle').addEventListener('click', () => { const dark = matchMedia('(prefers-color-scheme: dark)').matches; const current = root.dataset.theme || (dark ? 'dark' : 'light'); const next = current === 'dark' ? 'light' : 'dark'; root.dataset.theme = next; localStorage.setItem('theme', next); });
The dark palette appears twice in sumi.css: once for the system setting and once for data-theme="dark". If you change dark colors, change both blocks.
Element styles are wrapped in :where(), which has zero specificity, so a plain selector is enough to override them:
/* Sumi: :where(blockquote) { border-left: 3px solid … } */ blockquote { border-left-color: var(--s-warning); }
Build your own components from Sumi's tokens and they follow your theme and dark mode automatically:
.badge { padding: .1em .55em; border: 1px solid var(--s-border); border-radius: 999px; background: var(--s-surface); color: var(--s-muted); font-size: .8rem; }
Browser support
Current versions of Chrome, Edge, Firefox and Safari. Sumi uses :where(), :has() and color-mix(), which are available from Chrome and Edge 111, Firefox 121 and Safari 16.2. Older browsers still show readable pages, with plainer hover and focus colors.
File Purpose
sumi.css Source with comments, for development
sumi.min.css Minified build, for production
docs.html Every component with its HTML, a light/dark switch and a live token editor
tutorial.html Step-by-step guide to building a page with Sumi
To rebuild the minified file after editing the source:
npx lightningcss-cli --minify sumi.css -o sumi.min.css
License
MIT © 2026 Vladimir Carrer
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。