Validation of the CSS that documents carry.
Styles are data: a map of property → value per device. Before a declaration is
written to a stylesheet its property must be in an allow-list and its value
must match the grammar of that property (lengths, colors, keywords...), so a
stored document can never break out of its rule (}), load resources
(@import) or run script (expression()).
Custom CSS written by hand (the Custom CSS field of an element or of the
document) is a different case: it is free text, so scope/2 neutralizes the
dangerous parts and nests it inside the element's selector, which keeps its
rules from leaking to the rest of the page.
Summary
Functions
Whether value is a color the styles accept.
Writes a declaration block from a map of property → value, dropping invalid declarations. Keys are written in a stable order.
Whether value is a CSS length (12px, 1.5rem, 50%, 0...).
Properties a style map may set.
Parses an inline style attribute ("color: red; padding: 4px") keeping only
valid declarations. Used by the HTML sanitizer.
Prepares hand-written CSS and nests it inside selector using CSS nesting, so
every rule applies only inside the element (or document) it belongs to.
The box-shadow presets: %{name => css}.
Validates one declaration. Returns the value to write (sometimes normalized,
like a shadow preset expanded to its CSS) or nil when it must be dropped.
Functions
Whether value is a color the styles accept.
Writes a declaration block from a map of property → value, dropping invalid declarations. Keys are written in a stable order.
iex> ElementorexCms.CSS.declarations(%{"color" => "#fff", "x" => "1", "padding-top" => "8px"})
"color:#fff;padding-top:8px"
Whether value is a CSS length (12px, 1.5rem, 50%, 0...).
@spec properties() :: [String.t()]
Properties a style map may set.
Parses an inline style attribute ("color: red; padding: 4px") keeping only
valid declarations. Used by the HTML sanitizer.
Prepares hand-written CSS and nests it inside selector using CSS nesting, so
every rule applies only inside the element (or document) it belongs to.
The keyword selector refers to the element itself, like in Elementor:
selector { box-shadow: none }
selector .btn:hover { transform: translateY(-2px) }Declarations written outside any rule apply to the element as well. Before
nesting, the text loses < (so it can never close the <style> element),
@import/@charset/@namespace rules, expression(), behavior,
-moz-binding, javascript: and every url() that is not a safe http(s) or
relative URL. Returns "" for empty input.
The box-shadow presets: %{name => css}.
Validates one declaration. Returns the value to write (sometimes normalized,
like a shadow preset expanded to its CSS) or nil when it must be dropped.
iex> ElementorexCms.CSS.value("padding-top", "24px")
"24px"
iex> ElementorexCms.CSS.value("color", "var(--color-primary)")
"var(--color-primary)"
iex> ElementorexCms.CSS.value("color", "red;}body{display:none")
nil
iex> ElementorexCms.CSS.value("behavior", "url(x.htc)")
nil