attr()

Baseline 廣泛可用 *

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

* 此特性的某些部分可能存在不同級別的支援。

備註: attr() 函式可用於任何 CSS 屬性,但除 content 之外的屬性支援仍處於實驗階段。

attr() 這個 CSS 函式用於獲取所選元素的屬性值,並將其用於屬性值中,其用法類似於 var() 函式替換自定義屬性值。它也可以用於偽元素,在這種情況下,將返回偽元素源元素的屬性值。

試一試

blockquote {
  margin: 1em 0;
}

blockquote::after {
  display: block;
  content: " (source: " attr(cite) ") ";
  color: hotpink;
}
<blockquote cite="https://mozilla.org/en-US/about/">
  Mozilla makes browsers, apps, code, and tools that put people before profit.
</blockquote>

<blockquote cite="https://web.dev/about/">
  Google believes in an open, accessible, private, and secure web.
</blockquote>

語法

css
/* Basic usage */
attr(data-count)
attr(href)

/* With type */
attr(data-width px)
attr(data-size rem)
attr(data-name raw-string)
attr(id type(<custom-ident>))
attr(data-count type(<number>))
attr(data-size type(<length> | <percentage>))

/* With fallback */
attr(data-count type(<number>), 0)
attr(data-width px, inherit)
attr(data-something, "default")

引數

attr() 函式的語法如下:

attr(<attr-name> <attr-type>? , <fallback-value>?)

引數為:

<attr-name>

應從所選 HTML 元素中檢索其值的屬性名稱。

<attr-type>

指定如何將屬性值解析為 CSS 值。它可以是 raw-string 關鍵字、type() 函式或 CSS 維度單位(使用 <attr-unit> 識別符號指定)。如果省略,則預設為 raw-string

raw-string

raw-string 關鍵字使屬性的字面值被視為 CSS 字串的值,而不進行任何 CSS 解析(包括 CSS 轉義、空白移除、註釋等)。<fallback-value> 僅在省略屬性時使用;指定空值不會觸發回退。

css
attr(data-name raw-string, "stranger")

備註: 此關鍵字最初在 Chromium 瀏覽器中命名並支援為 string。為了向後相容,這兩個關鍵字都將在短期內得到支援。

type()

type() 函式接受一個 <syntax> 作為其引數,該引數指定了將值解析成的資料型別。

備註: 出於安全原因<url> 不允許作為 attr() 的資料型別。

<attr-unit>

<attr-unit> 識別符號指定數值應具有的單位(如果有)。它可以是 % 字元(百分比)或 CSS 距離單位,如 pxremdegs 等。

css
attr(data-size rem)
attr(data-width px, inherit)
attr(data-rotation deg)
<fallback-value>

當指定的屬性缺失或包含無效值時使用的值。

返回值

attr() 的返回值是名為 <attr-name> 的 HTML 屬性的值,該值被解析為給定的 <attr-type> 或解析為 CSS 字串。

當設定了 <attr-type> 時,attr() 會嘗試將屬性解析為指定的 <attr-type> 並返回它。如果屬性無法解析為給定的 <attr-type>,則將返回 <fallback-value>。如果未設定 <attr-type>,屬性將被解析為 CSS 字串。

如果未設定 <fallback-value>,當未設定 <attr-type> 時,返回值將預設為空字串;當設定了 <attr-type> 時,將預設為保證無效值

描述

限制和安全性

attr() 函式可以引用那些從未打算用於樣式化且可能包含敏感資訊的屬性(例如,頁面上指令碼使用的安全令牌)。通常情況下,這沒有問題,但在 URL 中使用時可能會成為安全威脅。因此,你不能使用 attr() 動態構建 URL。

html
<!-- This won't work! -->
<span data-icon="https://example.org/icons/question-mark.svg">help</span>
css
span[data-icon] {
  background-image: url(attr(data-icon));
}

使用 attr() 的值會被標記為attr()-tainted”(受 attr() 汙染的)。將一個 attr()-tainted 值用作或用於 <url> 中,會使宣告在計算值時無效(invalid at computed value time),簡稱 IACVT

向後相容性

一般來說,現代的 attr() 語法是向後相容的,因為舊的使用方式——不指定 <attr-type>——與以前的行為相同。在程式碼中使用 attr(data-attr) 與編寫 attr(data-attr type(<string>)) 或更簡單的 attr(data-attr string)) 是相同的。

然而,有兩種邊緣情況,現代 attr() 語法的行為與舊語法不同。

在以下程式碼片段中,不支援現代 attr() 語法的瀏覽器會丟棄第二個宣告,因為它們無法解析它。在這些瀏覽器中,結果是 "Hello World"

html
<div text="Hello"></div>
css
div::before {
  content: attr(text) " World";
}
div::before {
  content: attr(text) 1px;
}

在支援現代語法的瀏覽器中,輸出將是……什麼都沒有。這些瀏覽器會成功解析第二個宣告,但因為它對於 content 屬性是無效內容,所以該宣告會變得“在計算值時無效”,簡稱 IACVT

為防止這種情況,建議進行特性檢測

第二個邊緣情況如下:

html
<div id="parent"><div id="child" data-attr="foo"></div></div>
css
#parent {
  --x: attr(data-attr);
}
#child::before {
  content: var(--x);
}

不支援現代語法的瀏覽器會顯示文字 "foo"。在支援現代 attr() 的瀏覽器中,則沒有輸出。

這是因為 attr()——類似於使用 var() 函式的自定義屬性——在計算值時進行替換。在現代行為下,--x 首先嚐試從 #parent 元素讀取 data-attr 屬性,因為 #parent 上沒有該屬性,所以結果為空字串。然後該空字串被 #child 元素繼承,導致設定了 content: ; 宣告。

