txt: ## dist_zef-dwarring-CSS-Properties.md
  [[Raku CSS Project]](https://css-raku.github.io)
  / [[CSS-Properties Module]](https://css-raku.github.io/CSS-Properties-raku)
  
  [![](https://travis-ci.org/css-raku/CSS-Properties-raku.svg?branch=master)](https://travis-ci.org/css-raku/CSS-Properties-raku)
  [![](https://ci.appveyor.com/api/projects/status/github/css-raku/CSS-Properties-raku?branch=master&passingText=Windows%20-%20OK&failingText=Windows%20-%20FAIL&pendingText=Windows%20-%20pending&svg=true)](https://ci.appveyor.com/project/dwarring/CSS-Properties-raku/branch/master)
  
  The CSS::Properties module is a set of related classes for parsing, manipulation and generation of CSS property sets, including inheritance, and defaults.
  
  ## Synopsis
  
  ```
  use CSS::Units :pt;
  use CSS::Properties;
  
  my CSS::Properties() $css = "color:red !important; padding: 1pt";
  
  say $css.color.hex; # (FF 00 00)
  say $css.important("color"); # True
  
  $css.border-color = 'blue';
  
  # set all four margins individually (top, left, bottom, right)
  $css.margin = [5pt, 2pt, 5pt, 2pt];
  # set a common margin on all four sides
  $css.margin = 5pt;
  
  # set text alignment
  $css.text-align = 'right';
  
  say ~$css; # border-color:blue; color:red!important; margin:5pt; padding:1pt; text-align:right;
  
  ```
  
  ## Classes in this module
  
  * [CSS::Properties](https://css-raku.github.io/CSS-Properties-raku/CSS/Properties) - property list manipulation class.
  * [CSS::Properties::Calculator](https://css-raku.github.io/CSS-Properties-raku/CSS/Properties/Calculator) - property calculator and measurement tool.
  * [CSS::Properties::Optimizer](https://css-raku.github.io/CSS-Properties-raku/CSS/Properties/Optimizer) - property AST optimizer delegate
  * [CSS::Properties::PropertyInfo](https://css-raku.github.io/CSS-Properties-raku/CSS/Properties/PropertyInfo) - property meta-data delegate
  * [CSS::Box](https://css-raku.github.io/CSS-Properties-raku/CSS/Box) - CSS Box model implementation.
  * [CSS::Font](https://css-raku.github.io/CSS-Properties-raku/CSS/Font) - property font manipulation
  * [CSS::Font::Descriptor](https://css-raku.github.io/CSS-Properties-raku/CSS/Font/Descriptor) - `@font-face` font descriptor objects
  * [CSS::Font::Pattern](https://css-raku.github.io/CSS-Properties-raku/CSS/Font/Pattern) - `@font-face` font patterns and matching
  * [CSS::PageBox](https://css-raku.github.io/CSS-Properties-raku/CSS/PageBox) - CSS Box model for paged media
  * [CSS::Units](https://css-raku.github.io/CSS-Properties-raku/CSS/Units) - units and post-fix operators (e.g. `12pt`)
  
  ## See Also
  
  * [CSS](https://css-raku.github.io/CSS-raku/) - Top level CSS manipulation class
  
  ## Conformance Levels
  
  Processing defaults to CSS level 3 (class CSS::Module::CSS3). This can be configured via the :module option:
  
  ```
  use CSS::Properties;
  use CSS::Module;
  use CSS::Module::CSS1;
  use CSS::Module::CSS21;
  use CSS::Module::CSS3;
  use CSS::Module::SVG;
  
  my $style = 'color:red; azimuth:left;';
  
  my CSS::Module $module = CSS::Module::CSS1.module;
  my CSS::Properties $css1 .= new: :$style, :$module;
  ## warnings: dropping unknown property: azimuth
  
  $module = CSS::Module::CSS21.module;
  my CSS::Properties $css21 .= new: :$style, :$module;
  ## (no warnings)
  
  my CSS::Properties $css3 .= new: :$style; # CSS3 is the default
  # -- or --
  $module = CSS::Module::CSS3.module;
  $css3 .= new: :$style, :$module;
  
  $module = CSS::Module::SVG.module;
  $style ~= "paint-order:markers;";  # add a SVG specific property
  my CSS::Properties $css-svg .= new: :$style, :$module;
  
  ```
  
  `CSS::Module::SVG` is an extension to `CSS::Module::CSS3` that includes
  additional SVG specific properties.
  
  ### '@font-face' Properties
  
  The [CSS::Font::Descriptor](https://css-raku.github.io/CSS-Properties-raku/CSS/Font/Descriptor) module is a class for managing `@font-face` declarations. The `css` method can be used to get the raw properties.
  
  ```
  @font-face {
      font-family: myFirstFont;
      src: url(sansation_light.woff);
  }
  
  ```
  
  ```
  use CSS::Properties;
  use CSS::Font::Descriptor;
  
  my $style = "font-family: myFirstFont; src: url(sansation_light.woff)";
  my CSS::Font::Descriptor $fd .= new: :$style;
  my CSS::Properties $font-face-css = $fd.css;
  
  ```
  
  ## Default values
  
  Most properties have a default value. If a property is reset to its default value it will be omitted from stringification:
  
  ```
  my $css = (require CSS::Properties).new;
  say $css.background-image; # none
  $css.background-image = 'url(camellia.png)';
  say ~$css; # "background-image: url(camellia.png);"
  $css.background-image = $css.info("background-image").default;
  say $css.background-image; # none
  say ~$css; # ""
  
  ```
  
  ## Deleting properties
  
  Properties can be deleted via the `delete` method, or by assigning the property to `Nil`:
  
  ```
  my CSS::Properties $css .= new: :style("background-position:top left; border-top-color:red; border-bottom-color: green; color: blue");
  # delete background position
  $css.background-position = Nil;
  # delete all border colors
  $css.delete: "border-color";
  
  ```
  
  ## Inheritance
  
  A child class can inherit from one or more parent classes. This follows CSS standards:
  
  * not all properties are inherited by default; for example `color` is, but `margin` is not.
  * the `inherit` keyword can be used in the child property to ensure inheritance.
  * `initial` will reset the child property to the default value
  
  To inherit a css object or style string:
  
  * pass it as a `:inherit` option, when constructing the object, or
  * use the `inherit` method
  
  ```
  use CSS::Properties;
  
  my $parent-style = "margin-top:5pt; margin-left: 15pt; color:rgb(0,0,255) !important";
  my $style = "margin-top:25pt; margin-right: initial; margin-left: inherit; color:purple";
  my CSS::Properties $css .= new: :$style, :inherit($parent-style);
  
  say $css.color;                     # #7F007Frgb (purple)
  say $css.handling("margin-left");   # inherit
  say $css.margin-left;               # 15pt
  
  ```
  
  ## Optimization and Serialization
  
  ```
  method write(
      Bool :$optimize = True,        # consolidate properties
      Bool :$terse = True,           # single line output
      Bool :$color-names = True,     # use color names, where possible
      Bool :$keep-defaults = False,  # don't omit default values
      |c
  ) is also<Str gist> {
  
  ```
  
  The `.write` (alias `.Str`, or .`gist`) method can be used to produce CSS. Properties are optimized and normalized:
  
  * properties with default values are omitted
  * multiple component properties are generally consolidated to container properties (e.g. `font-family: Courier` and `font-size: 12pt`
    are consolidated to `font: 12pt Courier`).
  * rgb masks are translated to color-names, where possible
  
  ```
  use CSS::Properties;
  my CSS::Properties $css .= new( :style("background-repeat:repeat; border-style: groove; border-width: 2pt 2pt; color: rgb(255,0,0);") );
  # - 'border-width' and 'border-style' are consolidated to the 'border' container property
  # - rgb(255,0,0) is mapped to 'red'
  say $css.write;  # "border:2pt groove; color: red;"
  
  ```
  
  Notice that:
  
  * `background-repeat` was omitted because it has the default value
  * `border-style` and `border-width` have been consolidated to the `border` container property. This is possible
    because all four borders have common values
  * `color` has been translated from a color mask to a color
  
  `$.write` Options include:
  
  * `:!optimize` - turn off optimization. Don't, combine component properties into container properties (`border-style`, `border-width`, ... => `border`), or combine edges (`margin-top`, `margin-left`, ... => `margin`).
  * `:!terse` - enable multi-line output
  * `:!color-names` - don't translate RGB values to color-names
  
  See also [CSS::Properties::Optimizer](https://css-raku.github.io/CSS-Properties-raku/CSS/Properties/Optimizer).
  
  ## Property Meta-data
  
  The `info` method gives property specific meta-data, on all (component or container properties). It returns an object of type CSS::Properties::PropertyInfo:
  
  ```
  use CSS::Properties;
  use CSS::Properties::PropertyInfo;
  my CSS::Properties $css .= new;
  my CSS::Properties::PropertyInfo $margin-info = $css.info("margin");
  say $margin-info.synopsis; # <margin-width>{1,4}
  say $margin-info.edges;    # [margin-top margin-right margin-bottom margin-left]
  say $margin-info.inherit;  # True (property is inherited)
  
  ```
  
  ## Data Introspection
  
  The `properties` method, gives a list of current properties. Only component properties
  are returned. E.g. `font-family` may be returned; but `font` never is.
  
  ```
  use CSS::Properties;
  
  my $style = "margin-top: 10%; margin-right: 5mm; margin-bottom: auto";
  my CSS::Properties $css .= new: :$style;
  
  for $css.properties -> $prop {
      my $val = $css."$prop"();
      say "$prop: $val {$val.type}";
  }
  
  
  ```
  
  Gives:
  
  ```
  margin-top: 10 percent
  margin-bottom: auto keyw
  margin-right: 5 mm
  
  ```
  
  ## Lengths and Units
  
  CSS::Units is a convenience module that provides some simple post-fix length unit definitions.
  
  The `:ops` export overloads `+` and `-` to perform unit
  calculations. `+css` and `-css` are also available as
  more explicit infix operators:
  
  All infix operators convert to the left-hand operand's units.
  
  ```
  use CSS::Units :ops, :pt, :px, :in, :mm;
  my CSS::Properties $css .= new: :margin[5pt, 10px, .1in, 2mm];
  
  # display margins in millimeters
  say "%.2f mm".sprintf(.scale("mm")) for $css.margin.list;
  
  ```
  
  The `measure` method can be used to perform contextual measurement
  of lengths, which are converted to the default units.
  
  The current font-size is used for `em`, `ex` and percentage calculations.
  
  There are also `viewport-width` and `viewport-height` attributes
  that need to be set to enable `vw` and `vh` units.
  
  ```
  use CSS::Units :ops, :pt, :px, :in, :mm, :em, :vw, :vh, :percent;
  use CSS::Properties;
  my CSS::Properties $css .= new: :viewport-width(200);
  
  say $css.units;         # pt
  say $css.measure: 10px; # 7.5pt
  say $css.measure: 1in;  # 72pt
  
  say $css.font-size;     # 12pt
  say $css.measure: 2em;  # 24pt
  say $css.measure: 50%;  # 6pt
  say $css.measure: .1vw; # 20pt
  
  ```
  
  The `measure` method can also be used on specific properties. In the case
  of box measurements (borders, margins and padding) a `reference-width` also needs to be set for percentage calculations.
  
  ```
  use CSS::Units :px, :percent;
  use CSS::Properties;
  my CSS::Properties $css .= new: :margin[10%, 10px], :reference-width(120);
  
  say $css.measure: :margin-top;       # 12pt
  say $css.measure: :margin-left;      # 7.5pt
  say $css.measure: :margin-left(20%); # 24pt
  say $css.measure: :font-size;        # 12pt
  say $css.measure: :font-size(50%);   # 6pt
  
  ```
  
  The `units` attribute defaults to `pt` can be changed to any absolute length units:
  
  ```
  use CSS::Units :px, :mm;
  use CSS::Properties;
  my CSS::Properties $css .= new: :margin[10mm, 10px], :units<mm>;
  say $css.units;                      # mm
  say $css.measure: :margin-top;       # 10mm
  say $css.measure: :margin-left;      # 2.646mm
  
  ```
  
  ## Appendix : CSS3 Properties
  
  | Name | Default | Inherit | Type | Synopsis |
  | --- | --- | --- | --- | --- |
  | azimuth | center | Yes |  | <angle> | [[ left-side | far-left | left | center-left | center | center-right | right | far-right | right-side ] || behind ] | leftwards | rightwards |
  | background |  |  | hash | ['background-color' || 'background-image' || 'background-repeat' || 'background-attachment' || 'background-position'] |
  | background-attachment | scroll |  |  | scroll | fixed |
  | background-color | transparent |  |  | <color> | transparent |
  | background-image | none |  |  | <uri> | none |
  | background-position | 0% 0% |  |  | [ [ <percentage> | <length> | left | center | right ] [ <percentage> | <length> | top | center | bottom ]? ] | [ [ left | center | right ] || [ top | center | bottom ] ] |
  | background-repeat | repeat |  |  | repeat | repeat-x | repeat-y | no-repeat |
  | border |  |  | hash,box | [ 'border-width' || 'border-style' || 'border-color' ] |
  | border-bottom |  |  | hash | [ 'border-bottom-width' || 'border-bottom-style' || 'border-bottom-color' ] |
  | border-bottom-color | the value of the 'color' property |  |  | <color> | transparent |
  | border-bottom-style | none |  |  | <border-style> |
  | border-bottom-width | medium |  |  | <border-width> |
  | border-collapse | separate | Yes |  | collapse | separate |
  | border-color |  |  | box | [ <color> | transparent ]{1,4} |
  | border-left |  |  | hash | [ 'border-left-width' || 'border-left-style' || 'border-left-color' ] |
  | border-left-color | the value of the 'color' property |  |  | <color> | transparent |
  | border-left-style | none |  |  | <border-style> |
  | border-left-width | medium |  |  | <border-width> |
  | border-right |  |  | hash | [ 'border-right-width' || 'border-right-style' || 'border-right-color' ] |
  | border-right-color | the value of the 'color' property |  |  | <color> | transparent |
  | border-right-style | none |  |  | <border-style> |
  | border-right-width | medium |  |  | <border-width> |
  | border-spacing | 0 | Yes |  | <length> <length>? |
  | border-style |  |  | box | <border-style>{1,4} |
  | border-top |  |  | hash | [ 'border-top-width' || 'border-top-style' || 'border-top-color' ] |
  | border-top-color | the value of the 'color' property |  |  | <color> | transparent |
  | border-top-style | none |  |  | <border-style> |
  | border-top-width | medium |  |  | <border-width> |
  | border-width |  |  | box | <border-width>{1,4} |
  | bottom | auto |  |  | <length> | <percentage> | auto |
  | caption-side | top | Yes |  | top | bottom |
  | clear | none |  |  | none | left | right | both |
  | clip | auto |  |  | <shape> | auto |
  | color | depends on user agent | Yes |  | <color> |
  | content | normal |  |  | normal | none | [ <string> | <uri> | <counter> | <counters> | attr(<identifier>) | open-quote | close-quote | no-open-quote | no-close-quote ]+ |
  | counter-increment | none |  |  | none | [ <identifier> <integer>? ]+ |
  | counter-reset | none |  |  | none | [ <identifier> <integer>? ]+ |
  | cue |  |  | hash | [ 'cue-before' || 'cue-after' ] |
  | cue-after | none |  |  | <uri> | none |
  | cue-before | none |  |  | <uri> | none |
  | cursor | auto | Yes |  | [ [<uri> ,]\* [ auto | crosshair | default | pointer | move | e-resize | ne-resize | nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text | wait | help | progress ] ] |
  | direction | ltr | Yes |  | ltr | rtl |
  | display | inline |  |  | inline | block | list-item | inline-block | table | inline-table | table-row-group | table-header-group | table-footer-group | table-row | table-column-group | table-column | table-cell | table-caption | none |
  | elevation | level | Yes |  | <angle> | below | level | above | higher | lower |
  | empty-cells | show | Yes |  | show | hide |
  | float | none |  |  | left | right | none |
  | font |  | Yes | hash | [ [ <‘font-style’> || <font-variant-css21> || <‘font-weight’> || <‘font-stretch’> ]? <‘font-size’> [ / <‘line-height’> ]? <‘font-family’> ] | caption | icon | menu | message-box | small-caption | status-bar |
  | font-family | depends on user agent | Yes |  | [ <generic-family> | <family-name> ]# |
  | font-feature-settings | normal | Yes |  | normal | <feature-tag-value># |
  | font-kerning | auto | Yes |  | auto | normal | none |
  | font-language-override | normal | Yes |  | normal | <string> |
  | font-size | medium | Yes |  | <absolute-size> | <relative-size> | <length> | <percentage> |
  | font-size-adjust | none | Yes |  | none | auto | <number> |
  | font-stretch | normal | Yes |  | normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded |
  | font-style | normal | Yes |  | normal | italic | oblique |
  | font-synthesis | weight style | Yes |  | none | [ weight || style ] |
  | font-variant | normal | Yes |  | normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> || stylistic(<feature-value-name>) || historical-forms || styleset(<feature-value-name> #) || character-variant(<feature-value-name> #) || swash(<feature-value-name>) || ornaments(<feature-value-name>) || annotation(<feature-value-name>) || [ small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps ] || <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero || <east-asian-variant-values> || <east-asian-width-values> || ruby ] |
  | font-variant-alternates | normal | Yes |  | normal | [ stylistic(<feature-value-name>) || historical-forms || styleset(<feature-value-name>#) || character-variant(<feature-value-name>#) || swash(<feature-value-name>) || ornaments(<feature-value-name>) || annotation(<feature-value-name>) ] |
  | font-variant-caps | normal | Yes |  | normal | small-caps | all-small-caps | petite-caps | all-petite-caps | unicase | titling-caps |
  | font-variant-east-asian | normal | Yes |  | normal | [ <east-asian-variant-values> || <east-asian-width-values> || ruby ] |
  | font-variant-ligatures | normal | Yes |  | normal | none | [ <common-lig-values> || <discretionary-lig-values> || <historical-lig-values> || <contextual-alt-values> ] |
  | font-variant-numeric | normal | Yes |  | normal | [ <numeric-figure-values> || <numeric-spacing-values> || <numeric-fraction-values> || ordinal || slashed-zero ] |
  | font-variant-position | normal | Yes |  | normal | sub | super |
  | font-weight | normal | Yes |  | normal | bold | bolder | lighter | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 |
  | height | auto |  |  | <length> | <percentage> | auto |
  | left | auto |  |  | <length> | <percentage> | auto |
  | letter-spacing | normal | Yes |  | normal | <length> |
  | line-height | normal | Yes |  | normal | <number> | <length> | <percentage> |
  | list-style |  | Yes | hash | [ 'list-style-type' || 'list-style-position' || 'list-style-image' ] |
  | list-style-image | none | Yes |  | <uri> | none |
  | list-style-position | outside | Yes |  | inside | outside |
  | list-style-type | disc | Yes |  | disc | circle | square | decimal | decimal-leading-zero | lower-roman | upper-roman | lower-greek | lower-latin | upper-latin | armenian | georgian | lower-alpha | upper-alpha | none |
  | margin |  |  | box | <margin-width>{1,4} |
  | margin-bottom | 0 |  |  | <margin-width> |
  | margin-left | 0 |  |  | <margin-width> |
  | margin-right | 0 |  |  | <margin-width> |
  | margin-top | 0 |  |  | <margin-width> |
  | max-height | none |  |  | <length> | <percentage> | none |
  | max-width | none |  |  | <length> | <percentage> | none |
  | min-height | 0 |  |  | <length> | <percentage> |
  | min-width | 0 |  |  | <length> | <percentage> |
  | opacity | 1.0 |  |  | <number> |
  | orphans | 2 | Yes |  | <integer> |
  | outline |  |  | hash | [ 'outline-color' || 'outline-style' || 'outline-width' ] |
  | outline-color | invert |  |  | <color> | invert |
  | outline-style | none |  |  | [ none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset ] |
  | outline-width | medium |  |  | thin | medium | thick | <length> |
  | overflow | visible |  |  | visible | hidden | scroll | auto |
  | padding |  |  | box | <padding-width>{1,4} |
  | padding-bottom | 0 |  |  | <padding-width> |
  | padding-left | 0 |  |  | <padding-width> |
  | padding-right | 0 |  |  | <padding-width> |
  | padding-top | 0 |  |  | <padding-width> |
  | page-break-after | auto |  |  | auto | always | avoid | left | right |
  | page-break-before | auto |  |  | auto | always | avoid | left | right |
  | page-break-inside | auto |  |  | avoid | auto |
  | pause |  |  |  | [ [<time> | <percentage>]{1,2} ] |
  | pause-after | 0 |  |  | <time> | <percentage> |
  | pause-before | 0 |  |  | <time> | <percentage> |
  | pitch | medium | Yes |  | <frequency> | x-low | low | medium | high | x-high |
  | pitch-range | 50 | Yes |  | <number> |
  | play-during | auto |  |  | <uri> [ mix || repeat ]? | auto | none |
  | position | static |  |  | static | relative | absolute | fixed |
  | quotes | depends on user agent | Yes |  | [<string> <string>]+ | none |
  | richness | 50 | Yes |  | <number> |
  | right | auto |  |  | <length> | <percentage> | auto |
  | size | auto |  |  | <length>{1,2} | auto | [ <page-size> || [ portrait | landscape] ] |
  | speak | normal | Yes |  | normal | none | spell-out |
  | speak-header | once | Yes |  | once | always |
  | speak-numeral | continuous | Yes |  | digits | continuous |
  | speak-punctuation | none | Yes |  | code | none |
  | speech-rate | medium | Yes |  | <number> | x-slow | slow | medium | fast | x-fast | faster | slower |
  | stress | 50 | Yes |  | <number> |
  | table-layout | auto |  |  | auto | fixed |
  | text-align | a nameless value that acts as 'left' if 'direction' is 'ltr', 'right' if 'direction' is 'rtl' | Yes |  | left | right | center | justify |
  | text-decoration | none |  |  | none | [ underline || overline || line-through || blink ] |
  | text-indent | 0 | Yes |  | <length> | <percentage> |
  | text-transform | none | Yes |  | capitalize | uppercase | lowercase | none |
  | top | auto |  |  | <length> | <percentage> | auto |
  | unicode-bidi | normal |  |  | normal | embed | bidi-override |
  | vertical-align | baseline |  |  | baseline | sub | super | top | text-top | middle | bottom | text-bottom | <percentage> | <length> |
  | visibility | visible | Yes |  | visible | hidden | collapse |
  | voice-family | depends on user agent | Yes |  | [<generic-voice> | <specific-voice> ]# |
  | volume | medium | Yes |  | <number> | <percentage> | silent | x-soft | soft | medium | loud | x-loud |
  | white-space | normal | Yes |  | normal | pre | nowrap | pre-wrap | pre-line |
  | widows | 2 | Yes |  | <integer> |
  | width | auto |  |  | <length> | <percentage> | auto |
  | word-spacing | normal | Yes |  | normal | <length> |
  | z-index | auto |  |  | auto | <integer> |
  
  The above markdown table was produced with the following code snippet
  
  ```
  use v6;
  say <Name Default Inherit Type Synopsis>.join(' | ');
  say ('---' xx 5).join(' | ');
  
  my $css = (require CSS::Properties).new;
  
  for $css.properties(:all).sort -> $name {
      with $css.info($name) {
          my @type;
          @type.push: 'hash' if .children;
          @type.push: 'box' if .box;
          my $synopsis-escaped = .synopsis.subst(/<?before <[ < | > # ]>>/, '\\', :g); 
  
          say ($name,
               .default // '',
               .inherit ?? 'Yes' !! '',
               @type.join(','),
               $synopsis-escaped,
              ).join(' | ');
      }
  }
  
  
  ```
  