Nordstjernen Browser 1.0.24 released!
Today, 16 September 2026, we are pleased to announce the release of Nordstjernen 1.0.24. This is a layout release: flexbox resolves flexible lengths the way the specification describes and column containers wrap, absolutely positioned boxes inside grids take their containing block from the grid lines, and the Web Platform Tests for flexbox went from 1465 to 1997 of 3670 subtests. Around it are the things a reader notices day to day — the page itself scroll-snaps, Ctrl+P prints in the default process-per-tab mode, text selection highlights the text it is actually on and copies the way the page reads, and the about:start splash is painted anew. Nordstjernen is a web browser, written from scratch in C, focused on supporting the HTML and CSS standards. It runs on Windows, macOS and Linux, with builds for Android, iOS, FreeBSD, NetBSD and the JVM. Nordstjernen is built in Norway.
Nordstjernen Browser version 1.0.24 is available now as a source release. Read the full release notes here, or jump straight to the downloads.
It ships alongside Northstar 1.0.8, the GPL-licensed single-process edition of the same engine.
about:start page — the same night scene over the earth, painted in an impressionist hand with a gilded frame. more screenshots »what’s new in 1.0.24
- A painted splash.
about:startwears a new splash: the same night scene, painted in an impressionist hand with a gilded frame. It is rendered byscripts/build-splash-art.pyfrom the version inmeson.build, so a release regenerates the artwork with two scripts and no image editor. - Flexbox resolves flexible lengths the way css-flexbox-1 §9.7 describes. One implementation shared by row, wrapping-row and column containers distributes free space with the item freezing loop, so flex factors below one scale the free space,
flex-shrinkis weighted by the flex base size, and min/max violations are frozen and re-distributed. The automatic minimum size of a flex item is the smaller of its content size and its specified size, sowidth: 200pxin a 100px container shrinks as browsers do. Column flex containers wrap:flex-wrap: wrapandwrap-reversebreak items into lines against the definite main size,align-contentplaces the lines,rtlmirrors the cross axis,column-reversepacks from the main end, auto margins absorb free space, and an indefinite-height column sizes itself from its items soflex: 1items no longer collapse. Negative free space overflows in the right direction, and the static position of an absolutely positioned flex child honours the writing-mode-relative keywords. On a September checkout of the horizontal-writing-mode suites, WPTcss/css-flexboxgoes from 1465 to 1997 of 3670 subtests. - Grid catches up. An absolutely positioned box whose containing block is a grid container takes that block from its
grid-columnandgrid-rowlines, as css-grid-1 §9 requires. Grid containers withdirection: rtllay their columns out from the right;repeat(auto-fit, …)collapses the tracks no item occupies, so a card grid with fewer cards than columns stretches the remainingfrtracks; a grid item’s percentage height resolves against its grid area;align-content: stretchgrows only auto rows; andgetComputedStylereturns the used track sizes forgrid-template-columnsandgrid-template-rows, with explicit line names in place, as CSSOM requires. Track lists resolveemagainst the element’s own font size, an auto track grows to its max-content contribution beforefrtracks share the remainder, and the track-list parser rejects what the grammar excludes. - Alignment keywords, in full.
align-items,align-self,align-content,justify-content,justify-itemsandjustify-selfparsefirst baseline,last baselineand thesafeandunsafeprefixes, keep their full specified keyword, and theplace-*shorthands split two-word values and serialize a repeated value once. An absolutely positioned inline-level element that follows inline content takes its static position from the line it would have occupied,scrollWidthandscrollHeightinclude the end padding, andoffsetTop/offsetLeftflush pending layout before locating the offset parent. - The page itself snaps.
scroll-snap-typeworked on scroll containers only, which left out the arrangement almost every page that asks for snapping actually uses: full-height sections down the document, with the property onhtmlorbody. The document scroller is the one scroller that is not a box, so the solver now takes a snapport rather than deriving one, the renderer resolves the proposed offset against the root element’sscroll-snap-typeand returns the snapped one to the shell on the render response. Every source of document scrolling therefore snaps — the wheel, the scrollbar, the keyboard — in process-per-tab and--single-processalike, andscroll-paddingon the root insets the viewport snapport. Ctrl+Pprints in the default process-per-tab mode. Printing paginated in the renderer and drew onto cairo recording surfaces, which cross no process boundary, so every window not started with--single-process— which is every window, by default — answered Nothing to print. The renderer now rasterises each finished sheet into the runtime directory the way the page export already hands a file across, and the shell loads the sheets back and feeds them to the sameGtkPrintOperation. Single-process printing still hands the recording surfaces over untouched, so it keeps printing vectors.- Text selection that behaves. The selection highlight was painted as one flat pass over the finished page, in document coordinates, so inside a scrolling box it landed where the text would have been unscrolled and ignored transforms and clips. It is now drawn where the text is drawn, from a range table computed once per frame, and goes down before the glyphs, which is what lets
::selectioncarry an opaque background.user-selectand::selectionare read from where the style is, souser-select: nonetext no longer copies and a page’s selection colours appear. Copied text reads like the page: line breaks where block boundaries are,<br>as a newline, and no more one-word-per-line paragraphs. Double-click selects a word and triple-click the block, with word edges from the shaper rather than an ASCII rule, and shift-click extends the selection. A page can see and set the selection it is showing:getSelection()describes the real one,execCommandperformscopy,cut,selectAllandunselect, andclipboard.writeTextreaches the system clipboard. Reading the clipboard stays refused. - Registered custom properties.
@propertywas parsed forinheritsandinitial-valueand nothing else; thesyntaxdescriptor was read past, andCSS.registerPropertywas absent. Both now go through one grammar that parses a<syntax>string and matches a value against it, arithmetic included, socalc(7in - 12px)is a<length>andcalc(5px + 10%)is not. A registered property computes its value — a<length>arrives in pixels, an<angle>in degrees, a<color>asrgb()— and a registration from script restyles the page. The CSSOM grewCSSPropertyRule,@counter-stylerejects the names it may not take, and the tokenizer decides what starts an identifier the way CSS Syntax does, so the subtraction incalc(7in - 12px)is an operator rather than a name. - Viewport units inside a frame measure that frame.
vw,vh,vmin,vmaxand their small, large and dynamic spellings resolved against the top-level window wherever they appeared, so a 200×100 iframe laid its100vwbox out at the width of the whole browser. The cascade swaps in the frame’s own viewport while it walks a nested document, the way media-query evaluation already did.document.fonts.readywaits for the web fonts the page needs andfonts.statusreportsloadingmeanwhile. - The user decides what runs. An Enable JavaScript toggle in Settings (and
NS_NO_JAVASCRIPT=1) parses pages with scripting disabled, sonoscriptcontent renders, and skips script execution entirely — in the old Mozilla tradition. Popup blocking follows Firefox 1:window.openonly navigates within five seconds of a real user gesture, consumes that activation, and logs blocked attempts to the console;navigator.userActivationreports the live state. - The classic browser, restored.
view-source:—Ctrl+Uor Page Source in the menu — shows the current page’s HTML with classic syntax highlighting; only chrome-initiated navigations can use the scheme.Ctrl+Enterin the address bar completes a bare name towww.name.com,Shift+Enterto.netandCtrl+Shift+Enterto.org.Ctrl+Shift+RandCtrl+F5reload bypassing the HTTP cache,Ctrl+Dbookmarks the page, the status bar reads Done for a moment when a page finishes loading,about:mozillashows the maroon page every browser of this lineage owes its readers,about:configopens the settings page, andabout:bookcarries its Book. The heading ofabout:nordstjernennames the browser’s version and nothing else. - Forms follow the specification.
input.showPicker()andselect.showPicker()throwInvalidStateErroron disabled or readonly controls andNotAllowedErrorwithout a user gesture (WPT show-picker 129/129).stepUp()andstepDown()honour the per-type default step and scale, round to the step grid, clamp to min/max, and serialize date, month, week, time and datetime-local values back to their canonical strings (WPT input-stepup 53/53, time 32/32). The color input sanitizes through the CSS colour parser,label.control,label.formand.labelsfollow the spec, and constraint validation computesValidityStatefor disabled and readonly controls, compilespatternas av-flag regular expression, and firestooLongandtooShortonly after a user edit — the patternMismatch, tooLong, tooShort, typeMismatch and badInput suites now fully pass. - WebIDL semantics for live collections.
HTMLCollectionandNodeListgive silent sloppy-mode failures and strict-modeTypeErrors for read-only indexed and named properties, spec-compliant descriptors, expando support, andObject.keyslisting only indices;moveBefore()isParentNode-only,replaceChildren()queues a single mutation record,Node.isConnectedis true for any node whose root is a document,HTMLDialogElement.showModal()validates its state,structuredClonevalidates its arguments and transfer options, andAbortSignal.abort(),timeout()andany()produce standardDOMExceptions. - A faster DOM. Event dispatch evaluates
composedPath()lazily and skips listener arrays on nodes that have none; the standardEventmethods are bound onEvent.prototype;document.createElement, the attribute operations,textContent,innerText,classList,datasetandCSS.escapetake zero-allocation fast paths;Element.matches()andclosest()match simple class, tag and id selectors without building a selector AST; subtreegetElementByIdqueries use the document’s id index and bloom filters; and setting an identicallocalStoragevalue neither allocates nor dispatches.line-heightresolves every root-relative, font-relative, viewport and container-query unit. - Memory safety. Fixed a use-after-free of the session URL: timer, event-dispatch and
requestAnimationFramecallbacks saved the current URL pointer and restored it unconditionally afterwards, so a handler that navigated — a fragment click,location.hash =,history.pushState— left the engine reading and double-freeing a freed URL. It is now restored only when it was actually swapped for an iframe realm. Counter formatting buffers are bounded, pseudo-content resolution guarantees forward progress, tree traversals are depth-bounded and document-order comparisons are cycle-protected. - Smaller things. The Norwegian
Accept-Languageconfiguration carries complete fallbacks across Bokmål, Nynorsk and generic Norwegian; the ns-pango subproject pin moves to the latest upstream commit; and the WPT harness’s testdriver bridge grants real user activation for simulated gestures, with its hooks inert outside the harness.
about Nordstjernen
HTML Standard. Behaviour is measured against the spec text, section by section, not against another browser — 140 spec rows fully implemented, 31 partial, 0 absent across WHATWG HTML sections 1–16 as of July 2026. Against the Web Platform Tests, the full wpt-fast tree passes 88.4% of subtests overall — 91.7% of the HTML suite. See docs/HTML-compatibility.md.
Secure. Process-per-tab design — each tab's engine runs in its own sandboxed process (seccomp + Landlock on Linux), talking to the UI over IPC and shared-memory framebuffers · no JIT.
Minimalism. The core engine is about 185,000 lines of project C and headers (plus a thin GTK 4 shell), excluding the vendored libraries and generated assets — small enough for one person to read and audit end-to-end.
Private. Nordstjernen has no JIT so it is much more secure, and can still be fast enough. It ships no telemetry of any kind, and deliberately includes no AI assistant and no AI-style web APIs.
news
16 SEP 2026 · Nordstjernen 1.0.24 released — flexbox and grid rebuilt against the specifications, the page itself scroll-snaps, printing in process-per-tab mode, text selection that behaves, registered custom properties, a JavaScript off switch, and a painted about:start. Release notes »
16 SEP 2026 ·
Northstar 1.0.8 released — transitions and animations on every property with a Web Animations API, border-image, the background shorthand parsed layer by layer, position: fixed that stays put, and lexbor 3.0.1.
Announcement » ·
Release notes »
8 AUG 2026 ·
Nordstjernen 1.0.23 released — printing with @page and print stylesheets, correct offsetLeft/offsetTop, flexbox static positions, CSS Scroll Snap, and quickjs-ng 0.16.1.
Announcement » ·
Release notes »
8 AUG 2026 · Northstar 1.0.7 released — printing, a rebuilt about:start sky and earth, CSS Scroll Snap, frames that talk to their parent, and quickjs-ng 0.16.1. Announcement » · Release notes »
31 JUL 2026 · Nordstjernen 1.0.22 released — real-site layout fixes, a rebuilt grid, faster text through ns-pango, a reworked toolbar, and a much more capable Android app. Announcement » · Release notes »
5 JUN 2026 · Nordstjernen 1.0.0 released — the first stable release. Announcement » · Release notes »
download
Latest tagged release: Nordstjernen 1.0.24 — released 16 September 2026, as source. full release notes »
Nordstjernen is also available on the Microsoft Store and Google Play.
| Source | 1.0.24.tar.gz · 1.0.24.zip |
|---|---|
| Windows | Microsoft Store |
| Android | Google Play |
| Platform builds | The most recent prebuilt packages for Windows, macOS, Debian, Ubuntu, openSUSE, portable Linux, Alpine, FreeBSD, NetBSD and the JVM are from Nordstjernen 1.0.23, on the download page. |
| All releases | github.com/nordstjernen-web/nordstjernen-browser/releases |