為防止這種情況,除非你明確希望如此,否則不要將繼承的 attr() 值傳遞給子元素。

特性檢測

你可以使用 @supports at-rule 來檢測對現代 attr() 語法的支援。在測試中,嘗試將一個高階 attr() 賦值給一個(非自定義的)CSS 屬性。

例如

css
@supports (x: attr(x type(*))) {
  /* Browser has modern attr() support */
}

@supports not (x: attr(x type(*))) {
  /* Browser does not have modern attr() support */
}

我們可以使用 CSS.supports() 在 JavaScript 中執行相同的檢查:

js
if (CSS.supports("x: attr(x type(*))")) {
  /* Browser has modern attr() support */
}

if (!CSS.supports("x: attr(x type(*))")) {
  /* Browser does not have modern attr() support */
}

正式語法

<attr()> = 
attr( <attr-name> <attr-type>? , <declaration-value>? )

<attr-name> =
[ <ident-token>? '|' ]? <ident-token>

<attr-type> =
type( <syntax> ) |
raw-string |
number |
<attr-unit>

<syntax> =
'*' |
<syntax-component> [ <syntax-combinator> <syntax-component> ]* |
<syntax-string>

<syntax-component> =
<syntax-single-component> <syntax-multiplier>? |
'<' transform-list '>'

<syntax-combinator> =
'|'

<syntax-string> =
<string>

<syntax-single-component> =
'<' <syntax-type-name> '>' |
<ident>

<syntax-multiplier> =
'#' |
'+'

<syntax-type-name> =
angle |
color |
custom-ident |
image |
integer |
length |
length-percentage |
number |
percentage |
resolution |
string |
time |
url |
transform-function

示例

content 屬性

在此示例中,我們將 data-foo data-* 全域性屬性的值新增到 <p> 元素內容的開頭。

HTML

html
<p data-foo="hello">world</p>

CSS

css
[data-foo]::before {
  content: attr(data-foo) " ";
}

結果

使用回退值

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

在此示例中,我們將 data-browser data-* 全域性屬性的值附加到 <p> 元素。如果 <p> 元素缺少 data-browser 屬性,我們將附加回退值“Unknown”。

HTML

html
<p data-browser="Firefox">My favorite browser is:</p>
<p>Your favorite browser is:</p>

CSS

css
p::after {
  content: " " attr(data-browser, "Unknown");
  color: tomato;
}

結果

color 值

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

在此示例中,我們將 background-color 的 CSS 值設定為分配給 <div> 元素的 data-background data-* 全域性屬性的值。

HTML

html
<div class="background" data-background="lime">
  background expected to be red if your browser does not support advanced usage
  of attr()
</div>

CSS

css
.background {
  background-color: red;
}

.background[data-background] {
  background-color: attr(data-background type(<color>), red);
}

結果

使用維度單位

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

在此示例中,data-rotation 屬性被解析為一個 deg 單位,用於指定元素的旋轉角度。

HTML

html
<div data-rotation="-3">I am rotated by -3 degrees</div>
<div data-rotation="2">And I by 2 degrees</div>
<div>And so am I, using the fallback value of 1.5deg</div>

CSS

css
div {
  width: fit-content;
  transform-origin: 50% 50%;
  rotate: attr(data-rotation deg, 1.5deg);
}

結果

attr() 值解析為 <custom-ident>

實驗性: 這是一項實驗性技術
在生產中使用此技術之前,請仔細檢查瀏覽器相容性表格

在此示例中,view-transition-name 屬性的值來自元素的 id 屬性。該屬性被解析為 <custom-ident>,這正是 view-transition-name 接受的值型別。

view-transition-name 的結果值是 card-1card-2card-3 等。

HTML

HTML 包含四張具有不同 id 屬性的卡片和一個“Shuffle cards”(洗牌)的 <button>,用於打亂卡片順序。

html
<div class="cards">
  <div class="card" id="card-1">1</div>
  <div class="card" id="card-2">2</div>
  <div class="card" id="card-3">3</div>
  <div class="card" id="card-4">4</div>
</div>
<button>Shuffle cards</button>

CSS

卡片在 flex 容器中佈局:

css
.cards {
  display: flex;
  flex-direction: row;
  gap: 1em;
  padding: 1em;
}

在每張卡片上,attr() 函式獲取 id 屬性並將其解析為 <custom-ident>,用作 view-transition-name 屬性的值。如果卡片上未設定 id,則使用回退值 none

css
.card {
  view-transition-name: attr(id type(<custom-ident>), none);
  view-transition-class: card;
}

JavaScript

當按下 <button> 時,卡片會被打亂。這是透過隨機化一個包含所有卡片引用的陣列的順序,然後更新每張卡片的 order 屬性為其新的陣列索引位置來實現的。

為了讓每張卡片動畫到其新位置,我們使用了檢視過渡(View Transitions)。這是透過將 order 的更新包裝在對 document.startViewTransition 的呼叫中完成的。

js
const shuffle = (array) => {
  for (let i = array.length - 1; i >= 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [array[i], array[j]] = [array[j], array[i]];
  }
};

document.querySelector("button").addEventListener("click", (e) => {
  const $cards = Array.from(document.querySelectorAll(".card"));
  shuffle($cards);
  document.startViewTransition(() => {
    $cards.forEach(($card, i) => {
      $card.style.setProperty("order", i);
    });
  });
});

結果

規範

規範
CSS 值和單位模組 Level 5
# attr-notation

瀏覽器相容性

另見