当前位置: 首页 > article >正文

名词(术语)了解--CSSOM (CSS Object Model)

名词(术语)了解–CSSOM (CSS Object Model)

在这里插入图片描述

CSSOM 概述

CSSOM 是一个与 DOM (Document Object Model) 相对应的、用于 CSS 的 API 集合。

它提供了一种程序化的方式来读取和修改文档的样式信息。

CSSOM 的主要组成部分

  1. 样式规则树
document
└── stylesheets
    └── cssRules
        ├── style rule 1
        │   ├── selector
        │   └── declaration block
        ├── style rule 2
        └── style rule 3
  1. 计算样式
  • 浏览器会将所有适用的 CSS 规则计算并应用到每个 DOM 节点
  • 继承属性会从父节点传递到子节点
  • 最终每个节点都会有一个完整的计算样式(computed style)

CSSOM API 主要功能

  1. 读取样式信息
// 获取元素的计算样式
const style = window.getComputedStyle(element);
console.log(style.backgroundColor);

// 访问样式表
const sheets = document.styleSheets;
  1. 修改样式
// 直接修改元素样式
element.style.backgroundColor = 'red';

// 添加新的样式规则
const sheet = document.styleSheets[0];
sheet.insertRule('body { background-color: lightblue }', 0);
  1. 操作 CSS 规则
// 获取所有CSS规则
const rules = document.styleSheets[0].cssRules;

// 删除规则
document.styleSheets[0].deleteRule(0);

CSSOM 渲染过程

  1. 构建过程

    • 加载 HTML → 构建 DOM
    • 加载 CSS → 构建 CSSOM
    • DOM + CSSOM = 渲染树(Render Tree)
  2. 性能注意事项

    • CSS 被视为渲染阻塞资源
    • CSSOM 构建会阻止页面渲染
    • 优化建议:
      • 精简 CSS
      • 移除未使用的 CSS
      • 使用媒体查询划分 CSS

实际应用示例

  1. 动态主题切换
// 通过 CSSOM 实现动态主题切换
function toggleTheme(isDark) {
    const root = document.documentElement;
    if (isDark) {
        root.style.setProperty('--bg-color', '#333');
        root.style.setProperty('--text-color', '#fff');
    } else {
        root.style.setProperty('--bg-color', '#fff');
        root.style.setProperty('--text-color', '#333');
    }
}
  1. 响应式样式调整
// 监听视窗变化并动态调整样式
const mediaQuery = window.matchMedia('(max-width: 768px)');

function handleScreenChange(e) {
    if (e.matches) {
        // 小屏幕样式调整
        document.body.style.fontSize = '14px';
    } else {
        // 大屏幕样式调整
        document.body.style.fontSize = '16px';
    }
}

mediaQuery.addListener(handleScreenChange);

最佳实践

  1. 性能优化

    • 减少选择器复杂度
    • 避免频繁修改样式
    • 使用 CSS 类名切换代替直接样式操作
  2. 代码组织

    • 将样式操作封装成可复用的函数
    • 使用 CSS 变量实现主题系统
    • 保持 CSS 结构清晰
  3. 调试技巧

    • 使用浏览器开发工具的 Elements 面板
    • 利用 Computed 标签页查看计算样式
    • 使用 Sources 面板调试样式修改

深入CSSOM

1. CSSOM 的高级特性

1.1 视图相关 API (CSSOM View Module)

CSSOM View Module 提供了与元素视图相关的属性和方法:

// 1. 获取元素尺寸
const element = document.querySelector('.box');

// 元素完整尺寸(包括内边距和边框)
console.log(element.offsetWidth, element.offsetHeight);

// 元素内部尺寸(包括内边距)
console.log(element.clientWidth, element.clientHeight);

// 元素实际内容尺寸(包括溢出部分)
console.log(element.scrollWidth, element.scrollHeight);

// 2. 获取元素位置
// 相对于带定位父元素的偏移
console.log(element.offsetLeft, element.offsetTop);

// 相对于视口的位置
const rect = element.getBoundingClientRect();
console.log(rect.top, rect.left, rect.bottom, rect.right);

// 3. 视口信息
console.log(window.innerWidth, window.innerHeight); // 视口大小
console.log(window.pageXOffset, window.pageYOffset); // 页面滚动位置

1.2 CSS 自定义属性(CSS Variables)操作

// 1. 定义全局 CSS 变量
document.documentElement.style.setProperty('--primary-color', '#007bff');

// 2. 读取 CSS 变量
const styles = getComputedStyle(document.documentElement);
const primaryColor = styles.getPropertyValue('--primary-color');

// 3. 动态主题实现
class ThemeManager {
    constructor() {
        this.root = document.documentElement;
    }

    setTheme(theme) {
        const themes = {
            light: {
                '--bg-color': '#ffffff',
                '--text-color': '#333333',
                '--shadow-color': 'rgba(0,0,0,0.1)'
            },
            dark: {
                '--bg-color': '#333333',
                '--text-color': '#ffffff',
                '--shadow-color': 'rgba(255,255,255,0.1)'
            }
        };

        Object.entries(themes[theme]).forEach(([property, value]) => {
            this.root.style.setProperty(property, value);
        });
    }
}

2. 高级应用场景

2.1 响应式布局管理器

class ResponsiveLayoutManager {
    constructor() {
        this.breakpoints = {
            mobile: 480,
            tablet: 768,
            desktop: 1024
        };
        this.mediaQueries = {};
        this.init();
    }

    init() {
        Object.entries(this.breakpoints).forEach(([device, width]) => {
            const query = window.matchMedia(`(min-width: ${width}px)`);
            query.addListener(this.handleBreakpoint.bind(this));
            this.mediaQueries[device] = query;
        });
    }

