Description
This is a roadmap item (#345) that I’m interesting in working on. (Though I make no promise in terms of timeline or my future availability.) Below is an opinionated proposal of how this could be done.
User-visible changes
The taffy
crate gains a new Cargo feature named css
, disabled by default. Enabling it:
- Adds a dependency from
taffy
to https://crates.io/crates/cssparser - Adds a dependency from
taffy
totaffy-css-derive
, a new proc macro crate that lives in the same repository. Since many Rust types are involved, manually implementing everything without proc-macros would be quite repetitive and prone copy-paste errors. This crate is similar to Servo’sstyle_derive
. It depends onsyn
andquote
. - Adds these APIs to
taffy::style
:impl Style { pub fn parse_css(input: &str) -> (Self, Vec<CssParseError>) {..} pub fn serialize_css(&self) -> String {..} // maybe? } #[derive(Clone, Debug)] pub struct CssParseError {..} impl Display for CssParseError {..} impl Error for CssParseError {..}
Specifications
As an "input" of layout, taffy::style::Style
is the internal representation of computed values for a given element. Style::DEFAULT
is effectively initial values.
Style::parse_css
returns computed values as if the input string was a list of declarations from an HTML style
attribute (so with syntax like display: flex; margin: 10%
) and as if there were no other applicable declarations and no parent element for inheritance. Parsing is infallible: a Style
struct is always returned. Unspecified properties get their initial value. Parse errors (reported on the side) cause parts of the input to be ignored until the parser can recover. (For a declaration list, recovery is at the next semicolon.) Parse errors include invalid declaration syntax, unsupported property, invalid/unsupported value, etc.
Relative length units (font-relative like 1.5em
or viewport-relative like 80vw
) are not supported. (Per the above, using them cause the declaration to be ignored and to emit a parse error.)
Style::serialize_css
is similar to serialize a CSS declaration block. It omits properties that have their initial values (so Style::DEFAULT.serialize_css()
is the empty string). It round-trips without errors: Style::parse_css(x.serialize_css()) == (x, vec![])
for any x: Style
Testing
Use snapshot testing with https://insta.rs/ to check the derive(Debug)
output for various CSS inputs
Open API and behavior questions
-
API naming. Feel free to propose any change. (
from_css
/to_css
,parse
/impl Display
, …) -
Should serialization to CSS syntax be included? It’s relatively easy to do while also doing parsing, but maybe not as useful.
-
How are absolute length units anchored? CSS has seven of them. For historical reasons they all have a fixed ratio to each other:
1in
is96px
is72pt
is6pc
is2.54cm
is25.4mm
is101.6Q
. See reference pixel discussion.Taffy documents
Dimension::Points
as: “Points are abstract absolute units. Users of Taffy may define what they correspond to in their application (pixels, logical pixels, mm, etc) as they see fit.” The enum variant name suggests100pt
should parse asDimension::Points(100_f32)
, but on the web thepx
unit is much more common and gettingDimension(75_f32)
from100px
might be unexpected. I don’t really like this idea but maybe to force users to consider units, all units exceptpt
could be artificially unsupported?(By the way, I didn’t find this explicitly documented but I assume
Dimension::Points(100_f32)
maps to100_f32
intaffy::layout::Layout
?)Or there could be a configurable "DPI" or "device pixel ratio". A
taffy::node::Taffy
method seems like the natural place for it (next toenable_rounding
/disable_rounding
), but would require eitherTaffy::parse_css()
orStyle::parse_css(&Taffy)
instead ofStyle::parse_css()
.
Open licensing questions
cssparser
is licensed under MPL-2.0. Is that OK for a dependency?
Similarly, would it be OK for taffy-css-derive
to be licensed under MPL-2.0? This would allow copying some code from style_derive
. Alternatively taffy-css-derive
could be entirely new code, MIT-licensed like taffy
, obviously at the cost of more time and effort.
Disclaimer: although it’s been years since I’ve looked at it closely, I’ve contributed to style_derive
in the past.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
Todo