Skip to content

CSS 性能优化

性能优化简介

CSS性能优化是指通过优化CSS代码和加载方式,提高页面渲染速度和用户体验。

选择器优化

1. 避免使用通配符选择器

css
/* 不好的做法 */
* {
  margin: 0;
  padding: 0;
}

/* 好的做法 */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

2. 避免使用深层嵌套选择器

css
/* 不好的做法 */
.container .header .nav .menu .item {
  color: blue;
}

/* 好的做法 */
.nav-item {
  color: blue;
}

3. 使用类选择器代替标签选择器

css
/* 不好的做法 */
div {
  color: blue;
}

/* 好的做法 */
.container {
  color: blue;
}

4. 避免使用属性选择器进行正则匹配

css
/* 不好的做法 */
a[href^="https://"] {
  color: blue;
}

/* 好的做法 */
.external-link {
  color: blue;
}

5. 使用更具体的选择器

css
/* 不好的做法 */
div {
  color: blue;
}

/* 好的做法 */
.button-primary {
  color: blue;
}

CSS 加载优化

1. 减少CSS文件大小

css
/* 压缩CSS */
.button {
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* 压缩后 */
.button{padding:10px 20px;background-color:#007bff;color:white;border:none;border-radius:4px;cursor:pointer}

2. 使用CSS压缩工具

bash
# 使用cssnano
npm install cssnano-cli --save-dev

# 压缩CSS
cssnano input.css output.css

3. 合并CSS文件

html
<!-- 不好的做法 -->
<link rel="stylesheet" href="reset.css">
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="components.css">

<!-- 好的做法 -->
<link rel="stylesheet" href="main.css">

4. 异步加载CSS

html
<!-- 使用media属性 -->
<link rel="stylesheet" href="print.css" media="print">

<!-- 使用JavaScript异步加载 -->
<script>
  function loadCSS(href) {
    const link = document.createElement('link');
    link.rel = 'stylesheet';
    link.href = href;
    document.head.appendChild(link);
  }
  
  window.addEventListener('load', function() {
    loadCSS('async.css');
  });
</script>

5. 内联关键CSS

html
<style>
  .header {
    background-color: #333;
    color: white;
    padding: 20px;
  }
</style>

渲染性能优化

1. 使用 transform 和 opacity

css
/* 不好的做法 */
.element {
  left: 0;
  transition: left 0.3s ease;
}

.element:hover {
  left: 10px;
}

/* 好的做法 */
.element {
  transform: translateX(0);
  transition: transform 0.3s ease;
}

.element:hover {
  transform: translateX(10px);
}

2. 避免使用 width 和 height 进行动画

css
/* 不好的做法 */
.element {
  width: 100px;
  transition: width 0.3s ease;
}

.element:hover {
  width: 200px;
}

/* 好的做法 */
.element {
  transform: scaleX(1);
  transform-origin: left;
  transition: transform 0.3s ease;
}

.element:hover {
  transform: scaleX(2);
}

3. 使用 will-change 提示浏览器

css
.element {
  will-change: transform, opacity;
}

.element:hover {
  transform: translateX(10px);
}

4. 避免布局抖动

css
/* 不好的做法 */
.element {
  position: static;
  transition: all 0.3s ease;
}

.element:hover {
  margin-left: 10px;
}

/* 好的做法 */
.element {
  position: relative;
  transition: transform 0.3s ease;
}

.element:hover {
  transform: translateX(10px);
}

5. 使用硬件加速

css
.element {
  transform: translateZ(0);
  will-change: transform;
}

图片优化

1. 使用合适的图片格式

html
<!-- WebP格式 -->
<picture>
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="图片">
</picture>

2. 使用响应式图片

html
<img src="small.jpg" 
     srcset="small.jpg 480w, medium.jpg 768w, large.jpg 1024w" 
     sizes="(max-width: 480px) 480px, (max-width: 768px) 768px, 1024px"
     alt="响应式图片">

3. 懒加载图片

html
<img src="placeholder.jpg" 
     data-src="image.jpg" 
     alt="图片" 
     loading="lazy">

<script>
  const images = document.querySelectorAll('img[data-src]');
  
  const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        observer.unobserve(img);
      }
    });
  });
  
  images.forEach(img => imageObserver.observe(img));
</script>

字体优化

1. 使用系统字体

css
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

2. 使用 font-display

css
@font-face {
  font-family: 'MyFont';
  src: url('myfont.woff2') format('woff2');
  font-display: swap;
}

