-
Notifications
You must be signed in to change notification settings - Fork 109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parse Style
from (and serialize to?) CSS syntax
#440
Comments
UnitsTaffy's I would design your code to parse
Yes, correct. SerializationI'm definitely keen to see serialization support. Use cases:
I think both parsing and serialization are useful on their own, and I'd be happy to merge either both at once or one without the other. APIYou mention a derive macro. Presumably the idea is that this would be used on the It would be cool if it could be made to be somewhat extensible, as I know a lot of Taffy's users are working with systems that also use non-layout related CSS properties for various purposes. But I also wouldn't consider this necessary. LicensingWe prefer MIT, but I think MPL is fine (but CC @alice-i-cecile). My understanding is that MPL can be used in proprietary code, and as Prior art
Note: I'm not actively working on any of these, so very happy for you to take this on. |
I quick experiment shows that |
It sounds like there should a configurable pixel ratio of Taffy length units per CSS To avoid confusion with CSS I was thinking that derive macro(s) would be for internal use only and implement private trait(s). If there’s interest for a making it a public API that could also be considered, but be mindful that having Sketch of a trait to be derived: trait CssValue {
fn parse(parser: &mut cssparser::Parser) -> Result<Self, …>;
fn serialize(&self, dest: &mut impl std::fmt::Write) -> std::fmt::Result;
} If If |
It looks like This is why |
Oh. Shorthand v.s. longhand properties is nothing insurmountable but a headache I’d forgotten about 😅 |
Couldn't you produce an equivalent result (and therefore spec compliance) by parsing everything and then later (before returning from the parse function) throwing away values you don't understand? In any case, the fact that |
I'm somewhat questioning the value of a derive macro here. We only support ~20 properties, and even fewer of those are enums of keywords. It seems to me that it would be pretty easy to just handwrite parse/serialize function for those. And this would presumably be better for compile times. I guess a derive macro would make adding new properties easier though, so 🤷 I believe that properties that have a value of:
could be implemented using a single parsing function for
needing parsers. I think parsing the css function syntax for On the topic of grid styles, we currently don't support:
I'm not sure how that would interact with not parsing unsupported features, but I thought it bore mentioned. |
Just for context, over the last few days I started exploring parsing / validating html in taffy. My goal are the following:
My findings so far is that parsing html into a taffy node tree is not very useful unless we can also parse the accompanying css into |
If you take a look at #422, we found that we need to be able to control which elements are supported or not. Any parsing or validation we do in taffy needs to correspond tightly with whatever html or css properties we support in taffy. |
FWIW I wrote this issue with the scope in mind of only parsing "a list of CSS declaration" for creating a single If you want to parse entire stylesheets together with entire HTML documents, presumably you also to apply selectors and run the whole CSS cascade, inheritance, etc. This is a lot more involved than just parsing. In my opinion this would add an order of magnitude to the scope of the entire Taffy project, especially if you want it to be fast and support incremental updates. |
@SimonSapin So I believe @Weibye's primary objective here is to write a lint script for our test fixtures as we've a had a couple of cases of silly typos which caused a style not to apply. For this purpose a declaration list parser (and specifically the ability to parse inline styles from a Our test fixtures do use an external CSS file, however it's tiny (68 lines) and the one file is shared across all test fixtures so it's pretty easy to audit manually. The actual test cases are just inline CSS, but there are a lot of them so automated checking would be quite helpful. |
Yes, the primary idea was to solve validation of our test fixtures.
The secondary "goal" is to be able to parse html + css into a fully featured taffy tree, but as you point out that is complicated and perhaps not something worth pursuing at this time. It might also be that this functionality is better suited to a separate crate that depend on taffy, if this ever is implemented. |
Alright, I’ll start without and see how it goes. Note however that cssparser already has proc-macros that use syn and quote, so that "compile time tax" is already paid either way when enabling the new |
The old name for this one-dimensional length: * Suggests PostScript points, but is documented as an abstract unit: “Users of Taffy may define what they correspond to in their application (pixels, logical pixels, mm, etc) as they see fit.” * Is spelled similar to the two-dimensional `Point` though its meaning is unrelated. * In CSS syntax, `1px = 0.75pt` but the former is much more commonly used. When [parsing CSS into a `Style`](DioxusLabs#440) we’ll probably want the default mapping to be `1px` => 1f32 abstract unit, so naming the abstract unit "points" would be confusing.
⚠️ This is a fairly disruptive breaking changes, although the fix for users is mostly search-and-replace. The old name for this one-dimensional length: * Suggests PostScript points, but is documented as an abstract unit: “Users of Taffy may define what they correspond to in their application (pixels, logical pixels, mm, etc) as they see fit.” * Is spelled similar to the two-dimensional `Point` though its meaning is unrelated. * In CSS syntax, `1px = 0.75pt` but the former is much more commonly used. When [parsing CSS into a `Style`](DioxusLabs#440) we’ll probably want the default mapping to be `1px` => 1f32 abstract unit, so naming the abstract unit "points" would be confusing.
⚠️ This is a fairly disruptive breaking changes, although the fix for users is mostly search-and-replace. The old name for this one-dimensional length: * Suggests PostScript points, but is documented as an abstract unit: “Users of Taffy may define what they correspond to in their application (pixels, logical pixels, mm, etc) as they see fit.” * Is spelled similar to the two-dimensional `Point` though its meaning is unrelated. * In CSS syntax, `1px = 0.75pt` but the former is much more commonly used. When [parsing CSS into a `Style`](DioxusLabs#440) we’ll probably want the default mapping to be `1px` => 1f32 abstract unit, so naming the abstract unit "points" would be confusing.
⚠️ This is a fairly disruptive breaking changes, although the fix for users is mostly search-and-replace. The old name for this one-dimensional length: * Suggests PostScript points, but is documented as an abstract unit: “Users of Taffy may define what they correspond to in their application (pixels, logical pixels, mm, etc) as they see fit.” * Is spelled similar to the two-dimensional `Point` though its meaning is unrelated. * In CSS syntax, `1px = 0.75pt` but the former is much more commonly used. When [parsing CSS into a `Style`](DioxusLabs#440) we’ll probably want the default mapping to be `1px` => 1f32 abstract unit, so naming the abstract unit "points" would be confusing.
⚠️ This is a fairly disruptive breaking changes, although the fix for users is mostly search-and-replace. The old name for this one-dimensional length: * Suggests PostScript points, but is documented as an abstract unit: “Users of Taffy may define what they correspond to in their application (pixels, logical pixels, mm, etc) as they see fit.” * Is spelled similar to the two-dimensional `Point` though its meaning is unrelated. * In CSS syntax, `1px = 0.75pt` but the former is much more commonly used. When [parsing CSS into a `Style`](#440) we’ll probably want the default mapping to be `1px` => 1f32 abstract unit, so naming the abstract unit "points" would be confusing.
hey, I'm the maintainer of lightningcss and stumbled across this issue. If there's something I can do to help here please let me know. Adding more feature flags is totally an option, for example. Parsing all the CSS properties/values/rules is a lot of work so if there's something that makes sense to reuse that might be good. :) |
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 namedcss
, disabled by default. Enabling it:taffy
to https://crates.io/crates/cssparsertaffy
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
.taffy::style
: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 HTMLstyle
attribute (so with syntax likedisplay: flex; margin: 10%
) and as if there were no other applicable declarations and no parent element for inheritance. Parsing is infallible: aStyle
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 like80vw
) 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 (soStyle::DEFAULT.serialize_css()
is the empty string). It round-trips without errors:Style::parse_css(x.serialize_css()) == (x, vec![])
for anyx: Style
Testing
Use snapshot testing with https://insta.rs/ to check the
derive(Debug)
output for various CSS inputsOpen 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 fromstyle_derive
. Alternativelytaffy-css-derive
could be entirely new code, MIT-licensed liketaffy
, 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.The text was updated successfully, but these errors were encountered: