CSS教程

CSS重要函数:var(), url(), attr()

CSS重要函数:变量、URL和属性函数

CSS提供了众多功能强大的函数,其中var()url()attr()是三个非常实用且应用场景各不相同的函数。本文将详细介绍这三个函数的使用方法、应用场景以及它们如何提升CSS的开发效率和维护性。

1. var()函数:CSS自定义变量

CSS自定义属性(也称为CSS变量)允许开发者在整个样式表中存储和复用值,大大提高了CSS代码的可维护性。

1.1 基本语法与使用

自定义属性名需要以两个减号(--)开头,属性值则可以是任何有效的CSS值。通过var()函数可以获取这些自定义属性的值。

/* 在根元素定义全局变量 */
:root {
  --primary-color: #eb6844;
  --secondary-color: #2b2b2b;
  --default-font-size: 1rem;
  --main-padding: 15px;
}

/* 使用变量 */
.element {
  color: var(--primary-color);
  background: var(--secondary-color);
  font-size: var(--default-font-size);
  padding: var(--main-padding);
}

1.2 变量作用域

CSS变量遵循作用域规则,分为全局变量和局部变量。

/* 全局变量 */
:root {
  --main-bg-color: brown;
  --text-color: #333;
}

/* 局部变量 */
.container {
  --container-width: 1200px;
  --internal-padding: 20px;

  width: var(--container-width);
  background-color: var(--main-bg-color);
}

/* 只能在.container及其子元素中使用--internal-padding */
.content {
  padding: var(--internal-padding);
  color: var(--text-color);
}

1.3 回退值处理

当变量无效或未定义时,var()函数可以接受回退值。