    handleBreakpoint(e) {
        const html = document.documentElement;
        Object.entries(this.mediaQueries).forEach(([device, query]) => {
            if (query.matches) {
                html.setAttribute('data-device', device);
            }
        });
    }
}

const layoutManager = new ResponsiveLayoutManager();

2.2 动画性能优化器

class AnimationOptimizer {
    static prepareForAnimation(element) {
        // 强制浏览器创建新的图层,优化动画性能
        element.style.willChange = 'transform';
        
        // 使用 transform 代替位置属性
        element.style.transform = 'translateZ(0)';
    }

    static cleanupAfterAnimation(element) {
        // 动画结束后清理
        element.style.willChange = 'auto';
    }

    static smoothAnimation(element, properties, duration = 300) {
        this.prepareForAnimation(element);

        const animations = Object.entries(properties).map(([prop, value]) => {
            return element.animate({
                [prop]: value
            }, {
                duration,
                easing: 'cubic-bezier(0.4, 0, 0.2, 1)'
            });
        });

        Promise.all(animations.map(anim => anim.finished))
            .then(() => this.cleanupAfterAnimation(element));
    }
}

2.3 样式隔离实现

class StyleIsolator {
    constructor(scopeName) {
        this.scopeName = scopeName;
        this.styleSheet = this.createStyleSheet();
    }

    createStyleSheet() {
        const style = document.createElement('style');
        document.head.appendChild(style);
        return style.sheet;
    }

    addRule(selector, cssText) {
        // 添加作用域前缀
        const scopedSelector = `.${this.scopeName} ${selector}`;
        const rule = `${scopedSelector} { ${cssText} }`;
        this.styleSheet.insertRule(rule, this.styleSheet.cssRules.length);
    }

    removeAllRules() {
        while (this.styleSheet.cssRules.length > 0) {
            this.styleSheet.deleteRule(0);
        }
    }
}

3. 性能优化最佳实践

3.1 批量样式修改

class StyleBatchProcessor {
    static batchUpdate(element, updates) {
        // 将元素脱离文档流
        const display = element.style.display;
        element.style.display = 'none';

        // 批量更新样式
        requestAnimationFrame(() => {
            Object.entries(updates).forEach(([prop, value]) => {
                element.style[prop] = value;
            });
            
            // 重新加入文档流
            element.style.display = display;
        });
    }
}

// 使用示例
StyleBatchProcessor.batchUpdate(element, {
    backgroundColor: '#fff',
    transform: 'translateX(100px)',
    opacity: '0.8'
});

3.2 样式计算缓存

class StyleCache {
    constructor() {
        this.cache = new WeakMap();
    }

    getComputedStyle(element, property) {
        if (!this.cache.has(element)) {
            this.cache.set(element, new Map());
        }

        const elementCache = this.cache.get(element);
        if (!elementCache.has(property)) {
            const value = window.getComputedStyle(element)[property];
            elementCache.set(property, value);
        }

        return elementCache.get(property);
    }

    invalidate(element) {
        this.cache.delete(element);
    }
}

3.3 CSS 动画性能监控

class AnimationPerformanceMonitor {
    static startMonitoring() {
        this.observer = new PerformanceObserver((list) => {
            for (const entry of list.getEntries()) {
                if (entry.entryType === 'layout-shift') {
                    console.warn('Layout shift detected:', entry.value);
                }
            }
        });

        this.observer.observe({ entryTypes: ['layout-shift'] });
    }

    static measureAnimationPerformance(element, animationDuration) {
        const startTime = performance.now();
        
        const cleanup = () => {
            const endTime = performance.now();
            const duration = endTime - startTime;
            
            if (duration > animationDuration * 1.1) {
                console.warn('Animation performance issue detected');
            }
        };

        element.addEventListener('transitionend', cleanup, { once: true });
    }
}

http://www.kler.cn/a/370148.html

相关文章:

  • 使用vue-next-admin框架后台修改动态路由
  • [Qt]系统相关-多线程、线程安全问题以及线程的同步机制
  • Level2逐笔成交逐笔委托毫秒记录:今日分享优质股票数据20250121
  • QT多语言Demo及心得
  • 前瞻2024:前沿技术的全景洞察与深度剖析
  • 迈向 “全能管家” 之路:机器人距离终极蜕变还需几步?
  • SLAM|1. 相机投影及相机畸变
  • 从理解路由到实现一套Router(路由)
  • 九,Linux基础环境搭建(CentOS7)- 安装Sqoop
  • 【ROS 基础教学系列】机器人仿真运动控制
  • 5款项目管理软件,帮你做好任务管理
  • 自定义Widget插入QListWidget中,大量数据会卡问题
  • unity3D 导入图片与设置
  • 微信小程序-转发/分享/手机号验证/客服
  • uniapp实现左滑删除(详解)
  • python代码中通过pymobiledevice3访问iOS沙盒目录获取app日志
  • C语言中的数组并非指针:深入理解数组和指针的区别
  • EasyPlayer.js网页播放器,支持FLV、HLS、WebSocket、WebRTC、H.264/H.265、MP4、ts各种音视频流播放
  • PHP轻松阅读图书借阅系统小程序源码
  • 5KB实现html+js+css+json无限极分类展现带连线完整实例
  • vue中elementUI的el-select下拉框的层级太高修改设置!
  • el-menu,菜单折叠后菜单项文字不隐藏
  • Makefile Npm
  • 【香蕉成熟度数据集】香蕉新鲜腐烂识别检测 目标检测 机器视觉 (含数据集)
  • 51单片机应用开发---定时器(定时1S,LED以1S间隔闪烁)
  • VulkanTutorial(8·Shader modules)