diff --git a/src/browser/css/Parser.zig b/src/browser/css/Parser.zig
index 053e9435..401baecb 100644
--- a/src/browser/css/Parser.zig
+++ b/src/browser/css/Parser.zig
@@ -318,12 +318,6 @@ pub const RulesIterator = struct {
var selector_start: ?usize = null;
var selector_end: ?usize = null;
- // Skip leading trivia
- while (self.stream.peek()) |peeked| {
- if (!isWhitespaceOrComment(peeked.token)) break;
- _ = self.stream.next();
- }
-
while (true) {
const peeked = self.stream.peek() orelse return null;
@@ -370,6 +364,11 @@ pub const RulesIterator = struct {
continue;
}
+ if (selector_start == null and (isWhitespaceOrComment(peeked.token) or isSemicolon(peeked.token))) {
+ _ = self.stream.next();
+ continue;
+ }
+
const span = self.stream.next() orelse return null;
if (!isWhitespaceOrComment(span.token)) {
if (selector_start == null) selector_start = span.start;
@@ -470,3 +469,13 @@ test "RulesIterator: comments and whitespace" {
try testing.expectEqualStrings(" /* comment */ color: red; ", rule.block);
try testing.expectEqual(@as(?Rule, null), it.next());
}
+
+test "RulesIterator: top-level semicolons" {
+ var it = RulesIterator.init("*{}; ; p{}");
+ var rule = it.next() orelse return error.MissingRule;
+ try testing.expectEqualStrings("*", rule.selector);
+
+ rule = it.next() orelse return error.MissingRule;
+ try testing.expectEqualStrings("p", rule.selector);
+ try testing.expectEqual(@as(?Rule, null), it.next());
+}
diff --git a/src/browser/tests/css/stylesheet.html b/src/browser/tests/css/stylesheet.html
index 8e284e66..41ed60df 100644
--- a/src/browser/tests/css/stylesheet.html
+++ b/src/browser/tests/css/stylesheet.html
@@ -468,6 +468,18 @@
}
+
+