.element {
  /* 如果--primary-color不存在,使用orange */
  color: var(--primary-color, orange);

  /* 嵌套回退值 */
  background-color: var(--undefined-var, var(--secondary-color, #fff));

  /* 多个回退值 */
  font-size: var(--undefined-size, var(--another-undefined, 16px));
}

1.4 与calc()函数结合

CSS变量可以与calc()函数结合进行动态计算。

:root {
  --base-size: 12;
  --spacing-unit: 8px;
}

.element {
  /* 正确写法 */
  font-size: calc(1px * var(--base-size));
  margin: calc(var(--spacing-unit) * 2);

  /* 错误写法:font-size: calc(1 * var(--size)px); */
}

1.5 完整示例页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS var()函数示例</title>
  <style>
    :root {
      --theme-color: #3498db;
      --text-color: #2c3e50;
      --spacing: 20px;
      --border-radius: 8px;
      --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
    }

    .card {
      background-color: white;
      padding: var(--spacing);
      border-radius: var(--border-radius);
      box-shadow: var(--box-shadow);
      margin: var(--spacing);
      border-left: 4px solid var(--theme-color);
    }

    .card h3 {
      color: var(--theme-color);
      margin-top: 0;
    }

    .card p {
      color: var(--text-color);
      line-height: 1.6;
    }

    .button {
      display: inline-block;
      background-color: var(--theme-color);
      color: white;
      padding: 10px 20px;
      border-radius: var(--border-radius);
      text-decoration: none;
      border: none;
      cursor: pointer;
    }

    .button:hover {
      opacity: 0.9;
    }
  </style>
</head>
<body>
  <div class="card">
    <h3>CSS变量示例</h3>
    <p>这个卡片使用CSS自定义属性定义样式。尝试修改根元素中的变量值来查看变化。</p>
    <button class="button">示例按钮</button>
  </div>
</body>
</html>

1.6 使用JavaScript操作CSS变量

CSS变量可以通过JavaScript动态获取和修改。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JavaScript操作CSS变量</title>
  <style>
    :root {
      --primary-color: #3498db;
      --box-size: 150px;
    }

    .box {
      width: var(--box-size);
      height: var(--box-size);
      background-color: var(--primary-color);
      margin: 20px auto;
      transition: all 0.3s ease;
    }

    .controls {
      text-align: center;
      margin: 20px;
    }

    button {
      padding: 8px 16px;
      margin: 0 5px;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <div class="box" id="zzw_demoBox"></div>

  <div class="controls">
    <button onclick="zzw_changeColor('#e74c3c')">红色</button>
    <button onclick="zzw_changeColor('#2ecc71')">绿色</button>
    <button onclick="zzw_changeColor('#3498db')">蓝色</button>
    <button onclick="zzw_changeSize('200px')">变大</button>
    <button onclick="zzw_changeSize('100px')">变小</button>
  </div>

  <script>
    // 获取根元素
    const zzw_root = document.documentElement;

    // 修改变量值函数
    function zzw_changeColor(color) {
      zzw_root.style.setProperty('--primary-color', color);
    }

    function zzw_changeSize(size) {
      zzw_root.style.setProperty('--box-size', size);
    }

    // 获取变量值
    function zzw_getVariableValue(varName) {
      return getComputedStyle(zzw_root).getPropertyValue(varName);
    }

    // 示例:获取当前主要颜色
    console.log('当前主要颜色:', zzw_getVariableValue('--primary-color'));
  </script>
</body>
</html>

2. url()函数:处理外部资源

url()函数用于在CSS中引用外部资源,如背景图像、字体文件等。

2.1 基本语法

element {
  background-image: url(path/to/resource);
}

2.2 不同路径写法

url()函数支持多种路径写法,适应不同的资源位置需求。

/* 相对路径 */
.logo {
  background-image: url(images/logo.png);
}

/* 向上一级目录 */
.background {
  background-image: url(../assets/bg.jpg);
}

/* 进入子目录 */
.icon {
  background-image: url(icons/user.svg);
}

/* 根路径 */
.banner {
  background-image: url(/images/banner.jpg);
}

/* 绝对URL */
.external {
  background-image: url(https://example.com/images/photo.jpg);
}

2.3 完整示例页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS url()函数示例</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 20px;
    }

    .image-container {
      width: 100%;
      height: 300px;
      margin: 20px 0;
      border: 1px solid #ddd;
      background-size: cover;
      background-position: center;
      background-repeat: no-repeat;
    }

    .local-image {
      /* 假设项目目录中有images/bg.jpg文件 */
      background-image: url(images/bg.jpg);
    }

    .absolute-image {
      /* 使用在线图片URL */
      background-image: url(https://via.placeholder.com/800x400/3498db/ffffff?text=Placeholder+Image);
    }

    .gradient-overlay {
      /* 结合渐变使用 */
      background-image: 
        linear-gradient(rgba(0,0,0,0.5), rgba(0,0,0,0.5)),
        url(images/bg.jpg);
    }

    .custom-cursor {
      cursor: url(images/cursor.png), auto;
    }

    @font-face {
      font-family: 'CustomFont';
      src: url(fonts/custom-font.woff2) format('woff2'),
           url(fonts/custom-font.woff) format('woff');
    }

    .custom-font {
      font-family: 'CustomFont', Arial, sans-serif;
    }
  </style>
</head>
<body>
  <h1>CSS url()函数示例</h1>

  <h2>本地图片背景</h2>
  <div class="image-container local-image"></div>

  <h2>在线图片背景</h2>
  <div class="image-container absolute-image"></div>

  <h2>渐变叠加背景</h2>
  <div class="image-container gradient-overlay"></div>

  <h2 class="custom-cursor">自定义光标(悬停查看)</h2>

  <h2 class="custom-font">自定义字体示例</h2>
</body>
</html>

2.4 注意事项

  1. 路径解析:相对路径是相对于CSS文件的位置,而不是HTML文件。
  2. 跨域问题:加载外部域资源时可能遇到跨域限制。
  3. 性能考虑:过多或过大的外部资源会影响页面加载性能。
  4. 错误处理:当资源加载失败时,需要有适当的回退方案。

3. attr()函数:获取HTML属性值

attr()函数用于获取所选元素的HTML属性值并在样式表中使用。

3.1 基本语法

element::before {
  content: attr(attribute-name);
}

3.2 支持的值类型

attr()函数可以接受类型参数,将属性值解析为特定的CSS数据类型。

/* 字符串(默认) */
.text::before {
  content: attr(data-text);
}

/* 颜色值 */
.color-box {
  background-color: attr(data-bg-color color);
}

/* 数值 */
.slider {
  width: attr(data-width px, 100px);
}

/* URL */
.link {
  background-image: attr(data-bg-url url);
}

3.3 完整示例页面

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS attr()函数示例</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 800px;
      margin: 0 auto;
      padding: 20px;
    }

    /* 基础用法 - 工具提示 */
    .tooltip {
      position: relative;
      display: inline-block;
      border-bottom: 1px dotted #333;
      cursor: help;
      margin: 20px 0;
    }

    .tooltip::after {
      content: attr(data-tooltip);
      position: absolute;
      bottom: 125%;
      left: 50%;
      transform: translateX(-50%);
      background-color: #333;
      color: white;
      padding: 5px 10px;
      border-radius: 4px;
      white-space: nowrap;
      opacity: 0;
      transition: opacity 0.3s;
      pointer-events: none;
      font-size: 14px;
    }

    .tooltip:hover::after {
      opacity: 1;
    }

    /* 进度条 */
    .progress-bar {
      width: 100%;
      height: 20px;
      background-color: #f0f0f0;
      border-radius: 10px;
      overflow: hidden;
      margin: 15px 0;
    }

    .progress-bar::before {
      content: "";
      display: block;
      height: 100%;
      width: attr(data-progress %);
      background-color: #3498db;
      transition: width 0.3s ease;
    }

    /* 卡片组件 */
    .card {
      border: 1px solid #ddd;
      border-radius: 8px;
      padding: 15px;
      margin: 15px 0;
      background-color: #f9f9f9;
    }

    .card::before {
      content: attr(data-type);
      display: inline-block;
      background-color: #3498db;
      color: white;
      padding: 2px 8px;
      border-radius: 4px;
      font-size: 12px;
      margin-bottom: 10px;
      text-transform: uppercase;
    }

    /* 自定义列表 */
    .custom-list {
      list-style: none;
      padding: 0;
    }

    .custom-list li {
      margin: 10px 0;
      padding-left: 25px;
      position: relative;
    }

    .custom-list li::before {
      content: attr(data-icon);
      position: absolute;
      left: 0;
      top: 0;
      width: 20px;
      height: 20px;
      text-align: center;
    }
  </style>
</head>
<body>
  <h1>CSS attr()函数示例</h1>

  <h2>工具提示</h2>
  <div class="tooltip" data-tooltip="这是一个工具提示内容">
    悬停在我上面查看工具提示
  </div>

  <h2>进度条</h2>
  <div class="progress-bar" data-progress="75">
    <div class="progress-text">75%</div>
  </div>

  <h2>卡片组件</h2>
  <div class="card" data-type="信息">
    <h3>卡片标题</h3>
    <p>这是一个使用attr()函数显示类型的卡片。</p>
  </div>

  <div class="card" data-type="警告">
    <h3>警告卡片</h3>
    <p>这是一个警告类型的卡片。</p>
  </div>

  <h2>自定义列表</h2>
  <ul class="custom-list">
    <li data-icon="✓">列表项一</li>
    <li data-icon="★">列表项二</li>
    <li data-icon="➜">列表项三</li>
  </ul>
</body>
</html>

3.4 高级用法结合JavaScript

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>attr()与JavaScript结合</title>
  <style>
    :root {
      --theme-color: #3498db;
    }

    .dynamic-element {
      width: 200px;
      height: 100px;
      margin: 20px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: bold;
    }

    /* 使用数据属性控制样式 */
    .color-box[data-color="red"] {
      background-color: #e74c3c;
    }

    .color-box[data-color="green"] {
      background-color: #2ecc71;
    }

    .color-box[data-color="blue"] {
      background-color: #3498db;
    }

    .size-box::after {
      content: "宽度: " attr(data-width);
      font-size: 14px;
      margin-top: 10px;
      display: block;
    }

    /* 动态内容 */
    .user-card::before {
      content: "用户: " attr(data-username);
      display: block;
      font-size: 12px;
      color: #666;
      margin-bottom: 5px;
    }
  </style>
</head>
<body>
  <h1>attr()与JavaScript结合示例</h1>

  <div class="dynamic-element color-box" data-color="red" id="zzw_colorBox">
    颜色盒子
  </div>

  <div class="dynamic-element size-box" data-width="200px" id="zzw_sizeBox">
    尺寸盒子
  </div>

  <div class="dynamic-element user-card" data-username="默认用户" id="zzw_userCard">
    用户信息卡片
  </div>

  <button onclick="zzw_changeColor()">切换颜色</button>
  <button onclick="zzw_changeSize()">改变尺寸</button>
  <button onclick="zzw_changeUser()">更改用户</button>

  <script>
    const zzw_colorBox = document.getElementById('zzw_colorBox');
    const zzw_sizeBox = document.getElementById('zzw_sizeBox');
    const zzw_userCard = document.getElementById('zzw_userCard');

    let zzw_colorIndex = 0;
    const zzw_colors = ['red', 'green', 'blue'];

    function zzw_changeColor() {
      zzw_colorIndex = (zzw_colorIndex + 1) % zzw_colors.length;
      zzw_colorBox.setAttribute('data-color', zzw_colors[zzw_colorIndex]);
    }

    function zzw_changeSize() {
      const widths = ['200px', '250px', '300px', '150px'];
      const currentWidth = zzw_sizeBox.getAttribute('data-width');
      const currentIndex = widths.indexOf(currentWidth);
      const nextIndex = (currentIndex + 1) % widths.length;

      zzw_sizeBox.setAttribute('data-width', widths[nextIndex]);
      zzw_sizeBox.style.width = widths[nextIndex];
    }

    function zzw_changeUser() {
      const users = ['张三', '李四', '王五', '赵六'];
      const randomUser = users[Math.floor(Math.random() * users.length)];
      zzw_userCard.setAttribute('data-username', randomUser);
    }
  </script>
</body>
</html>

3.5 注意事项

  1. 浏览器兼容性:除了content属性外,其他属性对attr()的支持仍处于实验阶段。
  2. 类型限制:需要确保HTML属性的值与CSS属性期望的类型匹配。
  3. 性能考虑:过度使用可能导致性能问题,特别是在动态修改时。

4. 综合应用实例

下面是一个综合运用var()url()attr()函数的完整示例。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS函数综合示例</title>
  <style>
    :root {
      --primary-color: #3498db;
      --secondary-color: #2ecc71;
      --danger-color: #e74c3c;
      --text-color: #2c3e50;
      --spacing: 15px;
      --border-radius: 6px;
      --box-shadow: 0 2px 5px rgba(0,0,0,0.1);
      --background-url: url(https://via.placeholder.com/100/3498db/ffffff?text=IMG);
    }

    .dashboard {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: var(--spacing);
      padding: var(--spacing);
      max-width: 1200px;
      margin: 0 auto;
    }

    .widget {
      background: white;
      border-radius: var(--border-radius);
      box-shadow: var(--box-shadow);
      padding: var(--spacing);
      position: relative;
    }

    .widget::before {
      content: attr(data-widget-type);
      position: absolute;
      top: -10px;
      right: 10px;
      background-color: var(--primary-color);
      color: white;
      padding: 2px 8px;
      border-radius: 10px;
      font-size: 12px;
      text-transform: uppercase;
    }

    .widget-header {
      display: flex;
      align-items: center;
      margin-bottom: 10px;
    }

    .widget-icon {
      width: 40px;
      height: 40px;
      background-image: var(--background-url);
      background-size: cover;
      border-radius: 50%;
      margin-right: 10px;
    }

    .widget-title {
      color: var(--text-color);
      margin: 0;
      font-size: 18px;
    }

    .progress-container {
      margin: 15px 0;
    }

    .progress-bar {
      height: 10px;
      background-color: #ecf0f1;
      border-radius: 5px;
      overflow: hidden;
    }

    .progress-fill {
      height: 100%;
      background-color: var(--secondary-color);
      width: attr(data-progress %);
      transition: width 0.5s ease;
    }

    .stats {
      display: flex;
      justify-content: space-between;
      margin-top: 10px;
    }

    .stat-item {
      text-align: center;
    }

    .stat-value {
      font-size: 24px;
      font-weight: bold;
      color: var(--primary-color);
    }

    .stat-label {
      font-size: 12px;
      color: #7f8c8d;
    }

    /* 动态主题 */
    .theme-selector {
      text-align: center;
      margin: 20px 0;
    }

    .theme-button {
      padding: 8px 16px;
      margin: 0 5px;
      border: none;
      border-radius: var(--border-radius);
      cursor: pointer;
      background-color: #bdc3c7;
      color: var(--text-color);
    }

    .theme-button.active {
      background-color: var(--primary-color);
      color: white;
    }
  </style>
</head>
<body>
  <div class="theme-selector">
    <button class="theme-button active" onclick="zzw_changeTheme('default')">默认主题</button>
    <button class="theme-button" onclick="zzw_changeTheme('dark')">暗色主题</button>
    <button class="theme-button" onclick="zzw_changeTheme('warm')">暖色主题</button>
  </div>

  <div class="dashboard">
    <div class="widget" data-widget-type="统计" data-progress="75">
      <div class="widget-header">
        <div class="widget-icon"></div>
        <h3 class="widget-title">项目进度</h3>
      </div>
      <div class="progress-container">
        <div class="progress-bar">
          <div class="progress-fill" data-progress="75"></div>
        </div>
        <div class="stats">
          <div class="stat-item">
            <div class="stat-value">75%</div>
            <div class="stat-label">完成度</div>
          </div>
          <div class="stat-item">
            <div class="stat-value">15</div>
            <div class="stat-label">剩余天数</div>
          </div>
        </div>
      </div>
    </div>

    <div class="widget" data-widget-type="提醒" data-progress="30">
      <div class="widget-header">
        <div class="widget-icon"></div>
        <h3 class="widget-title">任务状态</h3>
      </div>
      <div class="progress-container">
        <div class="progress-bar">
          <div class="progress-fill" data-progress="30"></div>
        </div>
        <div class="stats">
          <div class="stat-item">
            <div class="stat-value">30%</div>
            <div class="stat-label">进行中</div>
          </div>
          <div class="stat-item">
            <div class="stat-value">7/10</div>
            <div class="stat-label">已完成</div>
          </div>
        </div>
      </div>
    </div>

    <div class="widget" data-widget-type="信息" data-progress="90">
      <div class="widget-header">
        <div class="widget-icon"></div>
        <h3 class="widget-title">资源使用</h3>
      </div>
      <div class="progress-container">
        <div class="progress-bar">
          <div class="progress-fill" data-progress="90"></div>
        </div>
        <div class="stats">
          <div class="stat-item">
            <div class="stat-value">90%</div>
            <div class="stat-label">使用率</div>
          </div>
          <div class="stat-item">
            <div class="stat-value">45GB</div>
            <div class="stat-label">已使用</div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    function zzw_changeTheme(theme) {
      const root = document.documentElement;

      // 移除所有主题类
      root.classList.remove('theme-default', 'theme-dark', 'theme-warm');

      // 添加当前主题类
      root.classList.add(`theme-${theme}`);

      // 更新活跃按钮
      document.querySelectorAll('.theme-button').forEach(btn => {
        btn.classList.remove('active');
      });
      event.target.classList.add('active');

      // 根据主题更新CSS变量
      if (theme === 'dark') {
        root.style.setProperty('--primary-color', '#9b59b6');
        root.style.setProperty('--secondary-color', '#1abc9c');
        root.style.setProperty('--text-color', '#ecf0f1');
        root.style.setProperty('--background-url', 'url(https://via.placeholder.com/100/9b59b6/ffffff?text=IMG)');
      } else if (theme === 'warm') {
        root.style.setProperty('--primary-color', '#e67e22');
        root.style.setProperty('--secondary-color', '#e74c3c');
        root.style.setProperty('--text-color', '#34495e');
        root.style.setProperty('--background-url', 'url(https://via.placeholder.com/100/e67e22/ffffff?text=IMG)');
      } else {
        // 默认主题
        root.style.setProperty('--primary-color', '#3498db');
        root.style.setProperty('--secondary-color', '#2ecc71');
        root.style.setProperty('--text-color', '#2c3e50');
        root.style.setProperty('--background-url', 'url(https://via.placeholder.com/100/3498db/ffffff?text=IMG)');
      }
    }

    // 动态更新进度条
    function zzw_animateProgress() {
      document.querySelectorAll('.progress-fill').forEach(bar => {
        const progress = bar.getAttribute('data-progress');
        bar.style.width = progress + '%';
      });
    }

    // 页面加载完成后执行动画
    window.addEventListener('load', zzw_animateProgress);
  </script>
</body>
</html>

5. 浏览器兼容性总结

在使用这三个CSS函数时,需要注意浏览器兼容性问题:

函数基本支持备注
var()现代浏览器广泛支持IE不支持,新版Edge支持
url()所有浏览器完全支持路径解析一致,跨域资源可能有限制
attr()基础功能支持良好content属性外,其他使用仍为实验性功能

知识点总结

知识点内容描述
var()函数用于访问CSS自定义属性(变量)的值,提高代码可维护性和主题一致性
CSS变量定义使用--前缀定义自定义属性,通常在:root伪类中定义全局变量
变量作用域CSS变量遵循作用域规则,分全局变量和局部变量,局部变量可覆盖全局变量
回退值var()函数支持提供回退值,当变量无效时使用
JavaScript操作可通过setProperty()getPropertyValue()方法动态修改和获取CSS变量
url()函数用于引用外部资源,如图片、字体等,支持相对路径和绝对路径
路径解析相对路径相对于CSS文件位置解析,可使用多种路径格式
attr()函数用于获取HTML元素的属性值并在CSS中使用,常用于content属性
属性类型attr()支持类型参数,可将属性值解析为颜色、数值等特定CSS数据类型
函数组合三个函数可结合使用,并与calc()等其他CSS函数配合,实现复杂样式效果

通过掌握var()url()attr()这三个重要的CSS函数,开发者可以创建更加动态、可维护和响应式的网页设计,减少对JavaScript的依赖,提高开发效率。