3. 预加载字体

html
<link rel="preload" href="myfont.woff2" as="font" type="font/woff2" crossorigin>

4. 使用字体子集

bash
# 使用fonttools
pip install fonttools

# 提取字体子集
pyftsubset myfont.ttf --text="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"

代码优化

1. 避免重复代码

css
/* 不好的做法 */
.button-primary {
  padding: 10px 20px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.button-secondary {
  padding: 10px 20px;
  background-color: #6c757d;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

/* 好的做法 */
.button {
  padding: 10px 20px;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.button-primary {
  background-color: #007bff;
}

.button-secondary {
  background-color: #6c757d;
}

2. 使用CSS变量

css
:root {
  --primary-color: #007bff;
  --secondary-color: #6c757d;
  --font-size-base: 16px;
  --spacing-unit: 8px;
}

.button {
  padding: calc(var(--spacing-unit) * 1.25) calc(var(--spacing-unit) * 2.5);
  background-color: var(--primary-color);
  font-size: var(--font-size-base);
}

3. 使用简写属性

css
/* 不好的做法 */
.button {
  margin-top: 10px;
  margin-right: 20px;
  margin-bottom: 10px;
  margin-left: 20px;
}

/* 好的做法 */
.button {
  margin: 10px 20px;
}

4. 移除未使用的CSS

bash
# 使用PurgeCSS
npm install purgecss --save-dev

# 移除未使用的CSS
purgecss --css styles.css --content index.html --output output.css

浏览器优化

1. 使用CSS containment

css
.card {
  contain: layout style paint;
}

2. 使用content-visibility

css
.section {
  content-visibility: auto;
  contain-intrinsic-size: 1000px;
}

3. 避免使用@import

html
<!-- 不好的做法 -->
<style>
  @import url('styles.css');
</style>

<!-- 好的做法 -->
<link rel="stylesheet" href="styles.css">

4. 使用媒体查询优化

css
/* 不好的做法 */
@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}

@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}

@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}

/* 好的做法 */
.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 20px;
}

实际应用

1. 关键CSS内联

html
<!DOCTYPE html>
<html>
<head>
  <style>
    .header {
      background-color: #333;
      color: white;
      padding: 20px;
    }
    
    .nav {
      display: flex;
      gap: 20px;
    }
  </style>
  
  <link rel="preload" href="main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
  <noscript><link rel="stylesheet" href="main.css"></noscript>
</head>
<body>
  <header class="header">
    <nav class="nav">
      <a href="/">首页</a>
      <a href="/about">关于</a>
    </nav>
  </header>
</body>
</html>

2. 图片懒加载

html
<img src="placeholder.jpg" 
     data-src="image.jpg" 
     alt="图片" 
     loading="lazy"
     class="lazy-image">

<style>
  .lazy-image {
    opacity: 0;
    transition: opacity 0.3s ease;
  }
  
  .lazy-image.loaded {
    opacity: 1;
  }
</style>

<script>
  const lazyImages = document.querySelectorAll('.lazy-image');
  
  const imageObserver = new IntersectionObserver((entries, observer) => {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        img.onload = () => img.classList.add('loaded');
        observer.unobserve(img);
      }
    });
  });
  
  lazyImages.forEach(img => imageObserver.observe(img));
</script>

面试常见问题

1. 如何优化CSS性能?

  • 优化选择器
  • 减少CSS文件大小
  • 使用transform和opacity
  • 避免布局抖动
  • 使用will-change
  • 懒加载图片
  • 使用CSS变量

2. 为什么使用transform代替left/top?

transform不会触发重排,只会触发重绘,性能更好。

css
/* 不好的做法 */
.element {
  left: 0;
  transition: left 0.3s ease;
}

/* 好的做法 */
.element {
  transform: translateX(0);
  transition: transform 0.3s ease;
}

3. 什么是重排和重绘?

  • 重排(Reflow): 元素的位置、大小发生变化
  • 重绘(Repaint): 元素的外观发生变化

4. 如何避免重排?

  • 使用transform代替left/top
  • 使用opacity代替display
  • 使用will-change提示浏览器
  • 避免频繁读取布局信息

5. 什么是关键CSS?

关键CSS是首屏渲染所需的CSS,应该内联到HTML中,加快首屏渲染速度。

html
<style>
  .header {
    background-color: #333;
    color: white;
  }
</style>

通过理解CSS性能优化的各种技术和最佳实践,可以创建高性能的网页。

好好学习,天天向上