Hello friends! July is done. We merged 319 pull requests from 47 contributors.
Welcoming new sponsors
Ladybird is entirely funded by the generous support of companies and individuals who believe in the open web. This month, we’re excited to welcome the following new sponsors:
- Scraping Fish with $5,000
- Blacksmith with high-performance CI infrastructure
We’re incredibly grateful for their support. If you’re interested in sponsoring the project, please contact us.
Web Platform Tests (WPT)
As usual, we’ve made some progress on the Web Platform Tests. We’ve added 13,090 passing tests for a new total of 1,831,856.
Google reCAPTCHA passing
There was a long-standing issue with our postMessage implementation: if the serialized type had not previously been used in the destination realm, we would fail to reconstruct it. The realm didn’t recognize the type and rejected the message.
This is now fixed, allowing Google reCAPTCHA to pass!
Unfortunately, this only works on https://www.google.com/
for now, due to a separate unresolved same-origin policy issue.
High refresh rate support
We now detect the refresh rate of the active screen to determine how often web content should be rendered. Previously, rendering was fixed at 60 frames per second.
Websites using requestAnimationFrame now render at up to 120Hz on supported hardware. This change also improves the smoothness of scrolling, animations, transitions, and more.
HTTP/3 support
HTTP/3 support was recently added in curl 8.14.0 for users of OpenSSL and ngtcp2. Since Ladybird uses the OpenSSL backend with libcurl, this enabled us to support HTTP/3 as well.
We now negotiate HTTP/3 for servers that advertise it via the Alt-Svc header.
We also found and reported an issue in curl where Alt-Svc: clear
was parsed incorrectly. This has since been fixed in curl 8.15.0.
Trusted Types
Trusted Types is a security feature that helps prevent cross-site scripting (XSS) by locking down injection sinks like Element.innerHTML
, HTMLScriptElement.text
, and HTMLScriptElement.src
. It allows web developers to define policies that control how sanitized content can be created and consumed.
This month, we added initial support for Trusted Types. This includes recognizing policies and enforcing type-safe DOM writes. Further work is ongoing to support more of the spec and improve compliance.
SVG foreignObject
improvements
The relationship between HTML and SVG is complex. While SVG content can appear in HTML, SVG can also embed arbitrary HTML using the foreignObject
element.
This month, we made major improvements to how Ladybird handles foreignObject
. Layout, style resolution, and rendering inside embedded HTML are now much closer to spec behavior, with better integration between the two worlds.
CSS content: url(...)
We added support for using content: url(...)
in CSS pseudo-elements such as ::before
and ::after
. This allows authors to insert images via CSS content, matching behavior seen on modern websites.
:state(foo)
and :unchecked
pseudo-classes
We gained two new pseudo-classes:
-
:state(foo)
matches a custom element whose states set includes"foo"
. This allows custom elements to be styled based on internal state, similar to how:checked
and:empty
work. -
:unchecked
matches elements that are checkable but currently not checked.
These additions improve our compatibility with web components and modern form styling.
Logical property groups
Building on work from last month, we now generate the mappings from logical to physical properties at compile time.
Logical and physical properties form groups—for example, the various margin
properties—and we now take these into account when serializing styles and when modifying them from JavaScript. This improves both CSS fidelity and performance.
Arbitrary substitution functions
This month we rewrote our implementations of var()
and attr()
to align with the formal definition of arbitrary substitution functions in recent CSS specs. These are functions that return a value to be substituted into the rule before parsing continues.
Our new implementation is more robust, more spec-compliant, and sets us up to support other substitution functions like if()
and env()
in the future.
<syntax>
parsing
CSS now allows authors to define the expected syntax for attribute values using the <syntax>
type. This is used within attr()
to guide how the value should be parsed.
For example:
color: attr(data-color type(<color>));
This instructs the parser to interpret the data-color
attribute as a CSS color. Ladybird now supports <syntax>
parsing and uses it to improve behavior in CSS Houdini and custom properties.
@property
progress
We’ve had a stub implementation of @property
for a while. This month, we started fleshing it out.
We now respect the initial value defined in a @property
declaration and added initial support for CSS.registerProperty()
. This brings us closer to full Houdini support.
The Web is UTF-16
By definition, strings in JavaScript and the web are UTF-16 encoded. Until now, LibJS used UTF-8 internally and transcoded to UTF-16 on the fly.
This month, we introduced a native UTF-16 string type and began transitioning LibJS and LibWeb to use it internally. This simplifies the implementation and avoids subtle encoding-related bugs, especially with Unicode edge cases.
Credits
We’d like to thank everyone who contributed code this month:
Abhinav, Ali Mohammad Pur, Aliaksandr Kalenik, Andreas Kling, Andrew Kaster, aplefull, Arran Ireland, ayeteadoe, Ben Eidson, Callum Law, Chase Knowlden, dmaivel, edvwib, Gingeh, Glenn Skrzypczak, Grant Knowlton, InvalidUsernameException, Jan Koudijs, Jelle Raaijmakers, Kemal Zebari, Kenneth Myhra, Lucien Fiorini, Luke Wilde, Manuel Zahariev, Michael Manganiello, mikiubo, norbiros, Olekoop, Philipp Dreher, Psychpsyo, rmgx, Rocco Corsi, Ryan Liptak, Sam Atkins, Shannon Booth, Tete17, Tim Ledbetter, Timothy Flynn, Trey Shaffer, Undefine, Veeti Paananen, zac