CSSのcalc()とattr()で割引価格を計算する作例とプロンプト

割引価格をCSSで完結させる思考法
ECサイトの開発で頻出する「定価から割引後の価格を計算して表示する」処理。通常はサーバーサイドで計算するか、JavaScriptでリアルタイムに算出する。ところがCSS-Tricksの最新記事では、CSSのcalc()とattr()を組み合わせることで、この計算をスタイルシートだけで完結させる手法が紹介されている。開発者にとっての本質は「表示目的の計算をCSSに委譲すれば、DOMはデータの保持に集中できる」という点にある。
データ属性とcalc()の連携
まずHTML側でdata-original-priceとdata-discount-percentのようなカスタムデータ属性を仕込む。ここに数値を文字列として格納しておく。CSS側ではattr()関数でこれらの値を取得し、calc()で計算する。ただしattr()の戻り値はデフォルトで文字列型。数値計算にはtype()構文を用いて明示的に数値として扱う必要がある。最近のBaseline対応状況では、attr()の数値型サポートはまだ限定的だが、2026年4月時点のChrome 124以降で動作確認が取れている。
/* 例:定価10000円、30%オフを計算 */
.product__price::after {
content: calc(
attr(data-original-price number) *
(100 - attr(data-discount-percent number)) / 100
) "円";
}
視覚的表現の工夫
計算結果の表示だけでは物足りない。割引前の価格に打消し線を引き、割引率を目立たせるのが定番パターン。疑似要素を使えば2行のテキストを生成できる。::beforeに元の価格を表示しtext-decoration: line-throughを適用。::afterに計算後の価格を出力する。さらにdata-discount-percentの値をcounter()と組み合わせれば、-30%のようなラベルもCSSだけで添えられる。JavaScriptやサーバーサイドの値を一切変更せずに、割引バッジの有無やスタイルを切り替えられるのは大きな利点だ。
実装上の落とし穴と対策
注意すべき点は3つ。1つ目はattr()の数値型がまだブラウザ間で実装に差があること。Safari 17.4以降では動作するが、Firefoxは未対応。代替としてCSSカスタムプロパティを用いたスマートなフォールバックを用意するのが現実的だ。--original-price: 10000; --discount-percent: 30;をインラインスタイルで埋め込み、calc()で直接計算する。2つ目は表示価格の丸め処理。割引率によっては小数点が発生する。round()関数はまだ実験的段階なので、現段階ではbottomやnearestの指定ができない。切り捨て表示が必要ならJavaScriptで前処理した値をCSSに渡す方が安全。3つ目はアクセシビリティ。計算結果をcontentプロパティで出力すると支援技術が読み上げないケースがある。aria-labelで計算後の価格を明示する必要がある。
この手法がもたらす開発フローの変化
CSSで価格計算を完結させる真価は、フロントエンドとバックエンドの責務分離にある。バックエンドは「割引率」というルールだけをデータ属性として渡し、表示ロジックをCSSに委ねられる。デザイナーが割引表示のスタイルを変更しても、テンプレートエンジンやAPIの修正は不要。コンポーネント単位でdata-*属性さえ正しく出力できれば、その後の視覚的加工はすべてCSSの仕事になる。
さらにCSS-Tricksの記事では、この手法を発展させて複数割引の積み上げ計算や税込み価格への応用も示唆している。ただし税計算には端数処理問題が絡むため、現時点ではCSS単体で完璧に扱うのは難しい。代わりに--tax-rate: 1.1のようなカスタムプロパティを別途定義し、calc()で乗算する方法が提案されている。実用化にはもう一段階のブラウザサポートの進展が必要だが、将来のWeb標準がCSSに「本来サーバーの仕事」を少しずつ委譲している流れは感じられる。
