欢迎光临
我们一直在努力

手搓CSS解析器:实现完整选择器匹配与样式计算

手搓CSS解析器:实现完整选择器匹配与样式计算

引言:CSS解析的奥秘

在当今Web开发领域,CSS(层叠样式表)是构建美观用户界面的核心技术之一。浏览器如何将看似简单的CSS规则转换为屏幕上精美的视觉效果?这个看似神奇的过程背后,是一套复杂而精密的解析引擎。本文将深入探讨如何从零开始构建一个完整的CSS解析器,实现选择器匹配与样式计算的全过程。

传统前端开发中,我们通常将CSS视为一种声明式语言,只需编写规则,浏览器便会自动应用。然而,当我们需要构建自定义样式引擎、实现CSS-in-JS解决方案、开发可视化CSS编辑器,或是优化样式性能时,深入理解CSS解析机制变得至关重要。手写CSS解析器不仅能加深对Web标准的理解,还能为解决复杂样式问题提供新的思路。

第一章:CSS解析器架构设计

1.1 CSS处理流程概述

浏览器处理CSS的过程可分为多个阶段:

  • 加载与解析:读取CSS文件,解析为结构化数据

  • 规则匹配:将CSS规则与DOM元素进行匹配

  • 样式计算:计算每个元素最终应用的样式值

  • 布局计算:根据样式计算元素布局

  • 绘制与合成:将元素绘制到屏幕上

  • 本文将重点聚焦前三个阶段:解析、匹配和计算。

    1.2 解析器整体架构

    我们将构建的CSS解析器包含以下核心模块:

    text

    CSS解析器架构:
    ├── 词法分析器 (Lexer)
    │ ├── 字符流处理
    │ ├── Token生成
    │ └── 错误恢复机制
    ├── 语法分析器 (Parser)
    │ ├── 规则解析
    │ ├── 选择器解析
    │ └── 声明解析
    ├── 样式规则管理器
    │ ├── 规则存储
    │ ├── 规则索引
    │ └── 规则排序
    ├── 选择器匹配引擎
    │ ├── 选择器解析
    │ ├── 元素匹配算法
    │ └── 伪类/伪元素处理
    └── 样式计算器
    ├── 层叠计算
    ├── 继承处理
    ├── 默认值填充
    └── 计算值转换

    1.3 数据结构设计

    我们需要定义几个核心数据结构:

    javascript

    // CSS Token类型
    const TokenType = {
    IDENT: 'IDENT', // 标识符
    STRING: 'STRING', // 字符串
    NUMBER: 'NUMBER', // 数字
    PERCENTAGE: 'PERCENTAGE', // 百分比
    DIMENSION: 'DIMENSION', // 带单位的数值
    COLON: 'COLON', // 冒号
    SEMICOLON: 'SEMICOLON', // 分号
    COMMA: 'COMMA', // 逗号
    LEFT_BRACE: 'LEFT_BRACE', // 左大括号
    RIGHT_BRACE: 'RIGHT_BRACE', // 右大括号
    LEFT_PAREN: 'LEFT_PAREN', // 左括号
    RIGHT_PAREN: 'RIGHT_PAREN', // 右括号
    LEFT_BRACKET: 'LEFT_BRACKET', // 左中括号
    RIGHT_BRACKET: 'RIGHT_BRACKET', // 右中括号
    HASH: 'HASH', // #号
    DOT: 'DOT', // 点号
    AT_KEYWORD: 'AT_KEYWORD', // @规则
    DELIM: 'DELIM', // 分隔符
    WHITESPACE: 'WHITESPACE', // 空白字符
    COMMENT: 'COMMENT', // 注释
    EOF: 'EOF' // 文件结束
    };

    // CSS规则表示
    class CSSRule {
    constructor(selectors, declarations, specificity, position) {
    this.selectors = selectors; // 选择器列表
    this.declarations = declarations; // 声明集合
    this.specificity = specificity; // 选择器优先级
    this.position = position; // 规则位置(用于层叠排序)
    }
    }

    // 样式声明
    class CSSDeclaration {
    constructor(property, value, important = false) {
    this.property = property; // 属性名
    this.value = value; // 属性值
    this.important = important; // !important标记
    }
    }

    // 选择器表示
    class Selector {
    constructor(selectorText, specificity) {
    this.selectorText = selectorText; // 选择器文本
    this.specificity = specificity; // 优先级值
    this.components = []; // 选择器组件
    }
    }

    第二章:词法分析器实现

    2.1 字符流处理

    词法分析器的首要任务是读取CSS源码并将其转换为一系列有意义的Token。我们需要一个字符流处理器来管理源码读取:

    javascript

    class CharStream {
    constructor(source) {
    this.source = source; // CSS源码
    this.position = 0; // 当前位置
    this.line = 1; // 当前行号
    this.column = 0; // 当前列号
    }

    // 查看下一个字符但不移动指针
    peek(offset = 0) {
    return this.source[this.position + offset] || '';
    }

    // 读取下一个字符并移动指针
    next() {
    const char = this.peek();
    if (char) {
    this.position++;
    if (char === '\\n') {
    this.line++;
    this.column = 0;
    } else {
    this.column++;
    }
    }
    return char;
    }

    // 检查是否到达结尾
    eof() {
    return this.position >= this.source.length;
    }

    // 回溯到上一个位置
    rewind(amount = 1) {
    this.position = Math.max(0, this.position – amount);
    // 注意:回溯时行号列号计算简化处理,实际实现需要更精确
    }
    }

    2.2 Token生成器

    基于字符流,我们可以构建Token生成器:

    javascript

    class CSSLexer {
    constructor(source) {
    this.stream = new CharStream(source);
    this.currentToken = null;
    }

    // 获取下一个Token
    nextToken() {
    this.skipWhitespaceAndComments();

    if (this.stream.eof()) {
    return this.createToken(TokenType.EOF, '');
    }

    const char = this.stream.peek();

    // 标识符或关键字
    if (this.isIdentStart(char)) {
    return this.scanIdent();
    }

    // 数字
    if (this.isDigit(char) || (char === '.' && this.isDigit(this.stream.peek(1)))) {
    return this.scanNumeric();
    }

    // 字符串
    if (char === '"' || char === "'") {
    return this.scanString();
    }

    // Hash值(如#fff)
    if (char === '#') {
    return this.scanHash();
    }

    // 符号处理
    switch (char) {
    case '{':
    this.stream.next();
    return this.createToken(TokenType.LEFT_BRACE, '{');
    case '}':
    this.stream.next();
    return this.createToken(TokenType.RIGHT_BRACE, '}');
    case ':':
    this.stream.next();
    return this.createToken(TokenType.COLON, ':');
    case ';':
    this.stream.next();
    return this.createToken(TokenType.SEMICOLON, ';');
    case ',':
    this.stream.next();
    return this.createToken(TokenType.COMMA, ',');
    case '(':
    this.stream.next();
    return this.createToken(TokenType.LEFT_PAREN, '(');
    case ')':
    this.stream.next();
    return this.createToken(TokenType.RIGHT_PAREN, ')');
    case '[':
    this.stream.next();
    return this.createToken(TokenType.LEFT_BRACKET, '[');
    case ']':
    this.stream.next();
    return this.createToken(TokenType.RIGHT_BRACKET, ']');
    case '.':
    this.stream.next();
    return this.createToken(TokenType.DOT, '.');
    case '@':
    return this.scanAtKeyword();
    }

    // 默认作为分隔符处理
    this.stream.next();
    return this.createToken(TokenType.DELIM, char);
    }

    // 扫描标识符
    scanIdent() {
    let value = '';

    // 读取标识符起始字符
    value += this.stream.next();

    // 读取标识符其余部分
    while (!this.stream.eof()) {
    const char = this.stream.peek();
    if (this.isIdentChar(char)) {
    value += this.stream.next();
    } else {
    break;
    }
    }

    // 检查是否为CSS关键字
    if (this.isCSSKeyword(value)) {
    return this.createToken(this.getKeywordTokenType(value), value);
    }

    return this.createToken(TokenType.IDENT, value);
    }

    // 扫描数字
    scanNumeric() {
    let value = '';
    let type = TokenType.NUMBER;

    // 读取数字部分
    while (!this.stream.eof() && this.isDigit(this.stream.peek())) {
    value += this.stream.next();
    }

    // 检查小数点
    if (this.stream.peek() === '.' && this.isDigit(this.stream.peek(1))) {
    value += this.stream.next(); // 小数点
    while (!this.stream.eof() && this.isDigit(this.stream.peek())) {
    value += this.stream.next();
    }
    }

    // 检查单位
    if (!this.stream.eof()) {
    const nextChar = this.stream.peek();
    if (this.isIdentStart(nextChar)) {
    const unitStart = this.stream.position;
    const unit = this.scanIdent().value;

    // 百分比特殊处理
    if (unit === '%') {
    type = TokenType.PERCENTAGE;
    value += unit;
    } else {
    type = TokenType.DIMENSION;
    value += unit;
    }
    }
    }

    return this.createToken(type, value);
    }

    // 辅助方法
    isDigit(char) {
    return /[0-9]/.test(char);
    }

    isIdentStart(char) {
    return /[a-zA-Z_]/.test(char) || char.charCodeAt(0) > 127;
    }

    isIdentChar(char) {
    return this.isIdentStart(char) || /[0-9-]/.test(char);
    }

    skipWhitespaceAndComments() {
    while (!this.stream.eof()) {
    const char = this.stream.peek();

    // 跳过空白字符
    if (/\\s/.test(char)) {
    this.stream.next();
    continue;
    }

    // 处理注释
    if (char === '/' && this.stream.peek(1) === '*') {
    this.skipComment();
    continue;
    }

    break;
    }
    }

    skipComment() {
    // 跳过 /*
    this.stream.next();
    this.stream.next();

    // 直到遇到 */
    while (!this.stream.eof()) {
    if (this.stream.peek() === '*' && this.stream.peek(1) === '/') {
    this.stream.next();
    this.stream.next();
    break;
    }
    this.stream.next();
    }
    }

    createToken(type, value) {
    return {
    type,
    value,
    line: this.stream.line,
    column: this.stream.column
    };
    }
    }

    2.3 词法分析优化

    实际应用中,我们需要对词法分析器进行优化:

    javascript

    class OptimizedCSSLexer extends CSSLexer {
    constructor(source) {
    super(source);
    this.tokenCache = []; // Token缓存
    this.cacheIndex = 0; // 缓存索引
    this.lookaheadTokens = []; // 预读Token
    }

    // 带缓存的Token获取
    nextToken() {
    if (this.cacheIndex < this.tokenCache.length) {
    return this.tokenCache[this.cacheIndex++];
    }

    const token = super.nextToken();
    this.tokenCache.push(token);
    this.cacheIndex++;
    return token;
    }

    // 查看未来第n个Token
    peekToken(n = 0) {
    while (this.lookaheadTokens.length <= n) {
    const token = super.nextToken();
    this.lookaheadTokens.push(token);
    }
    return this.lookaheadTokens[n];
    }

    // 消耗一个Token
    consumeToken() {
    if (this.lookaheadTokens.length > 0) {
    const token = this.lookaheadTokens.shift();
    this.tokenCache.push(token);
    this.cacheIndex++;
    return token;
    }
    return this.nextToken();
    }

    // 回溯到指定位置
    rewindTo(position) {
    this.cacheIndex = Math.max(0, Math.min(position, this.tokenCache.length));
    }
    }

    第三章:语法分析器构建

    3.1 CSS语法规则定义

    CSS语法可以形式化表示为:

    text

    stylesheet : [ CDO | CDC | S | statement ]*;
    statement : ruleset | at-rule;
    ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
    selector : simple_selector [ combinator simple_selector ]*;
    simple_selector : element_name? [ HASH | class | attrib | pseudo ]* S*;
    declaration : property S* ':' S* value;
    property : IDENT;
    value : [ any | block | ATKEYWORD S* ]+;

    3.2 语法分析器实现

    语法分析器将Token流转换为抽象语法树(AST):

    javascript

    class CSSParser {
    constructor(lexer) {
    this.lexer = lexer;
    this.currentToken = null;
    this.rules = [];
    this.errors = [];
    }

    // 解析整个样式表
    parseStylesheet() {
    const rules = [];

    while (!this.isTokenType(TokenType.EOF)) {
    this.consumeWhitespace();

    if (this.isTokenType(TokenType.AT_KEYWORD)) {
    const atRule = this.parseAtRule();
    if (atRule) rules.push(atRule);
    } else if (this.isTokenType(TokenType.IDENT) || this.isTokenType(TokenType.HASH) ||
    this.isTokenType(TokenType.DOT) || this.isTokenType(TokenType.LEFT_BRACKET) ||
    this.isTokenType(TokenType.COLON) || this.isTokenType(TokenType.DELIM)) {
    const rule = this.parseRule();
    if (rule) rules.push(rule);
    } else if (!this.isTokenType(TokenType.EOF)) {
    this.reportError(`Unexpected token: ${this.currentToken.value}`);
    this.consumeToken();
    }
    }

    return rules;
    }

    // 解析CSS规则
    parseRule() {
    try {
    // 解析选择器
    const selectors = this.parseSelectors();

    // 期望左大括号
    this.expectToken(TokenType.LEFT_BRACE);

    // 解析声明块
    const declarations = this.parseDeclarationBlock();

    // 期望右大括号
    this.expectToken(TokenType.RIGHT_BRACE);

    // 计算选择器优先级
    const specificity = this.calculateSpecificity(selectors);

    return new CSSRule(
    selectors,
    declarations,
    specificity,
    { line: this.currentToken.line, column: this.currentToken.column }
    );
    } catch (error) {
    this.reportError(error.message);
    this.recoverFromError();
    return null;
    }
    }

    // 解析选择器列表
    parseSelectors() {
    const selectors = [];
    let currentSelector = '';

    while (!this.isTokenType(TokenType.LEFT_BRACE) && !this.isTokenType(TokenType.EOF)) {
    const token = this.consumeToken();

    if (token.type === TokenType.COMMA) {
    if (currentSelector.trim()) {
    selectors.push(this.parseSelector(currentSelector));
    currentSelector = '';
    }
    } else {
    currentSelector += token.value;
    }
    }

    // 处理最后一个选择器
    if (currentSelector.trim()) {
    selectors.push(this.parseSelector(currentSelector));
    }

    return selectors;
    }

    // 解析单个选择器
    parseSelector(selectorText) {
    // 移除首尾空白
    selectorText = selectorText.trim();

    // 解析选择器组件
    const components = this.parseSelectorComponents(selectorText);

    // 计算优先级
    const specificity = this.calculateSelectorSpecificity(components);

    return new Selector(selectorText, specificity, components);
    }

    // 解析选择器组件
    parseSelectorComponents(selectorText) {
    const components = [];
    let buffer = '';
    let inAttribute = false;
    let inPseudo = false;
    let parenDepth = 0;

    for (let i = 0; i < selectorText.length; i++) {
    const char = selectorText[i];

    if (char === '[' && !inPseudo) {
    inAttribute = true;
    buffer += char;
    } else if (char === ']' && inAttribute) {
    inAttribute = false;
    buffer += char;
    components.push({ type: 'attribute', value: buffer });
    buffer = '';
    } else if (char === ':' && !inAttribute) {
    if (buffer) {
    components.push({ type: 'element', value: buffer });
    buffer = '';
    }
    inPseudo = true;
    buffer += char;
    } else if (char === '(' && inPseudo) {
    parenDepth++;
    buffer += char;
    } else if (char === ')' && inPseudo) {
    parenDepth–;
    buffer += char;
    if (parenDepth === 0) {
    components.push({ type: 'pseudo', value: buffer });
    buffer = '';
    inPseudo = false;
    }
    } else if ((char === ' ' || char === '>' || char === '+' || char === '~') &&
    !inAttribute && !inPseudo && parenDepth === 0) {
    if (buffer) {
    components.push({ type: 'element', value: buffer });
    buffer = '';
    }
    components.push({ type: 'combinator', value: char });
    } else if (char === '.' && !inAttribute && !inPseudo) {
    if (buffer) {
    components.push({ type: 'element', value: buffer });
    buffer = '';
    }
    buffer = char;
    } else if (char === '#' && !inAttribute && !inPseudo) {
    if (buffer) {
    components.push({ type: 'element', value: buffer });
    buffer = '';
    }
    buffer = char;
    } else {
    buffer += char;
    }
    }

    // 处理最后一部分
    if (buffer) {
    if (buffer.startsWith('.')) {
    components.push({ type: 'class', value: buffer });
    } else if (buffer.startsWith('#')) {
    components.push({ type: 'id', value: buffer });
    } else if (!inAttribute && !inPseudo) {
    components.push({ type: 'element', value: buffer });
    }
    }

    return components;
    }

    // 解析声明块
    parseDeclarationBlock() {
    const declarations = [];

    this.consumeWhitespace();

    while (!this.isTokenType(TokenType.RIGHT_BRACE) && !this.isTokenType(TokenType.EOF)) {
    const declaration = this.parseDeclaration();
    if (declaration) {
    declarations.push(declaration);
    }

    // 跳过可选的分号
    if (this.isTokenType(TokenType.SEMICOLON)) {
    this.consumeToken();
    }

    this.consumeWhitespace();
    }

    return declarations;
    }

    // 解析单个声明
    parseDeclaration() {
    // 期望属性名
    if (!this.isTokenType(TokenType.IDENT)) {
    this.reportError(`Expected property name, got ${this.currentToken.type}`);
    return null;
    }

    const property = this.consumeToken().value;

    this.consumeWhitespace();

    // 期望冒号
    this.expectToken(TokenType.COLON);

    this.consumeWhitespace();

    // 解析属性值
    const valueTokens = [];
    let important = false;

    // 收集值Token,直到遇到分号或右大括号
    while (!this.isTokenType(TokenType.SEMICOLON) &&
    !this.isTokenType(TokenType.RIGHT_BRACE) &&
    !this.isTokenType(TokenType.EOF)) {

    const token = this.consumeToken();

    // 检查!important
    if (token.type === TokenType.DELIM && token.value === '!') {
    const nextToken = this.peekToken();
    if (nextToken && nextToken.type === TokenType.IDENT &&
    nextToken.value.toLowerCase() === 'important') {
    this.consumeToken(); // 消耗'important'
    important = true;
    break;
    }
    }

    valueTokens.push(token);
    }

    // 组合值Token
    const value = valueTokens.map(t => t.value).join('').trim();

    return new CSSDeclaration(property, value, important);
    }

    // 计算选择器优先级
    calculateSelectorSpecificity(components) {
    let a = 0; // ID选择器
    let b = 0; // 类选择器、属性选择器、伪类
    let c = 0; // 类型选择器、伪元素

    for (const component of components) {
    switch (component.type) {
    case 'id':
    a++;
    break;
    case 'class':
    case 'attribute':
    case 'pseudo':
    // 检查是否为伪类(:hover等)而不是伪元素(::before)
    if (component.type === 'pseudo' && component.value.startsWith('::')) {
    c++;
    } else if (component.type === 'pseudo') {
    b++;
    } else {
    b++;
    }
    break;
    case 'element':
    // 忽略通用选择器(*)
    if (component.value !== '*') {
    c++;
    }
    break;
    }
    }

    return (a << 16) | (b << 8) | c;
    }

    // 辅助方法
    consumeToken() {
    if (!this.currentToken) {
    this.currentToken = this.lexer.nextToken();
    }
    const token = this.currentToken;
    this.currentToken = this.lexer.nextToken();
    return token;
    }

    peekToken() {
    if (!this.currentToken) {
    this.currentToken = this.lexer.nextToken();
    }
    return this.currentToken;
    }

    isTokenType(type) {
    const token = this.peekToken();
    return token.type === type;
    }

    expectToken(type) {
    const token = this.consumeToken();
    if (token.type !== type) {
    throw new Error(`Expected ${type}, got ${token.type}`);
    }
    return token;
    }

    consumeWhitespace() {
    while (this.isTokenType(TokenType.WHITESPACE)) {
    this.consumeToken();
    }
    }

    reportError(message) {
    this.errors.push({
    message,
    line: this.currentToken ? this.currentToken.line : 0,
    column: this.currentToken ? this.currentToken.column : 0
    });
    }

    recoverFromError() {
    // 跳过直到找到右大括号或分号
    while (!this.isTokenType(TokenType.RIGHT_BRACE) &&
    !this.isTokenType(TokenType.SEMICOLON) &&
    !this.isTokenType(TokenType.EOF)) {
    this.consumeToken();
    }
    }
    }

    3.3 语法树优化

    为了提高解析效率,我们可以对语法树进行优化:

    javascript

    class OptimizedCSSParser extends CSSParser {
    constructor(lexer) {
    super(lexer);
    this.selectorCache = new Map(); // 选择器解析缓存
    this.declarationCache = new Map(); // 声明解析缓存
    }

    // 缓存选择器解析结果
    parseSelector(selectorText) {
    if (this.selectorCache.has(selectorText)) {
    return this.selectorCache.get(selectorText);
    }

    const selector = super.parseSelector(selectorText);
    this.selectorCache.set(selectorText, selector);
    return selector;
    }

    // 优化声明解析
    parseDeclaration() {
    const startPos = this.lexer.stream.position;
    const declaration = super.parseDeclaration();

    if (declaration) {
    const cacheKey = `${declaration.property}:${declaration.value}:${declaration.important}`;
    this.declarationCache.set(cacheKey, declaration);
    }

    return declaration;
    }
    }

    第四章:选择器匹配引擎

    4.1 选择器匹配算法

    选择器匹配是CSS引擎的核心功能。我们需要实现多种选择器类型的匹配逻辑:

    javascript

    class SelectorMatcher {
    constructor() {
    this.matchers = {
    // 元素选择器匹配
    element: (element, selector) => {
    const tagName = element.tagName.toLowerCase();
    const selectorName = selector.value.toLowerCase();
    return selectorName === '*' || tagName === selectorName;
    },

    // 类选择器匹配
    class: (element, selector) => {
    const className = selector.value.substring(1); // 去掉开头的.
    return element.classList.contains(className);
    },

    // ID选择器匹配
    id: (element, selector) => {
    const idValue = selector.value.substring(1); // 去掉开头的#
    return element.id === idValue;
    },

    // 属性选择器匹配
    attribute: (element, selector) => {
    const attrSelector = selector.value;
    // 简化的属性选择器解析
    // 支持 [attr], [attr=value], [attr~=value], [attr|=value], [attr^=value], [attr$=value], [attr*=value]

    // 提取属性名和操作符
    const match = attrSelector.match(/\\[([^\\]=~|\\^\\$\\*]+)(?:([~|^$*]?=)["']?([^"'\\]]+)["']?)?\\]/);
    if (!match) return false;

    const [, attrName, operator, expectedValue] = match;
    const actualValue = element.getAttribute(attrName);

    if (actualValue === null) return false;

    if (!operator) {
    // [attr] 形式:只要属性存在
    return true;
    }

    switch (operator) {
    case '=':
    return actualValue === expectedValue;
    case '~=':
    return actualValue.split(/\\s+/).includes(expectedValue);
    case '|=':
    return actualValue === expectedValue ||
    actualValue.startsWith(expectedValue + '-');
    case '^=':
    return actualValue.startsWith(expectedValue);
    case '$=':
    return actualValue.endsWith(expectedValue);
    case '*=':
    return actualValue.includes(expectedValue);
    default:
    return false;
    }
    },

    // 伪类匹配
    pseudo: (element, selector, context) => {
    const pseudoValue = selector.value.toLowerCase();

    // 结构伪类
    if (pseudoValue.startsWith(':nth-child')) {
    return this.matchNthChild(element, pseudoValue);
    } else if (pseudoValue.startsWith(':nth-of-type')) {
    return this.matchNthOfType(element, pseudoValue);
    } else if (pseudoValue === ':first-child') {
    return this.matchFirstChild(element);
    } else if (pseudoValue === ':last-child') {
    return this.matchLastChild(element);
    } else if (pseudoValue === ':only-child') {
    return this.matchOnlyChild(element);
    }

    // 状态伪类
    if (pseudoValue === ':hover') {
    return context.isHovered && context.isHovered(element);
    } else if (pseudoValue === ':focus') {
    return context.isFocused && context.isFocused(element);
    } else if (pseudoValue === ':checked') {
    return element.checked === true;
    } else if (pseudoValue === ':disabled') {
    return element.disabled === true;
    } else if (pseudoValue === ':enabled') {
    return !element.disabled;
    }

    // 默认返回false,不支持所有伪类
    return false;
    }
    };
    }

    // 匹配第n个子元素
    matchNthChild(element, pseudoValue) {
    const match = pseudoValue.match(/:nth-child\\(([^)]+)\\)/);
    if (!match) return false;

    const formula = match[1].trim();
    const parent = element.parentElement;
    if (!parent) return false;

    const children = Array.from(parent.children);
    const index = children.indexOf(element) + 1; // nth-child是从1开始的

    return this.evaluateNthFormula(formula, index);
    }

    // 匹配第n个类型元素
    matchNthOfType(element, pseudoValue) {
    const match = pseudoValue.match(/:nth-of-type\\(([^)]+)\\)/);
    if (!match) return false;

    const formula = match[1].trim();
    const parent = element.parentElement;
    if (!parent) return false;

    const siblings = Array.from(parent.children)
    .filter(child => child.tagName === element.tagName);
    const index = siblings.indexOf(element) + 1;

    return this.evaluateNthFormula(formula, index);
    }

    // 评估nth公式
    evaluateNthFormula(formula, index) {
    // 处理特殊关键字
    if (formula === 'odd') {
    return index % 2 === 1;
    } else if (formula === 'even') {
    return index % 2 === 0;
    }

    // 处理An+B格式
    const match = formula.match(/^(-?\\d*)?n([+-]\\d+)?$/);
    if (match) {
    const [, aStr, bStr] = match;
    const a = aStr === '' ? 1 : aStr === '-' ? -1 : parseInt(aStr || 0);
    const b = bStr ? parseInt(bStr) : 0;

    if (a === 0) {
    return index === b;
    }

    // 检查是否满足 index = a * n + b
    const n = (index – b) / a;
    return n >= 0 && Number.isInteger(n);
    }

    // 处理单个数字
    const singleNumber = parseInt(formula);
    if (!isNaN(singleNumber)) {
    return index === singleNumber;
    }

    return false;
    }

    // 匹配第一个子元素
    matchFirstChild(element) {
    const parent = element.parentElement;
    if (!parent) return false;
    return parent.firstElementChild === element;
    }

    // 匹配最后一个子元素
    matchLastChild(element) {
    const parent = element.parentElement;
    if (!parent) return false;
    return parent.lastElementChild === element;
    }

    // 匹配唯一子元素
    matchOnlyChild(element) {
    const parent = element.parentElement;
    if (!parent) return false;
    return parent.children.length === 1 && parent.firstElementChild === element;
    }

    // 匹配组合选择器
    matchCombinedSelector(element, selector, context) {
    const components = selector.components;
    let currentElement = element;
    let componentIndex = components.length – 1;

    while (componentIndex >= 0 && currentElement) {
    const component = components[componentIndex];

    if (component.type === 'combinator') {
    // 处理组合符
    switch (component.value) {
    case ' ':
    // 后代选择器:移动到父元素
    currentElement = currentElement.parentElement;
    componentIndex–;
    break;
    case '>':
    // 子选择器:检查父元素
    const parent = currentElement.parentElement;
    if (!parent) return false;

    // 检查父元素是否匹配前一个组件
    componentIndex–;
    if (componentIndex >= 0) {
    const prevComponent = components[componentIndex];
    if (!this.matchComponent(parent, prevComponent, context)) {
    return false;
    }
    currentElement = parent;
    componentIndex–;
    }
    break;
    case '+':
    // 相邻兄弟选择器
    const prevSibling = currentElement.previousElementSibling;
    if (!prevSibling) return false;

    componentIndex–;
    if (componentIndex >= 0) {
    const prevComponent = components[componentIndex];
    if (!this.matchComponent(prevSibling, prevComponent, context)) {
    return false;
    }
    currentElement = prevSibling;
    componentIndex–;
    }
    break;
    case '~':
    // 通用兄弟选择器
    let found = false;
    let sibling = currentElement.previousElementSibling;

    componentIndex–;
    if (componentIndex < 0) return false;

    const targetComponent = components[componentIndex];

    while (sibling) {
    if (this.matchComponent(sibling, targetComponent, context)) {
    found = true;
    currentElement = sibling;
    break;
    }
    sibling = sibling.previousElementSibling;
    }

    if (!found) return false;
    componentIndex–;
    break;
    }
    } else {
    // 检查当前元素是否匹配组件
    if (!this.matchComponent(currentElement, component, context)) {
    return false;
    }
    componentIndex–;
    }
    }

    return componentIndex < 0;
    }

    // 匹配单个组件
    matchComponent(element, component, context) {
    const matcher = this.matchers[component.type];
    if (!matcher) {
    console.warn(`No matcher for component type: ${component.type}`);
    return false;
    }

    return matcher(element, component, context);
    }

    // 检查元素是否匹配选择器
    matchesSelector(element, selector, context = {}) {
    return this.matchCombinedSelector(element, selector, context);
    }
    }

    4.2 规则索引与快速匹配

    为了提高匹配效率,我们需要建立规则索引:

    javascript

    class RuleIndex {
    constructor() {
    // 按选择器类型索引
    this.idIndex = new Map(); // #id选择器
    this.classIndex = new Map(); // .class选择器
    this.tagIndex = new Map(); // tag选择器
    this.attributeIndex = new Map(); // [attr]选择器
    this.universalRules = []; // *选择器
    this.otherRules = []; // 其他选择器
    }

    // 添加规则到索引
    addRule(rule) {
    for (const selector of rule.selectors) {
    this.indexSelector(selector, rule);
    }
    }

    // 索引选择器
    indexSelector(selector, rule) {
    const components = selector.components;

    // 从右向左查找关键组件(最右侧的简单选择器)
    for (let i = components.length – 1; i >= 0; i–) {
    const component = components[i];

    if (component.type === 'id') {
    // ID选择器
    const id = component.value.substring(1); // 去掉#
    if (!this.idIndex.has(id)) {
    this.idIndex.set(id, []);
    }
    this.idIndex.get(id).push({ selector, rule });
    return;
    } else if (component.type === 'class') {
    // 类选择器
    const className = component.value.substring(1); // 去掉.
    if (!this.classIndex.has(className)) {
    this.classIndex.set(className, []);
    }
    this.classIndex.get(className).push({ selector, rule });
    return;
    } else if (component.type === 'element' && component.value !== '*') {
    // 元素选择器(非通配符)
    const tagName = component.value.toLowerCase();
    if (!this.tagIndex.has(tagName)) {
    this.tagIndex.set(tagName, []);
    }
    this.tagIndex.get(tagName).push({ selector, rule });
    return;
    } else if (component.type === 'attribute') {
    // 属性选择器
    const attrMatch = component.value.match(/\\[([^\\]=~|\\^\\$\\*]+)/);
    if (attrMatch) {
    const attrName = attrMatch[1];
    if (!this.attributeIndex.has(attrName)) {
    this.attributeIndex.set(attrName, []);
    }
    this.attributeIndex.get(attrName).push({ selector, rule });
    return;
    }
    } else if (component.type === 'element' && component.value === '*') {
    // 通配符选择器
    this.universalRules.push({ selector, rule });
    return;
    }
    }

    // 没有找到关键组件,放入其他规则
    this.otherRules.push({ selector, rule });
    }

    // 查找匹配元素的规则
    findMatchingRules(element, matcher, context = {}) {
    const matchingRules = [];

    // 检查ID索引
    if (element.id) {
    const idRules = this.idIndex.get(element.id);
    if (idRules) {
    this.testRules(idRules, element, matcher, context, matchingRules);
    }
    }

    // 检查类索引
    if (element.classList && element.classList.length > 0) {
    for (const className of element.classList) {
    const classRules = this.classIndex.get(className);
    if (classRules) {
    this.testRules(classRules, element, matcher, context, matchingRules);
    }
    }
    }

    // 检查标签索引
    const tagName = element.tagName.toLowerCase();
    const tagRules = this.tagIndex.get(tagName);
    if (tagRules) {
    this.testRules(tagRules, element, matcher, context, matchingRules);
    }

    // 检查属性索引
    if (element.attributes) {
    for (const attr of element.attributes) {
    const attrRules = this.attributeIndex.get(attr.name);
    if (attrRules) {
    this.testRules(attrRules, element, matcher, context, matchingRules);
    }
    }
    }

    // 检查通配符规则
    this.testRules(this.universalRules, element, matcher, context, matchingRules);

    // 检查其他规则
    this.testRules(this.otherRules, element, matcher, context, matchingRules);

    return matchingRules;
    }

    // 测试规则是否匹配
    testRules(ruleEntries, element, matcher, context, matchingRules) {
    for (const entry of ruleEntries) {
    if (matcher.matchesSelector(element, entry.selector, context)) {
    if (!matchingRules.includes(entry.rule)) {
    matchingRules.push(entry.rule);
    }
    }
    }
    }
    }

    第五章:样式计算引擎

    5.1 层叠与优先级计算

    CSS的核心特性之一是层叠(Cascade),它决定了当多个规则应用于同一元素时,哪个规则最终生效:

    javascript

    class StyleCascade {
    constructor() {
    this.defaultStyles = this.createDefaultStyles();
    this.userAgentStyles = this.createUserAgentStyles();
    this.inheritedProperties = this.getInheritedProperties();
    }

    // 计算元素的最终样式
    computeElementStyles(element, matchingRules, importantDeclarations = []) {
    // 收集所有适用的声明
    const declarations = this.collectDeclarations(
    element,
    matchingRules,
    importantDeclarations
    );

    // 按优先级排序
    this.sortDeclarationsBySpecificity(declarations);

    // 应用层叠
    const computedStyles = this.applyCascade(declarations);

    // 处理继承
    this.applyInheritance(element, computedStyles);

    // 应用默认值
    this.applyDefaults(computedStyles);

    return computedStyles;
    }

    // 收集所有声明
    collectDeclarations(element, matchingRules, importantDeclarations) {
    const declarations = [];

    // 1. 用户代理样式(最低优先级)
    for (const rule of this.userAgentStyles) {
    if (this.elementMatchesRule(element, rule)) {
    declarations.push(…rule.declarations.map(d => ({
    …d,
    source: 'user-agent',
    specificity: { a: 0, b: 0, c: 0 }
    })));
    }
    }

    // 2. 用户样式(普通)
    for (const rule of matchingRules) {
    declarations.push(…rule.declarations.map(d => ({
    …d,
    source: 'author',
    specificity: rule.specificity,
    rulePosition: rule.position
    })));
    }

    // 3. 重要声明(作者)
    for (const declaration of importantDeclarations) {
    declarations.push({
    …declaration,
    source: 'author',
    important: true,
    specificity: { a: 0, b: 0, c: 0 } // 内联样式无选择器
    });
    }

    return declarations;
    }

    // 按优先级排序声明
    sortDeclarationsBySpecificity(declarations) {
    declarations.sort((a, b) => {
    // 1. 重要性比较
    if (a.important && !b.important) return 1;
    if (!a.important && b.important) return -1;

    // 2. 来源比较
    const sourceOrder = { 'user-agent': 0, 'author': 1 };
    if (sourceOrder[a.source] !== sourceOrder[b.source]) {
    return sourceOrder[b.source] – sourceOrder[a.source];
    }

    // 3. 选择器优先级比较
    if (a.specificity !== b.specificity) {
    return this.compareSpecificity(a.specificity, b.specificity);
    }

    // 4. 位置比较(后出现的覆盖先出现的)
    if (a.rulePosition && b.rulePosition) {
    if (a.rulePosition.line !== b.rulePosition.line) {
    return a.rulePosition.line – b.rulePosition.line;
    }
    return a.rulePosition.column – b.rulePosition.column;
    }

    return 0;
    });
    }

    // 比较选择器优先级
    compareSpecificity(specA, specB) {
    // 假设specificity是一个包含a, b, c三个数字的对象
    if (specA.a !== specB.a) {
    return specA.a – specB.a;
    }
    if (specA.b !== specB.b) {
    return specA.b – specB.b;
    }
    return specA.c – specB.c;
    }

    // 应用层叠规则
    applyCascade(declarations) {
    const computedStyles = {};
    const seenProperties = new Set();

    // 从高优先级到低优先级遍历
    for (let i = declarations.length – 1; i >= 0; i–) {
    const declaration = declarations[i];
    const property = declaration.property;

    // 如果属性尚未设置,则应用当前声明
    if (!seenProperties.has(property)) {
    computedStyles[property] = declaration.value;
    seenProperties.add(property);
    }
    }

    return computedStyles;
    }

    // 应用继承
    applyInheritance(element, computedStyles) {
    const parent = element.parentElement;
    if (!parent) return;

    const parentStyles = parent.computedStyles || {};

    for (const property of this.inheritedProperties) {
    if (!(property in computedStyles) && property in parentStyles) {
    computedStyles[property] = parentStyles[property];
    }
    }
    }

    // 应用默认值
    applyDefaults(computedStyles) {
    for (const [property, defaultValue] of Object.entries(this.defaultStyles)) {
    if (!(property in computedStyles)) {
    computedStyles[property] = defaultValue;
    }
    }
    }

    // 创建默认样式表
    createDefaultStyles() {
    return {
    'display': 'inline',
    'color': 'black',
    'font-size': 'medium',
    'font-family': 'serif',
    'background-color': 'transparent',
    'border': 'none',
    'margin': '0',
    'padding': '0',
    'width': 'auto',
    'height': 'auto'
    // 更多默认值…
    };
    }

    // 创建用户代理样式表
    createUserAgentStyles() {
    // 简化的用户代理样式
    return [
    {
    selectors: [new Selector('html', { a: 0, b: 0, c: 1 })],
    declarations: [
    new CSSDeclaration('display', 'block'),
    new CSSDeclaration('font-size', '16px')
    ]
    },
    {
    selectors: [new Selector('body', { a: 0, b: 0, c: 1 })],
    declarations: [
    new CSSDeclaration('margin', '8px'),
    new CSSDeclaration('line-height', '1.2')
    ]
    },
    {
    selectors: [new Selector('div', { a: 0, b: 0, c: 1 })],
    declarations: [
    new CSSDeclaration('display', 'block')
    ]
    },
    {
    selectors: [new Selector('span', { a: 0, b: 0, c: 1 })],
    declarations: [
    new CSSDeclaration('display', 'inline')
    ]
    },
    {
    selectors: [new Selector('h1', { a: 0, b: 0, c: 1 })],
    declarations: [
    new CSSDeclaration('display', 'block'),
    new CSSDeclaration('font-size', '2em'),
    new CSSDeclaration('font-weight', 'bold'),
    new CSSDeclaration('margin', '0.67em 0')
    ]
    }
    // 更多用户代理规则…
    ];
    }

    // 获取可继承属性列表
    getInheritedProperties() {
    return [
    'color',
    'font-family',
    'font-size',
    'font-style',
    'font-weight',
    'line-height',
    'text-align',
    'visibility'
    // 更多可继承属性…
    ];
    }

    // 检查元素是否匹配规则
    elementMatchesRule(element, rule) {
    // 简化实现,实际应使用选择器匹配引擎
    for (const selector of rule.selectors) {
    if (selector.selectorText === element.tagName.toLowerCase()) {
    return true;
    }
    }
    return false;
    }
    }

    5.2 值计算与转换

    CSS值计算涉及单位转换、相对值计算等复杂操作:

    javascript

    class CSSValueCalculator {
    constructor() {
    this.unitConverters = {
    // 长度单位转换(px为基准)
    'px': value => value,
    'em': (value, context) => value * context.fontSize,
    'rem': (value, context) => value * context.rootFontSize,
    'pt': value => value * 1.33333, // 1pt = 1.333px
    'pc': value => value * 16, // 1pc = 16px
    'in': value => value * 96, // 1in = 96px
    'cm': value => value * 37.8, // 1cm ≈ 37.8px
    'mm': value => value * 3.78, // 1mm ≈ 3.78px
    '%': (value, context, property) => {
    // 百分比根据属性不同有不同的基准
    switch (property) {
    case 'width':
    return value * context.parentWidth / 100;
    case 'height':
    return value * context.parentHeight / 100;
    case 'font-size':
    return value * context.parentFontSize / 100;
    default:
    return value;
    }
    }
    };

    this.colorParsers = {
    'hex': this.parseHexColor.bind(this),
    'rgb': this.parseRgbColor.bind(this),
    'rgba': this.parseRgbaColor.bind(this),
    'hsl': this.parseHslColor.bind(this),
    'hsla': this.parseHslaColor.bind(this),
    'named': this.parseNamedColor.bind(this)
    };
    }

    // 计算CSS值
    computeValue(value, property, context = {}) {
    if (value === 'inherit') {
    return context.inheritedValue || '';
    }

    if (value === 'initial') {
    return this.getInitialValue(property);
    }

    if (value === 'unset') {
    return this.isInheritedProperty(property) ? 'inherit' : 'initial';
    }

    // 尝试解析为带单位的数值
    const unitMatch = value.match(/^([-+]?[0-9]*\\.?[0-9]+)([a-z%]*)$/);
    if (unitMatch) {
    const [, numStr, unit] = unitMatch;
    const numValue = parseFloat(numStr);

    if (unit in this.unitConverters) {
    const converter = this.unitConverters[unit];
    return converter(numValue, context, property);
    }

    return numValue; // 无单位数值
    }

    // 尝试解析颜色
    const color = this.parseColor(value);
    if (color) {
    return color;
    }

    // 其他值(字符串、关键字等)
    return value;
    }

    // 解析颜色值
    parseColor(colorStr) {
    colorStr = colorStr.trim().toLowerCase();

    // 十六进制颜色
    if (colorStr.startsWith('#')) {
    return this.colorParsers.hex(colorStr);
    }

    // rgb/rgba颜色
    if (colorStr.startsWith('rgb')) {
    const isRgba = colorStr.startsWith('rgba');
    return isRgba ?
    this.colorParsers.rgba(colorStr) :
    this.colorParsers.rgb(colorStr);
    }

    // hsl/hsla颜色
    if (colorStr.startsWith('hsl')) {
    const isHsla = colorStr.startsWith('hsla');
    return isHsla ?
    this.colorParsers.hsla(colorStr) :
    this.colorParsers.hsl(colorStr);
    }

    // 颜色名称
    return this.colorParsers.named(colorStr);
    }

    // 解析十六进制颜色
    parseHexColor(hex) {
    // 移除#号
    hex = hex.substring(1);

    let r, g, b, a = 1;

    if (hex.length === 3) {
    // #RGB格式
    r = parseInt(hex[0] + hex[0], 16);
    g = parseInt(hex[1] + hex[1], 16);
    b = parseInt(hex[2] + hex[2], 16);
    } else if (hex.length === 4) {
    // #RGBA格式
    r = parseInt(hex[0] + hex[0], 16);
    g = parseInt(hex[1] + hex[1], 16);
    b = parseInt(hex[2] + hex[2], 16);
    a = parseInt(hex[3] + hex[3], 16) / 255;
    } else if (hex.length === 6) {
    // #RRGGBB格式
    r = parseInt(hex.substring(0, 2), 16);
    g = parseInt(hex.substring(2, 4), 16);
    b = parseInt(hex.substring(4, 6), 16);
    } else if (hex.length === 8) {
    // #RRGGBBAA格式
    r = parseInt(hex.substring(0, 2), 16);
    g = parseInt(hex.substring(2, 4), 16);
    b = parseInt(hex.substring(4, 6), 16);
    a = parseInt(hex.substring(6, 8), 16) / 255;
    } else {
    return null;
    }

    return `rgba(${r}, ${g}, ${b}, ${a})`;
    }

    // 解析rgb颜色
    parseRgbColor(rgbStr) {
    const match = rgbStr.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);
    if (!match) return null;

    const [, r, g, b] = match;
    return `rgb(${r}, ${g}, ${b})`;
    }

    // 解析命名颜色
    parseNamedColor(colorName) {
    const namedColors = {
    'black': '#000000',
    'white': '#ffffff',
    'red': '#ff0000',
    'green': '#008000',
    'blue': '#0000ff',
    'yellow': '#ffff00',
    'cyan': '#00ffff',
    'magenta': '#ff00ff',
    'silver': '#c0c0c0',
    'gray': '#808080',
    'maroon': '#800000',
    'olive': '#808000',
    'purple': '#800080',
    'teal': '#008080',
    'navy': '#000080',
    // 更多颜色…
    };

    return namedColors[colorName] || null;
    }

    // 获取属性初始值
    getInitialValue(property) {
    const initialValues = {
    'display': 'inline',
    'position': 'static',
    'float': 'none',
    'clear': 'none',
    'width': 'auto',
    'height': 'auto',
    'margin': '0',
    'padding': '0',
    'border': 'none',
    'background': 'none',
    'color': 'black',
    'font-size': 'medium',
    'font-weight': 'normal',
    'text-align': 'start',
    'vertical-align': 'baseline'
    // 更多初始值…
    };

    return initialValues[property] || '';
    }

    // 检查属性是否可继承
    isInheritedProperty(property) {
    const inheritedProperties = [
    'color',
    'font-family',
    'font-size',
    'font-style',
    'font-weight',
    'line-height',
    'text-align',
    'visibility'
    ];

    return inheritedProperties.includes(property);
    }
    }

    第六章:集成与优化

    6.1 完整CSS引擎集成

    将各个模块组合成完整的CSS引擎:

    javascript

    class CSSEngine {
    constructor() {
    this.lexer = null;
    this.parser = null;
    this.ruleIndex = new RuleIndex();
    this.selectorMatcher = new SelectorMatcher();
    this.styleCascade = new StyleCascade();
    this.valueCalculator = new CSSValueCalculator();
    this.stylesheet = null;
    this.computedStyles = new WeakMap(); // 缓存计算后的样式
    }

    // 加载和解析CSS
    loadCSS(cssText) {
    this.lexer = new OptimizedCSSLexer(cssText);
    this.parser = new OptimizedCSSParser(this.lexer);
    this.stylesheet = this.parser.parseStylesheet();

    // 构建规则索引
    for (const rule of this.stylesheet) {
    this.ruleIndex.addRule(rule);
    }

    return this.stylesheet;
    }

    // 计算元素的样式
    computeStyles(element, pseudoState = {}) {
    // 检查缓存
    if (this.computedStyles.has(element)) {
    return this.computedStyles.get(element);
    }

    // 查找匹配的规则
    const matchingRules = this.ruleIndex.findMatchingRules(
    element,
    this.selectorMatcher,
    pseudoState
    );

    // 收集内联样式
    const inlineStyles = this.parseInlineStyles(element);

    // 计算最终样式
    const computedStyles = this.styleCascade.computeElementStyles(
    element,
    matchingRules,
    inlineStyles
    );

    // 计算值(单位转换等)
    const context = this.createComputationContext(element);
    const finalStyles = {};

    for (const [property, value] of Object.entries(computedStyles)) {
    finalStyles[property] = this.valueCalculator.computeValue(
    value,
    property,
    context
    );
    }

    // 缓存结果
    this.computedStyles.set(element, finalStyles);

    return finalStyles;
    }

    // 解析内联样式
    parseInlineStyles(element) {
    const styleAttr = element.getAttribute('style');
    if (!styleAttr) return [];

    const declarations = [];
    const parts = styleAttr.split(';');

    for (const part of parts) {
    const trimmed = part.trim();
    if (!trimmed) continue;

    const colonIndex = trimmed.indexOf(':');
    if (colonIndex === -1) continue;

    const property = trimmed.substring(0, colonIndex).trim();
    let value = trimmed.substring(colonIndex + 1).trim();
    let important = false;

    // 检查!important
    const importantIndex = value.toLowerCase().indexOf('!important');
    if (importantIndex !== -1) {
    value = value.substring(0, importantIndex).trim();
    important = true;
    }

    declarations.push(new CSSDeclaration(property, value, important));
    }

    return declarations;
    }

    // 创建计算上下文
    createComputationContext(element) {
    const parent = element.parentElement;
    const parentStyles = parent ? this.computeStyles(parent) : {};

    return {
    fontSize: this.parseFontSize(parentStyles['font-size'] || '16px'),
    rootFontSize: 16, // 假设根字体大小为16px
    parentWidth: this.parseLength(parentStyles['width'] || 'auto'),
    parentHeight: this.parseLength(parentStyles['height'] || 'auto'),
    parentFontSize: this.parseFontSize(parentStyles['font-size'] || '16px')
    };
    }

    // 解析字体大小
    parseFontSize(fontSizeStr) {
    const match = fontSizeStr.match(/^([-+]?[0-9]*\\.?[0-9]+)([a-z%]*)$/);
    if (!match) return 16;

    const [, numStr, unit] = match;
    const numValue = parseFloat(numStr);

    if (unit === 'px') return numValue;
    if (unit === 'em') return numValue * 16; // 简化处理
    if (unit === 'rem') return numValue * 16;
    if (unit === '%') return numValue * 16 / 100;

    return 16; // 默认值
    }

    // 解析长度值
    parseLength(lengthStr) {
    if (lengthStr === 'auto') return null;

    const match = lengthStr.match(/^([-+]?[0-9]*\\.?[0-9]+)([a-z%]*)$/);
    if (!match) return 0;

    const [, numStr] = match;
    return parseFloat(numStr);
    }

    // 强制重新计算元素样式
    recomputeStyles(element) {
    this.computedStyles.delete(element);
    return this.computeStyles(element);
    }

    // 获取元素的计算样式(类似window.getComputedStyle)
    getComputedStyle(element, pseudoElt = null) {
    const pseudoState = pseudoElt ? this.getPseudoState(pseudoElt) : {};
    return this.computeStyles(element, pseudoState);
    }

    // 获取伪元素状态
    getPseudoState(pseudoElt) {
    // 简化实现
    const state = {};

    if (pseudoElt === ':hover') {
    state.isHovered = () => true;
    } else if (pseudoElt === ':focus') {
    state.isFocused = () => true;
    }

    return state;
    }
    }

    6.2 性能优化策略

    CSS引擎的性能至关重要,特别是在处理大型DOM和复杂样式表时:

    javascript

    class OptimizedCSSEngine extends CSSEngine {
    constructor() {
    super();
    this.styleCache = new LRUCache(1000); // LRU缓存
    this.dependencyGraph = new Map(); // 样式依赖图
    this.invalidationTracker = new InvalidationTracker();
    }

    // 带缓存的样式计算
    computeStyles(element, pseudoState = {}) {
    // 生成缓存键
    const cacheKey = this.generateCacheKey(element, pseudoState);

    // 检查缓存
    if (this.styleCache.has(cacheKey)) {
    return this.styleCache.get(cacheKey);
    }

    // 计算样式
    const styles = super.computeStyles(element, pseudoState);

    // 更新缓存
    this.styleCache.set(cacheKey, styles);

    // 跟踪依赖
    this.trackDependencies(element, styles);

    return styles;
    }

    // 生成缓存键
    generateCacheKey(element, pseudoState) {
    const parts = [
    element.tagName,
    element.id,
    Array.from(element.classList).join('.'),
    JSON.stringify(Array.from(element.attributes).map(attr =>
    `${attr.name}=${attr.value}`
    ).sort())
    ];

    // 添加伪状态
    if (pseudoState) {
    parts.push(JSON.stringify(pseudoState));
    }

    // 添加上下文信息
    const parent = element.parentElement;
    if (parent) {
    const parentKey = this.generateCacheKey(parent, {});
    parts.push(`parent:${parentKey}`);
    }

    return parts.join('|');
    }

    // 跟踪样式依赖
    trackDependencies(element, styles) {
    const dependencies = new Set();

    // 跟踪继承依赖
    for (const property of this.styleCascade.inheritedProperties) {
    if (property in styles) {
    const parent = element.parentElement;
    if (parent) {
    dependencies.add(`parent:${property}`);
    }
    }
    }

    // 跟踪相对单位依赖
    for (const [property, value] of Object.entries(styles)) {
    if (typeof value === 'string') {
    if (value.includes('em') || value.includes('rem') || value.includes('%')) {
    dependencies.add(`relative:${property}`);
    }
    }
    }

    this.dependencyGraph.set(element, dependencies);
    }

    // 处理样式失效
    invalidateStyles(element, changedProperty = null) {
    // 标记元素样式失效
    this.computedStyles.delete(element);
    this.styleCache.delete(this.generateCacheKey(element, {}));

    // 传播失效到依赖项
    this.propagateInvalidation(element, changedProperty);
    }

    // 传播失效
    propagateInvalidation(element, changedProperty) {
    // 查找依赖此元素样式的子元素
    for (const [depElement, dependencies] of this.dependencyGraph.entries()) {
    if (depElement === element) continue;

    let shouldInvalidate = false;

    // 检查继承依赖
    if (changedProperty &&
    this.styleCascade.inheritedProperties.includes(changedProperty)) {
    if (dependencies.has(`parent:${changedProperty}`)) {
    shouldInvalidate = true;
    }
    }

    // 检查相对单位依赖
    if (changedProperty && (changedProperty === 'font-size' ||
    changedProperty === 'width' || changedProperty === 'height')) {
    if (dependencies.has(`relative:${changedProperty}`)) {
    shouldInvalidate = true;
    }
    }

    if (shouldInvalidate) {
    this.invalidateStyles(depElement);
    }
    }
    }

    // 批量样式计算
    computeStylesBatch(elements) {
    // 按DOM顺序排序以减少重排
    const sortedElements = this.sortByDOMOrder(elements);
    const results = new Map();

    for (const element of sortedElements) {
    results.set(element, this.computeStyles(element));
    }

    return results;
    }

    // 按DOM顺序排序
    sortByDOMOrder(elements) {
    return Array.from(elements).sort((a, b) => {
    if (a.contains(b)) return 1;
    if (b.contains(a)) return -1;
    return 0;
    });
    }
    }

    // LRU缓存实现
    class LRUCache {
    constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
    }

    get(key) {
    if (!this.cache.has(key)) return undefined;

    const value = this.cache.get(key);
    // 刷新键的使用顺序
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
    }

    set(key, value) {
    if (this.cache.has(key)) {
    this.cache.delete(key);
    } else if (this.cache.size >= this.capacity) {
    // 删除最久未使用的
    const firstKey = this.cache.keys().next().value;
    this.cache.delete(firstKey);
    }

    this.cache.set(key, value);
    }

    has(key) {
    return this.cache.has(key);
    }

    delete(key) {
    return this.cache.delete(key);
    }
    }

    第七章:测试与验证

    7.1 测试框架

    为确保CSS解析器的正确性,需要建立全面的测试套件:

    javascript

    class CSSParserTestSuite {
    constructor() {
    this.tests = [];
    this.results = [];
    }

    // 添加测试用例
    addTest(name, cssInput, expectedOutput, testFunction) {
    this.tests.push({
    name,
    cssInput,
    expectedOutput,
    testFunction: testFunction || this.defaultTestFunction
    });
    }

    // 默认测试函数
    defaultTestFunction(cssInput, expectedOutput) {
    const lexer = new CSSLexer(cssInput);
    const parser = new CSSParser(lexer);
    const result = parser.parseStylesheet();

    // 简化比较,实际应更详细
    return JSON.stringify(result) === JSON.stringify(expectedOutput);
    }

    // 运行所有测试
    runAllTests() {
    console.log('开始运行CSS解析器测试…');

    for (const test of this.tests) {
    try {
    const startTime = performance.now();
    const passed = test.testFunction(test.cssInput, test.expectedOutput);
    const endTime = performance.now();

    this.results.push({
    name: test.name,
    passed,
    duration: endTime – startTime
    });

    console.log(`${test.name}: ${passed ? '✓' : '✗'} (${(endTime – startTime).toFixed(2)}ms)`);
    } catch (error) {
    console.log(`${test.name}: ✗ (错误: ${error.message})`);
    this.results.push({
    name: test.name,
    passed: false,
    error: error.message
    });
    }
    }

    this.printSummary();
    }

    // 打印测试摘要
    printSummary() {
    const total = this.results.length;
    const passed = this.results.filter(r => r.passed).length;
    const failed = total – passed;

    console.log('\\n测试摘要:');
    console.log(`总计: ${total}, 通过: ${passed}, 失败: ${failed}`);

    if (failed > 0) {
    console.log('\\n失败测试:');
    for (const result of this.results.filter(r => !r.passed)) {
    console.log(` – ${result.name}: ${result.error || '未知错误'}`);
    }
    }
    }

    // 创建标准测试套件
    static createStandardTestSuite() {
    const suite = new CSSParserTestSuite();

    // 基础选择器测试
    suite.addTest(
    '简单元素选择器',
    'div { color: red; }',
    [{
    selectors: [{ selectorText: 'div', specificity: { a: 0, b: 0, c: 1 } }],
    declarations: [{ property: 'color', value: 'red', important: false }]
    }]
    );

    // 类选择器测试
    suite.addTest(
    '类选择器',
    '.container { width: 100%; }',
    [{
    selectors: [{ selectorText: '.container', specificity: { a: 0, b: 1, c: 0 } }],
    declarations: [{ property: 'width', value: '100%', important: false }]
    }]
    );

    // ID选择器测试
    suite.addTest(
    'ID选择器',
    '#main { margin: 0 auto; }',
    [{
    selectors: [{ selectorText: '#main', specificity: { a: 1, b: 0, c: 0 } }],
    declarations: [{ property: 'margin', value: '0 auto', important: false }]
    }]
    );

    // 多个声明测试
    suite.addTest(
    '多个声明',
    'p { color: blue; font-size: 14px; line-height: 1.5; }',
    [{
    selectors: [{ selectorText: 'p', specificity: { a: 0, b: 0, c: 1 } }],
    declarations: [
    { property: 'color', value: 'blue', important: false },
    { property: 'font-size', value: '14px', important: false },
    { property: 'line-height', value: '1.5', important: false }
    ]
    }]
    );

    // 多个选择器测试
    suite.addTest(
    '多个选择器',
    'h1, h2, h3 { font-weight: bold; }',
    [{
    selectors: [
    { selectorText: 'h1', specificity: { a: 0, b: 0, c: 1 } },
    { selectorText: 'h2', specificity: { a: 0, b: 0, c: 1 } },
    { selectorText: 'h3', specificity: { a: 0, b: 0, c: 1 } }
    ],
    declarations: [{ property: 'font-weight', value: 'bold', important: false }]
    }]
    );

    // !important测试
    suite.addTest(
    '重要声明',
    '.warning { color: red !important; }',
    [{
    selectors: [{ selectorText: '.warning', specificity: { a: 0, b: 1, c: 0 } }],
    declarations: [{ property: 'color', value: 'red', important: true }]
    }]
    );

    // 属性选择器测试
    suite.addTest(
    '属性选择器',
    '[data-test] { border: 1px solid #ccc; }',
    [{
    selectors: [{ selectorText: '[data-test]', specificity: { a: 0, b: 1, c: 0 } }],
    declarations: [{ property: 'border', value: '1px solid #ccc', important: false }]
    }]
    );

    // 伪类测试
    suite.addTest(
    '伪类选择器',
    'a:hover { text-decoration: underline; }',
    [{
    selectors: [{ selectorText: 'a:hover', specificity: { a: 0, b: 1, c: 1 } }],
    declarations: [{ property: 'text-decoration', value: 'underline', important: false }]
    }]
    );

    // 复杂选择器测试
    suite.addTest(
    '复杂选择器',
    'div.container > p:first-child { margin-top: 0; }',
    [{
    selectors: [{ selectorText: 'div.container > p:first-child', specificity: { a: 0, b: 2, c: 2 } }],
    declarations: [{ property: 'margin-top', value: '0', important: false }]
    }]
    );

    // 媒体查询测试(简化)
    suite.addTest(
    '媒体查询',
    '@media (max-width: 600px) { .sidebar { display: none; } }',
    []
    );

    return suite;
    }
    }

    // 性能测试工具
    class CSSPerformanceBenchmark {
    constructor() {
    this.testCases = [];
    }

    // 添加性能测试
    addTestCase(name, setupFunction, testFunction) {
    this.testCases.push({ name, setupFunction, testFunction });
    }

    // 运行性能测试
    runBenchmark(iterations = 100) {
    console.log('开始性能基准测试…\\n');

    const results = [];

    for (const testCase of this.testCases) {
    console.log(`测试: ${testCase.name}`);

    // 准备测试
    const testData = testCase.setupFunction();

    // 预热
    for (let i = 0; i < 10; i++) {
    testCase.testFunction(testData);
    }

    // 正式测试
    const startTime = performance.now();
    for (let i = 0; i < iterations; i++) {
    testCase.testFunction(testData);
    }
    const endTime = performance.now();

    const avgTime = (endTime – startTime) / iterations;
    results.push({ name: testCase.name, avgTime });

    console.log(` 平均时间: ${avgTime.toFixed(3)}ms\\n`);
    }

    // 排序结果
    results.sort((a, b) => a.avgTime – b.avgTime);

    console.log('性能排名:');
    results.forEach((result, index) => {
    console.log(`${index + 1}. ${result.name}: ${result.avgTime.toFixed(3)}ms`);
    });

    return results;
    }

    // 创建标准性能测试套件
    static createStandardBenchmark() {
    const benchmark = new CSSPerformanceBenchmark();

    // 大型样式表解析测试
    benchmark.addTestCase(
    '大型样式表解析',
    () => {
    // 生成大型CSS
    let css = '';
    for (let i = 0; i < 1000; i++) {
    css += `.class-${i} { color: #${Math.floor(Math.random()*16777215).toString(16)}; }\\n`;
    }
    return css;
    },
    (css) => {
    const lexer = new CSSLexer(css);
    const parser = new CSSParser(lexer);
    parser.parseStylesheet();
    }
    );

    // 复杂选择器匹配测试
    benchmark.addTestCase(
    '复杂选择器匹配',
    () => {
    // 创建测试元素和规则
    const engine = new CSSEngine();
    const css = `
    div.container > ul.list li.item:nth-child(odd) a[href^="https"]:hover {
    color: red;
    font-weight: bold;
    }
    #main .sidebar ~ section.content article:first-of-type h2 {
    margin-top: 0;
    }
    `;
    engine.loadCSS(css);

    // 创建测试元素
    const div = { tagName: 'DIV', classList: ['container'], id: '' };
    const ul = { tagName: 'UL', classList: ['list'], parentElement: div };
    const li = { tagName: 'LI', classList: ['item'], parentElement: ul };
    const a = {
    tagName: 'A',
    parentElement: li,
    getAttribute: (attr) => attr === 'href' ? 'https://example.com' : null
    };

    return { engine, element: a };
    },
    ({ engine, element }) => {
    engine.computeStyles(element, { isHovered: () => true });
    }
    );

    // 样式计算性能测试
    benchmark.addTestCase(
    '批量样式计算',
    () => {
    const engine = new CSSEngine();
    const css = `
    * { box-sizing: border-box; }
    div { display: block; }
    .box { width: 100px; height: 100px; margin: 10px; }
    .red { background-color: red; }
    .blue { background-color: blue; }
    .large { font-size: 20px; }
    .small { font-size: 12px; }
    `;
    engine.loadCSS(css);

    // 创建多个测试元素
    const elements = [];
    for (let i = 0; i < 100; i++) {
    const element = {
    tagName: 'DIV',
    classList: ['box', i % 2 ? 'red' : 'blue', i % 3 ? 'large' : 'small'],
    parentElement: i > 0 ? elements[i-1] : null,
    getAttribute: () => null
    };
    elements.push(element);
    }

    return { engine, elements };
    },
    ({ engine, elements }) => {
    for (const element of elements) {
    engine.computeStyles(element);
    }
    }
    );

    return benchmark;
    }
    }

    7.2 浏览器兼容性测试

    为确保解析器行为与主流浏览器一致,需要进行兼容性测试:

    javascript

    class BrowserCompatibilityTester {
    constructor() {
    this.features = [
    'css-variables',
    'css-grid',
    'flexbox',
    'css-transitions',
    'css-animations',
    'css-calc',
    'media-queries',
    'pseudo-elements',
    'pseudo-classes',
    'attribute-selectors'
    ];
    }

    // 测试特定CSS功能
    testFeature(featureName, testCSS) {
    const testResults = {
    feature: featureName,
    supported: false,
    details: {}
    };

    try {
    const lexer = new CSSLexer(testCSS);
    const parser = new CSSParser(lexer);
    const rules = parser.parseStylesheet();

    testResults.supported = rules.length > 0;
    testResults.details.rulesParsed = rules.length;
    testResults.details.errors = parser.errors;

    if (testResults.supported) {
    console.log(`✓ ${featureName}: 支持`);
    } else {
    console.log(`✗ ${featureName}: 不支持或解析失败`);
    }
    } catch (error) {
    testResults.supported = false;
    testResults.details.error = error.message;
    console.log(`✗ ${featureName}: 错误 – ${error.message}`);
    }

    return testResults;
    }

    // 运行所有兼容性测试
    runAllCompatibilityTests() {
    console.log('开始浏览器兼容性测试…\\n');

    const results = {};

    // CSS变量测试
    results.cssVariables = this.testFeature('css-variables', `
    :root {
    –main-color: #06c;
    –accent-color: #006;
    }
    .component {
    color: var(–main-color);
    background-color: var(–accent-color);
    }
    `);

    // CSS Grid测试
    results.cssGrid = this.testFeature('css-grid', `
    .container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-gap: 10px;
    }
    `);

    // Flexbox测试
    results.flexbox = this.testFeature('flexbox', `
    .container {
    display: flex;
    justify-content: center;
    align-items: center;
    }
    `);

    // 过渡效果测试
    results.cssTransitions = this.testFeature('css-transitions', `
    .button {
    transition: all 0.3s ease-in-out;
    }
    .button:hover {
    transform: scale(1.1);
    }
    `);

    // calc()函数测试
    results.cssCalc = this.testFeature('css-calc', `
    .element {
    width: calc(100% – 20px);
    height: calc(50vh + 10px);
    }
    `);

    // 媒体查询测试
    results.mediaQueries = this.testFeature('media-queries', `
    @media (min-width: 768px) {
    .container {
    max-width: 750px;
    }
    }
    @media (min-width: 992px) {
    .container {
    max-width: 970px;
    }
    }
    `);

    // 伪元素测试
    results.pseudoElements = this.testFeature('pseudo-elements', `
    p::first-line {
    font-weight: bold;
    }
    p::before {
    content: "→ ";
    }
    `);

    // 复杂伪类测试
    results.pseudoClasses = this.testFeature('pseudo-classes', `
    li:nth-child(3n+1) {
    color: red;
    }
    input:not(:checked) + label {
    opacity: 0.5;
    }
    `);

    // 属性选择器测试
    results.attributeSelectors = this.testFeature('attribute-selectors', `
    input[type="text"] {
    border: 1px solid #ccc;
    }
    a[href^="https"] {
    color: green;
    }
    img[src$=".jpg"] {
    border: 2px solid #999;
    }
    `);

    return results;
    }
    }

    第八章:实际应用与扩展

    8.1 构建CSS-in-JS解决方案

    基于我们的CSS引擎,可以构建一个简单的CSS-in-JS库:

    javascript

    class StyledComponents {
    constructor() {
    this.engine = new OptimizedCSSEngine();
    this.styleSheet = '';
    this.componentStyles = new Map();
    this.styleElement = null;
    }

    // 创建样式组件
    createStyledComponent(tagName, styles) {
    const componentId = `sc-${Math.random().toString(36).substr(2, 9)}`;
    const cssRules = this.generateCSS(componentId, styles);

    // 添加到样式表
    this.styleSheet += cssRules;
    this.updateStyleElement();

    // 返回组件工厂函数
    return (props = {}, …children) => {
    const element = {
    tagName: tagName.toUpperCase(),
    classList: [componentId],
    attributes: [],
    parentElement: null,
    children: children || [],
    getAttribute: (name) => {
    const attr = this.attributes.find(a => a.name === name);
    return attr ? attr.value : null;
    }
    };

    // 处理props
    if (props.className) {
    element.classList.push(props.className);
    }

    // 动态样式
    if (props.style) {
    element.attributes.push({ name: 'style', value: this.objectToCSS(props.style) });
    }

    return element;
    };
    }

    // 生成CSS规则
    generateCSS(componentId, styles) {
    const selector = `.${componentId}`;
    let css = `${selector} {\\n`;

    for (const [property, value] of Object.entries(styles)) {
    const cssProperty = this.camelToKebab(property);
    css += ` ${cssProperty}: ${value};\\n`;
    }

    css += '}\\n';
    return css;
    }

    // 驼峰命名转短横线命名
    camelToKebab(str) {
    return str.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
    }

    // 对象转CSS字符串
    objectToCSS(styleObj) {
    return Object.entries(styleObj)
    .map(([key, value]) => `${this.camelToKebab(key)}: ${value}`)
    .join('; ');
    }

    // 更新样式元素
    updateStyleElement() {
    if (!this.styleElement) {
    this.styleElement = document.createElement('style');
    document.head.appendChild(this.styleElement);
    }

    this.styleElement.textContent = this.styleSheet;
    this.engine.loadCSS(this.styleSheet);
    }

    // 创建关键帧动画
    keyframes(keyframesObj) {
    const animationName = `animation-${Math.random().toString(36).substr(2, 9)}`;
    let css = `@keyframes ${animationName} {\\n`;

    for (const [keyframe, styles] of Object.entries(keyframesObj)) {
    css += ` ${keyframe} {\\n`;

    for (const [property, value] of Object.entries(styles)) {
    const cssProperty = this.camelToKebab(property);
    css += ` ${cssProperty}: ${value};\\n`;
    }

    css += ' }\\n';
    }

    css += '}\\n';
    this.styleSheet += css;
    this.updateStyleElement();

    return animationName;
    }

    // 创建全局样式
    createGlobalStyle(styles) {
    const css = `* {\\n${this.objectToCSS(styles).replace(/;/g, ';\\n')}\\n}\\n`;
    this.styleSheet += css;
    this.updateStyleElement();
    }
    }

    // 使用示例
    const styled = new StyledComponents();

    // 创建样式组件
    const Button = styled.createStyledComponent('button', {
    backgroundColor: '#007bff',
    color: 'white',
    padding: '10px 20px',
    border: 'none',
    borderRadius: '4px',
    fontSize: '16px',
    cursor: 'pointer',
    transition: 'background-color 0.3s ease',

    '&:hover': {
    backgroundColor: '#0056b3'
    },

    '&:active': {
    backgroundColor: '#004085'
    }
    });

    // 创建动画
    const spinAnimation = styled.keyframes({
    '0%': { transform: 'rotate(0deg)' },
    '100%': { transform: 'rotate(360deg)' }
    });

    // 创建带动画的组件
    const Spinner = styled.createStyledComponent('div', {
    width: '40px',
    height: '40px',
    border: '4px solid #f3f3f3',
    borderTop: '4px solid #3498db',
    borderRadius: '50%',
    animation: `${spinAnimation} 1s linear infinite`
    });

    // 设置全局样式
    styled.createGlobalStyle({
    margin: 0,
    padding: 0,
    boxSizing: 'border-box',
    fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
    });

    8.2 可视化CSS编辑器

    利用我们的CSS引擎,可以构建一个可视化CSS编辑器:

    javascript

    class VisualCSSEditor {
    constructor(containerId) {
    this.container = document.getElementById(containerId);
    this.engine = new OptimizedCSSEngine();
    this.selectedElement = null;
    this.stylesheet = '';
    this.initUI();
    }

    // 初始化用户界面
    initUI() {
    // 创建编辑器布局
    this.container.innerHTML = `
    <div class="css-editor">
    <div class="editor-top">
    <div class="element-selector">
    <h3>选择元素</h3>
    <div class="element-tree" id="elementTree"></div>
    </div>
    <div class="css-editor-panel">
    <h3>CSS编辑器</h3>
    <textarea id="cssEditor" rows="20" cols="50"></textarea>
    <div class="editor-buttons">
    <button id="applyCSS">应用CSS</button>
    <button id="resetCSS">重置</button>
    </div>
    </div>
    </div>
    <div class="editor-bottom">
    <div class="style-inspector">
    <h3>样式检查器</h3>
    <div id="styleProperties"></div>
    </div>
    <div class="preview-area">
    <h3>预览</h3>
    <div id="previewContainer" contenteditable="true">
    <h1>可视化CSS编辑器</h1>
    <p>编辑此区域的内容和样式</p>
    <button class="demo-button">示例按钮</button>
    <div class="demo-box">
    <p>这是一个示例框</p>
    </div>
    </div>
    </div>
    </div>
    </div>
    `;

    // 绑定事件
    this.bindEvents();

    // 初始化元素树
    this.buildElementTree();

    // 初始化默认CSS
    this.loadDefaultCSS();
    }

    // 绑定事件
    bindEvents() {
    // CSS编辑器应用按钮
    document.getElementById('applyCSS').addEventListener('click', () => {
    this.applyCSS();
    });

    // 重置按钮
    document.getElementById('resetCSS').addEventListener('click', () => {
    this.resetCSS();
    });

    // 预览区域点击事件(用于选择元素)
    document.getElementById('previewContainer').addEventListener('click', (e) => {
    this.selectElement(e.target);
    });

    // 实时CSS编辑(可选)
    document.getElementById('cssEditor').addEventListener('input', () => {
    // 可以添加防抖处理
    // this.applyCSS();
    });
    }

    // 构建元素树
    buildElementTree() {
    const previewContainer = document.getElementById('previewContainer');
    const elementTree = document.getElementById('elementTree');

    const buildTree = (element, parentNode) => {
    const node = document.createElement('div');
    node.className = 'tree-node';
    node.textContent = element.tagName.toLowerCase();
    node.dataset.elementId = this.getElementId(element);

    node.addEventListener('click', (e) => {
    e.stopPropagation();
    this.selectElement(element);
    });

    parentNode.appendChild(node);

    // 递归处理子元素
    if (element.children.length > 0) {
    const childrenContainer = document.createElement('div');
    childrenContainer.className = 'tree-children';
    node.appendChild(childrenContainer);

    for (const child of element.children) {
    buildTree(child, childrenContainer);
    }
    }
    };

    elementTree.innerHTML = '';
    buildTree(previewContainer, elementTree);
    }

    // 选择元素
    selectElement(element) {
    // 清除之前的选择
    if (this.selectedElement) {
    this.selectedElement.classList.remove('selected');
    }

    // 设置新选择
    this.selectedElement = element;
    element.classList.add('selected');

    // 更新元素树选择
    this.updateElementTreeSelection();

    // 显示元素样式
    this.inspectElementStyles();

    // 更新CSS编辑器
    this.updateCSSEditor();
    }

    // 更新元素树选择
    updateElementTreeSelection() {
    const elementId = this.getElementId(this.selectedElement);
    const treeNodes = document.querySelectorAll('.tree-node');

    treeNodes.forEach(node => {
    node.classList.remove('selected');
    if (node.dataset.elementId === elementId) {
    node.classList.add('selected');
    // 确保节点可见
    node.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
    }
    });
    }

    // 检查元素样式
    inspectElementStyles() {
    if (!this.selectedElement) return;

    const computedStyles = this.engine.getComputedStyle(this.selectedElement);
    const propertiesContainer = document.getElementById('styleProperties');

    propertiesContainer.innerHTML = '<table class="style-table"><thead><tr><th>属性</th><th>值</th><th>来源</th></tr></thead><tbody></tbody></table>';

    const tbody = propertiesContainer.querySelector('tbody');

    // 按属性名排序
    const sortedProperties = Object.keys(computedStyles).sort();

    for (const property of sortedProperties) {
    const value = computedStyles[property];
    const row = document.createElement('tr');

    row.innerHTML = `
    <td><code>${property}</code></td>
    <td><code>${value}</code></td>
    <td>计算值</td>
    `;

    tbody.appendChild(row);
    }
    }

    // 更新CSS编辑器
    updateCSSEditor() {
    if (!this.selectedElement) return;

    const editor = document.getElementById('cssEditor');
    const selector = this.generateSelector(this.selectedElement);

    // 查找现有的样式规则
    const existingRule = this.findRuleForElement(this.selectedElement);

    if (existingRule) {
    editor.value = existingRule;
    } else {
    editor.value = `${selector} {\\n \\n}`;
    // 将光标定位在大括号内
    editor.focus();
    editor.setSelectionRange(selector.length + 3, selector.length + 3);
    }
    }

    // 生成选择器
    generateSelector(element) {
    let selector = element.tagName.toLowerCase();

    if (element.id) {
    selector = `#${element.id}`;
    } else if (element.classList.length > 0) {
    // 使用第一个类
    selector = `.${element.classList[0]}`;
    }

    return selector;
    }

    // 查找元素的现有规则
    findRuleForElement(element) {
    // 简化实现
    const selector = this.generateSelector(element);

    // 在样式表中查找
    const lines = this.stylesheet.split('\\n');
    let inRule = false;
    let ruleStart = -1;
    let ruleSelector = '';

    for (let i = 0; i < lines.length; i++) {
    const line = lines[i].trim();

    if (line.endsWith('{') && !line.includes('@')) {
    inRule = true;
    ruleStart = i;
    ruleSelector = line.substring(0, line.length – 1).trim();
    } else if (line === '}' && inRule) {
    inRule = false;

    // 检查选择器是否匹配
    if (this.selectorMatchesElement(ruleSelector, element)) {
    // 提取整个规则
    const ruleLines = lines.slice(ruleStart, i + 1);
    return ruleLines.join('\\n');
    }
    }
    }

    return null;
    }

    // 检查选择器是否匹配元素
    selectorMatchesElement(selector, element) {
    // 简化实现
    try {
    return element.matches(selector);
    } catch (e) {
    return false;
    }
    }

    // 应用CSS
    applyCSS() {
    const editor = document.getElementById('cssEditor');
    const css = editor.value;

    // 添加到样式表
    this.stylesheet += '\\n' + css;

    // 更新引擎
    this.engine.loadCSS(this.stylesheet);

    // 重新计算样式
    this.inspectElementStyles();

    // 更新预览
    this.updatePreview();
    }

    // 重置CSS
    resetCSS() {
    this.stylesheet = '';
    this.engine = new OptimizedCSSEngine();
    this.loadDefaultCSS();
    this.inspectElementStyles();
    this.updatePreview();

    // 清空编辑器
    document.getElementById('cssEditor').value = '';
    }

    // 更新预览
    updatePreview() {
    // 重新计算所有元素的样式
    const previewContainer = document.getElementById('previewContainer');
    this.updateElementStyles(previewContainer);
    }

    // 递归更新元素样式
    updateElementStyles(element) {
    // 计算样式
    const styles = this.engine.getComputedStyle(element);

    // 应用内联样式
    let styleString = '';
    for (const [property, value] of Object.entries(styles)) {
    const cssProperty = property.replace(/[A-Z]/g, m => `-${m.toLowerCase()}`);
    styleString += `${cssProperty}: ${value}; `;
    }

    element.style.cssText = styleString;

    // 递归处理子元素
    for (const child of element.children) {
    this.updateElementStyles(child);
    }
    }

    // 加载默认CSS
    loadDefaultCSS() {
    const defaultCSS = `
    #previewContainer {
    font-family: Arial, sans-serif;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 5px;
    background-color: #f9f9f9;
    }

    #previewContainer h1 {
    color: #333;
    border-bottom: 2px solid #007bff;
    padding-bottom: 10px;
    }

    #previewContainer p {
    line-height: 1.6;
    color: #666;
    }

    .demo-button {
    background-color: #28a745;
    color: white;
    padding: 10px 20px;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    font-size: 16px;
    }

    .demo-button:hover {
    background-color: #218838;
    }

    .demo-box {
    border: 1px solid #ddd;
    padding: 15px;
    margin-top: 20px;
    border-radius: 4px;
    background-color: white;
    }

    .selected {
    outline: 2px dashed #007bff;
    outline-offset: 2px;
    }
    `;

    this.stylesheet = defaultCSS;
    this.engine.loadCSS(defaultCSS);
    }

    // 获取元素唯一ID
    getElementId(element) {
    if (!element._cssEditorId) {
    element._cssEditorId = `el-${Math.random().toString(36).substr(2, 9)}`;
    }
    return element._cssEditorId;
    }
    }

    第九章:未来发展与优化方向

    9.1 支持CSS新特性

    随着CSS标准不断发展,解析器需要持续更新以支持新特性:

    javascript

    class ModernCSSParser extends CSSParser {
    constructor(lexer) {
    super(lexer);
    this.supportedFeatures = {
    'css-grid': true,
    'css-variables': true,
    'css-contain': true,
    'css-subgrid': false, // 尚未支持
    'css-container-queries': false // 尚未支持
    };
    }

    // 解析CSS自定义属性
    parseCustomProperty(declaration) {
    if (declaration.property.startsWith('–')) {
    return {
    type: 'custom-property',
    name: declaration.property,
    value: declaration.value
    };
    }
    return null;
    }

    // 解析CSS Grid属性
    parseGridValue(value) {
    // 简化的Grid解析
    const gridValues = {
    'grid-template-columns': this.parseGridTemplate(value),
    'grid-template-rows': this.parseGridTemplate(value),
    'grid-area': this.parseGridArea(value)
    };
    return gridValues;
    }

    parseGridTemplate(value) {
    // 解析如 "1fr 1fr minmax(100px, 1fr)" 的值
    const parts = value.split(' ');
    return parts.map(part => {
    if (part.startsWith('minmax(')) {
    return this.parseMinMax(part);
    } else if (part.startsWith('repeat(')) {
    return this.parseRepeat(part);
    }
    return part;
    });
    }

    parseMinMax(minmaxStr) {
    const match = minmaxStr.match(/minmax\\(([^,]+),\\s*([^)]+)\\)/);
    if (match) {
    return {
    type: 'minmax',
    min: match[1].trim(),
    max: match[2].trim()
    };
    }
    return minmaxStr;
    }

    // 解析容器查询
    parseContainerQuery(atRule) {
    if (atRule.name === 'container') {
    return {
    type: 'container-query',
    condition: atRule.condition,
    rules: atRule.rules
    };
    }
    return null;
    }
    }

    9.2 性能优化策略

    进一步优化解析器性能:

    javascript

    class HighPerformanceCSSEngine extends OptimizedCSSEngine {
    constructor() {
    super();
    this.workerPool = new WorkerPool(4); // 4个工作线程
    this.incrementalParser = new IncrementalParser();
    this.selectiveRecalc = new SelectiveRecalcEngine();
    }

    // 并行解析CSS
    async parseCSSInParallel(cssText) {
    // 将CSS分割为多个块
    const chunks = this.splitCSSIntoChunks(cssText);

    // 并行解析每个块
    const promises = chunks.map(chunk =>
    this.workerPool.enqueue(() => this.parseChunk(chunk))
    );

    const results = await Promise.all(promises);

    // 合并结果
    return this.mergeParseResults(results);
    }

    // 增量解析
    parseCSSIncrementally(cssText, callback) {
    return this.incrementalParser.parse(cssText, (progress, rules) => {
    // 逐步添加规则到索引
    for (const rule of rules) {
    this.ruleIndex.addRule(rule);
    }
    callback(progress, rules);
    });
    }

    // 选择性重新计算
    recomputeStylesSelectively(element, changedProperties) {
    return this.selectiveRecalc.recompute(
    element,
    changedProperties,
    this.computeStyles.bind(this)
    );
    }
    }

    // 工作线程池
    class WorkerPool {
    constructor(size) {
    this.size = size;
    this.queue = [];
    this.workers = Array.from({ length: size }, () => ({
    busy: false,
    worker: this.createWorker()
    }));
    }

    createWorker() {
    // 创建Web Worker或使用模拟
    return {
    execute: (task) => new Promise(resolve => {
    // 模拟异步执行
    setTimeout(() => resolve(task()), Math.random() * 10);
    })
    };
    }

    enqueue(task) {
    return new Promise((resolve) => {
    this.queue.push({ task, resolve });
    this.processQueue();
    });
    }

    processQueue() {
    const availableWorker = this.workers.find(w => !w.busy);
    if (!availableWorker || this.queue.length === 0) return;

    const { task, resolve } = this.queue.shift();
    availableWorker.busy = true;

    availableWorker.worker.execute(task).then(result => {
    availableWorker.busy = false;
    resolve(result);
    this.processQueue();
    });
    }
    }

    // 增量解析器
    class IncrementalParser {
    constructor() {
    this.buffer = '';
    this.partialRules = [];
    }

    parse(cssText, callback) {
    this.buffer += cssText;
    let progress = 0;

    // 按规则边界分割
    const rules = [];
    let ruleStart = 0;
    let braceDepth = 0;
    let inComment = false;

    for (let i = 0; i < this.buffer.length; i++) {
    // 跳过注释
    if (this.buffer.substr(i, 2) === '/*') {
    inComment = true;
    i++;
    continue;
    }

    if (inComment && this.buffer.substr(i, 2) === '*/') {
    inComment = false;
    i++;
    continue;
    }

    if (inComment) continue;

    // 跟踪大括号深度
    if (this.buffer[i] === '{') {
    braceDepth++;
    } else if (this.buffer[i] === '}') {
    braceDepth–;

    // 找到完整规则
    if (braceDepth === 0) {
    const ruleText = this.buffer.substring(ruleStart, i + 1);
    rules.push(ruleText);
    ruleStart = i + 1;

    // 更新进度
    progress = (i + 1) / this.buffer.length;
    callback(progress, this.parseRules([ruleText]));
    }
    }
    }

    // 保留未完成的规则
    this.buffer = this.buffer.substring(ruleStart);

    return rules;
    }

    parseRules(ruleTexts) {
    // 使用主解析器解析规则
    return ruleTexts.map(text => {
    const lexer = new CSSLexer(text);
    const parser = new CSSParser(lexer);
    return parser.parseRule();
    }).filter(rule => rule !== null);
    }
    }

    // 选择性重新计算引擎
    class SelectiveRecalcEngine {
    constructor() {
    this.dependencyMap = new Map();
    }

    recompute(element, changedProperties, computeFunction) {
    // 检查哪些属性需要重新计算
    const propertiesToRecalc = this.getDependentProperties(
    element,
    changedProperties
    );

    if (propertiesToRecalc.length === 0) {
    // 没有依赖,无需重新计算
    return null;
    }

    // 重新计算
    return computeFunction(element);
    }

    getDependentProperties(element, changedProperties) {
    const dependencies = new Set();

    // 获取元素的样式依赖
    const elementDeps = this.dependencyMap.get(element) || new Set();

    for (const changedProp of changedProperties) {
    // 查找依赖此属性的属性
    for (const dep of elementDeps) {
    if (dep.dependsOn === changedProp) {
    dependencies.add(dep.property);
    }
    }
    }

    return Array.from(dependencies);
    }

    trackDependencies(element, property, value) {
    if (!this.dependencyMap.has(element)) {
    this.dependencyMap.set(element, new Set());
    }

    const deps = this.dependencyMap.get(element);

    // 分析值中的依赖
    if (typeof value === 'string') {
    // 检查相对单位
    if (value.includes('em') || value.includes('rem')) {
    deps.add({
    property,
    dependsOn: 'font-size',
    type: 'relative-unit'
    });
    }

    if (value.includes('%')) {
    deps.add({
    property,
    dependsOn: 'parent-size',
    type: 'percentage'
    });
    }

    // 检查CSS变量
    const varMatch = value.match(/var\\(–([^)]+)\\)/);
    if (varMatch) {
    deps.add({
    property,
    dependsOn: `var-${varMatch[1]}`,
    type: 'css-variable'
    });
    }
    }
    }
    }

    结语

    通过本文的详细阐述,我们完整地构建了一个功能齐全的CSS解析器,实现了从词法分析、语法解析到选择器匹配和样式计算的全过程。这个解析器不仅能够处理基本的CSS规则,还支持复杂的选择器匹配、层叠计算、继承处理和性能优化。

    手写CSS解析器的意义不仅在于技术实现本身,更重要的是通过这个过程,我们能够:

  • 深入理解浏览器工作原理:CSS解析是浏览器渲染引擎的核心部分,理解这一过程有助于我们编写更高效的CSS代码。

  • 掌握编译原理实践:CSS解析器是一个典型的编译器前端实现,涉及词法分析、语法分析等编译原理核心概念。

  • 构建自定义样式解决方案:基于自定义解析器,我们可以构建CSS-in-JS、可视化样式编辑器、样式优化工具等高级应用。

  • 性能优化基础:理解样式计算过程有助于我们发现和解决Web应用中的样式性能瓶颈。

  • 跨平台样式引擎:可以基于此解析器构建跨平台的样式引擎,用于移动端、桌面端或游戏UI系统。

  • 虽然本文实现的CSS解析器已经相当完整,但在生产环境中使用还需要考虑更多因素,如完整的CSS规范支持、错误恢复机制、内存管理优化等。此外,随着CSS标准的不断发展,解析器也需要持续更新以支持新特性。

    希望本文能够为读者提供深入的CSS解析器实现指导,并激发更多关于Web技术底层实现的探索兴趣。通过理解这些基础技术,我们能够更好地驾驭现代Web开发,构建更高效、更可靠的Web应用。

    附录

    A. CSS解析器完整源码结构

    text

    css-parser/
    ├── src/
    │ ├── lexer/
    │ │ ├── CharStream.js
    │ │ ├── CSSLexer.js
    │ │ └── OptimizedCSSLexer.js
    │ ├── parser/
    │ │ ├── CSSParser.js
    │ │ ├── OptimizedCSSParser.js
    │ │ └── ModernCSSParser.js
    │ ├── selector/
    │ │ ├── SelectorMatcher.js
    │ │ ├── RuleIndex.js
    │ │ └── SpecificityCalculator.js
    │ ├── cascade/
    │ │ ├── StyleCascade.js
    │ │ ├── CSSValueCalculator.js
    │ │ └── InheritanceManager.js
    │ ├── engine/
    │ │ ├── CSSEngine.js
    │ │ ├── OptimizedCSSEngine.js
    │ │ └── HighPerformanceCSSEngine.js
    │ └── utils/
    │ ├── LRUCache.js
    │ ├── WorkerPool.js
    │ └── IncrementalParser.js
    ├── test/
    │ ├── CSSParserTestSuite.js
    │ ├── CSSPerformanceBenchmark.js
    │ └── BrowserCompatibilityTester.js
    ├── examples/
    │ ├── styled-components.js
    │ ├── visual-css-editor.js
    │ └── css-optimizer.js
    └── docs/
    ├── API.md
    ├── ARCHITECTURE.md
    └── PERFORMANCE.md

    B. 推荐阅读与学习资源

  • CSS规范文档

    • CSS Syntax Module Level 3

    • CSS Selectors Level 4

    • CSS Cascading and Inheritance Level 4

  • 浏览器源码

    • WebKit/Blink源码中的CSS解析部分

    • Firefox Servo引擎的样式系统

  • 相关工具和库

    • PostCSS:现代CSS处理器

    • CSSOM:CSS对象模型操作库

    • Styled-components:CSS-in-JS实现

  • 进阶主题

    • 样式隔离与Shadow DOM

    • CSS Houdini:浏览器扩展API

    • 响应式设计原理与实现

  • 通过不断学习和实践,我们可以将CSS解析器的理解应用到实际项目中,提升Web应用的性能和用户体验。

    赞(0)
    未经允许不得转载:171主机测评 » 手搓CSS解析器:实现完整选择器匹配与样式计算
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址