Class: CSS::Cascade

Inherits:
Object
  • Object
show all
Defined in:
lib/css/cascade.rb

Overview

Resolves the cascade for a Stylesheet against a single element. Returns ‘Hash<String, Declaration>` keyed by property name with the winning declaration after applying:

- `@media` filtering (against a `MediaQueries::Context`)
- selector matching (`Selectors::Matcher`)
- cascade sort: `!important` > origin / inline > specificity > source order

The Stylesheet is compiled once on construction (selectors are pre-parsed, specificities pre-computed, ‘@media` chains are evaluated against the supplied context up-front, and rules are indexed by the rightmost compound’s strongest anchor — id > class > tag > universal). ‘resolve(element)` then visits only the rules whose anchor could match the element.

Cascade layers, ‘@scope` proximity, and Shadow DOM encapsulation are not modeled — `@layer`, `@supports`, `@container`, `@scope`, and `@starting-style` blocks are descended into unconditionally.

Defined Under Namespace

Classes: AnchorKey, Index, Match, RuleEntry

Constant Summary collapse

TRANSPARENT_AT_RULES =
%w[supports layer scope starting-style container].freeze

Instance Method Summary collapse

Constructor Details

#initialize(stylesheet, context: MediaQueries::Context.default) ⇒ Cascade

Returns a new instance of Cascade.



27
28
29
30
31
# File 'lib/css/cascade.rb', line 27

def initialize(stylesheet, context: MediaQueries::Context.default)
  @context = context
  @entries = compile(stylesheet)
  @index   = build_index(@entries)
end

Instance Method Details

#resolve(element, inline_style: nil) ⇒ Object

Returns Hash<String, Declaration> of winning declarations.



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/css/cascade.rb', line 34

def resolve(element, inline_style: nil)
  cache       = {}
  candidates  = collect_candidate_indexes(element, cache)
  order       = 0
  matches     = []

  candidates.each do |idx|
    entry = @entries[idx]
    spec  = best_matching_specificity(element, entry.selector_pairs, cache)

    next if spec.nil?

    entry.declarations.each do |decl|
      order += 1
      matches << Match.new(declaration: decl, specificity: spec, inline: false, order: order)
    end
  end

  if inline_style
    inline_declarations(inline_style).each do |decl|
      order += 1
      matches << Match.new(declaration: decl, specificity: Selectors::Specificity::ZERO, inline: true, order: order)
    end
  end

  pick_winners(matches)
end