Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Released on Saturday, September 5 2026
- Fixed `not <known media type>` is always false (#231)
- Fixed `calc()` computations in AoT-compiled applications (#236) @sebastienros
- Fixed usage of `calc()` with unitless scaling (multiplication / division)
- Fixed case-sensitive matching of `and` / `or` in `@supports` and `from` / `to` in `@keyframes` (#240)
- Added optional CSSOM compliant color seralization (#229) @lahma
- Added user-preference media features to the render device (#235) @lahma
- Added media query list evaluation using `IRenderDevice` (#228) @lahma
Expand Down
33 changes: 33 additions & 0 deletions src/AngleSharp.Css.Tests/Rules/CssKeyframeRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,38 @@ public void KeyframeRuleWithPercentage_Issue128()
Assert.AreEqual(3, rule.Key.Stops.Count());
Assert.AreEqual(0, rule.Style.Length);
}

[Test]
public void KeyframeRuleWithUppercaseFrom()
{
var rule = ParseKeyframeRule(@" FROM {
margin-left: 0px;
}");
Assert.IsNotNull(rule);
Assert.AreEqual("0%", rule.KeyText);
Assert.AreEqual(1, rule.Key.Stops.Count());
Assert.AreEqual(1, rule.Style.Length);
}

[Test]
public void KeyframeRuleWithUppercaseTo()
{
var rule = ParseKeyframeRule(@" TO {
margin-left: 200px;
}");
Assert.IsNotNull(rule);
Assert.AreEqual("100%", rule.KeyText);
Assert.AreEqual(1, rule.Key.Stops.Count());
Assert.AreEqual(1, rule.Style.Length);
}

[Test]
public void KeyframeRuleWithMixedCaseFromAndTo()
{
var rule = ParseKeyframeRule(@" From, To { }");
Assert.IsNotNull(rule);
Assert.AreEqual("0%, 100%", rule.KeyText);
Assert.AreEqual(2, rule.Key.Stops.Count());
}
}
}
52 changes: 52 additions & 0 deletions src/AngleSharp.Css.Tests/Rules/CssSupports.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,5 +209,57 @@ public void SupportsNegatedDisplayFlexRuleWithDeclarations()
Assert.AreEqual("not (display: flex)", supports.ConditionText);
Assert.IsFalse(supports.Condition.Check(device));
}

[Test]
public void SupportsUppercaseAndKeywordRule()
{
var source = @"@supports ((background-color: red) AND (color: blue)) { }";
var sheet = ParseStyleSheet(source);
var device = new DefaultRenderDevice();
Assert.AreEqual(1, sheet.Rules.Length);
Assert.IsInstanceOf<CssSupportsRule>(sheet.Rules[0]);
var supports = sheet.Rules[0] as CssSupportsRule;
Assert.AreEqual("((background-color: red) and (color: blue))", supports.ConditionText);
Assert.IsTrue(supports.Condition.Check(device));
}

[Test]
public void SupportsUppercaseOrKeywordRule()
{
var source = @"@supports ((background-transparency: half) OR (color: blue)) { }";
var sheet = ParseStyleSheet(source);
var device = new DefaultRenderDevice();
Assert.AreEqual(1, sheet.Rules.Length);
Assert.IsInstanceOf<CssSupportsRule>(sheet.Rules[0]);
var supports = sheet.Rules[0] as CssSupportsRule;
Assert.AreEqual("((background-transparency: half) or (color: blue))", supports.ConditionText);
Assert.IsTrue(supports.Condition.Check(device));
}

[Test]
public void SupportsMixedCaseAndKeywordChainRule()
{
var source = @"@supports ((background-color: red) And (color: blue) aND (width: 10px)) { }";
var sheet = ParseStyleSheet(source);
var device = new DefaultRenderDevice();
Assert.AreEqual(1, sheet.Rules.Length);
Assert.IsInstanceOf<CssSupportsRule>(sheet.Rules[0]);
var supports = sheet.Rules[0] as CssSupportsRule;
Assert.AreEqual("((background-color: red) and (color: blue) and (width: 10px))", supports.ConditionText);
Assert.IsTrue(supports.Condition.Check(device));
}

[Test]
public void SupportsUppercaseAndKeywordKeepsInnerRules()
{
var source = @"@supports (color: red) AND (display: flex) {
body { width: 100%; }
}";
var sheet = ParseStyleSheet(source);
Assert.AreEqual(1, sheet.Rules.Length);
Assert.IsInstanceOf<CssSupportsRule>(sheet.Rules[0]);
var supports = sheet.Rules[0] as CssSupportsRule;
Assert.AreEqual(1, supports.Rules.Length);
}
}
}
6 changes: 3 additions & 3 deletions src/AngleSharp.Css/Parser/Micro/ConditionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ private static IConditionFunction ConjunctionOrDisjunction(this StringSource sou

if (ident != null)
{
var isAnd = ident.Is(CssKeywords.And);
var isOr = ident.Is(CssKeywords.Or);
var isAnd = ident.Isi(CssKeywords.And);
var isOr = ident.Isi(CssKeywords.Or);

if (isAnd || isOr)
{
Expand Down Expand Up @@ -141,7 +141,7 @@ private static IEnumerable<IConditionFunction> Scan(this StringSource source, St
source.SkipSpacesAndComments();
ident = source.ParseIdent();
}
while (ident != null && ident.Is(keyword));
while (ident != null && ident.Isi(keyword));

return conditions;
}
Expand Down
4 changes: 2 additions & 2 deletions src/AngleSharp.Css/Parser/Micro/KeyframeParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ public static IKeyframeSelector ParseKeyframeSelector(this StringSource source)

stops.Add(test.Value);
}
else if (id.Is(CssKeywords.From))
else if (id.Isi(CssKeywords.From))
{
stops.Add(0f);
}
else if (id.Is(CssKeywords.To))
else if (id.Isi(CssKeywords.To))
{
stops.Add(1f);
}
Expand Down
Loading