Get the computed value of any CSS property for an element, find the rule it came from, and recompute styles for a focused element or a narrow viewport, including stylesheets the page links to.
DocumentStyles.Create gathers a page’s style sources and runs the cascade. That includes the HTML user-agent stylesheet, presentational attributes, <style>, style="" and linked sheets, with layers, !important, var(), shorthands and @media/@supports. The library never fetches anything, so a <link rel=stylesheet> gets its bytes from a resolver you supply, keyed by absolute URL.
The page in this example links /css/site.css:
body { font-family: Georgia, serif; color: #222 } .card h2 { font-size: 1.5rem } nav ul { display: flex; gap: 1rem } @media (max-width: 600px) { nav ul { display: block } }
using System.Text; using RecursiveAI.OneHtml; using RecursiveAI.OneHtml.Css; Document doc = Document.Parse(File.ReadAllBytes("events.html")); // The page links /css/site.css. The library never fetches it: you hand it the bytes. var options = new StyleSourceOptions { BaseUrl = "https://library.example/events/", Resolver = url => url == "https://library.example/css/site.css" ? new StylesheetResource(File.ReadAllBytes("site.css")) : null, }; DocumentStyles styles = DocumentStyles.Create(doc, StyleContext.Default, options); Node heading = doc.Root.QuerySelector(".card h2"); ComputedStyle style = styles.GetStyle(heading); Console.WriteLine($"color: {style.GetPropertyValue("color")}, computed: {style.GetComputedValue("color")}"); Console.WriteLine($"font-size: {style.FontSizePx}px, display: {style.GetPropertyValue("display")}"); // Where a value came from DeclarationSource? source = style.GetSource("color"); Console.WriteLine($"color set by \"{source?.SelectorText}\" in {source?.SheetUrl ?? "an inline <style>"}"); DeclarationSource? font = style.GetSource("font-family"); Console.WriteLine($"font-family: {style.GetPropertyValue("font-family")} from \"{font?.SelectorText}\" in {font?.SheetUrl}"); // The same element under another context: a focused link, a narrow viewport Node link = doc.Root.QuerySelector("main a"); DocumentStyles focused = styles.WithContext(StyleContext.Default.WithFocus(link)); Console.WriteLine($"outline normally: {styles.GetStyle(link).GetPropertyValue("outline-style")}, " + $"focused: {focused.GetStyle(link).GetPropertyValue("outline-style")}"); DocumentStyles phone = styles.WithContext(StyleContext.Default.WithMedia(new MediaFeatures { Width = 390, Height = 844 })); Node nav = doc.Root.QuerySelector("nav ul"); Console.WriteLine($"nav at {MediaFeatures.Default.Width}px: {styles.GetStyle(nav).GetPropertyValue("display")}, " + $"at 390px: {phone.GetStyle(nav).GetPropertyValue("display")}"); foreach (StyleDiagnostic diagnostic in styles.Diagnostics) { Console.WriteLine(diagnostic); }
color: #1a4d7a, computed: rgb(26, 77, 122) font-size: 24px, display: block color set by ".card h2" in an inline <style> font-family: Georgia, serif from "body" in https://library.example/css/site.css outline normally: none, focused: solid nav at 1280px: flex, at 390px: block
How to read it:
GetPropertyValuereturns the value as text.GetComputedValuereturns thegetComputedStyleserialization for the typed properties, such as colors asrgb(). Typed accessors such asColor,FontSizePx,Display,VisibilityandOpacitygive values you can compute with:1.5rembecame24px.GetSourcenames the declaration that won: its selector, sheet URL (null for an inline<style>), origin, layer and importance. For an inherited property it is the ancestor’s declaration, herebodyinsite.css.StyleContextis the environment: the viewport and media features, plus at most one focused, hovered, active or target element.WithContextreturns a view that recomputes only what the new context can reach. The default viewport is 1280 px wide.Diagnosticsreports what couldn’t be used, such as a linked sheet your resolver returned null for (MissingStylesheet), an import cycle or an unsupported rule. This page has none.
There is no layout. Values that depend on layout, like percentages resolved against a containing block or the used width of an element, stay unresolved. Cascade lists what is implemented and what isn’t, and CSS values lists the typed properties.