How to Compute and Display Discounts Purely in CSS: A Practical Guide

By

Introduction

CSS has evolved far beyond styling layouts and colors. Modern CSS now includes powerful mathematical capabilities that can handle real-world calculations—without relying on JavaScript or server-side logic. One compelling use case is displaying discounted prices on e‑commerce or subscription pages. By leveraging CSS math functions, calc(), custom properties, and the newer :has() selector, you can compute and present sale prices directly from data-* attributes. This approach reduces code complexity, eliminates network latency, and keeps the logic entirely in the browser’s rendering layer.

How to Compute and Display Discounts Purely in CSS: A Practical Guide
Source: css-tricks.com

Setting Up the Markup

The foundation is a clean, semantic HTML structure that stores base price and discount values in data-* attributes. For example, a list of streaming services with student discounts:

<li>
  <label>
    <span>Netflix</span>
    <div class="ott-price" data-price="7.99" data-discount="0.2">$7.99</div>
    <input type="checkbox" class="is-ott-selected">
  </label>
  <label>
    <span>Apply Student Discount <br> 20%</span>
    <input type="checkbox" class="is-ott-discounted">
  </label>
</li>

Here, data-price holds the original price (e.g., $7.99) and data-discount the discount fraction (0.2 = 20%). The checkbox toggles whether the discount is applied. This structure is simple, accessible, and keeps the business data embedded in the markup itself.

Calculating the Discounted Price with CSS

When the discount checkbox is checked, CSS takes over. Using the :has() pseudo‑class, we detect the checked state and then apply calculations via calc() and the attr() function.

Step 1: Strike Through the Original Price

First, visually indicate that the original price is no longer valid:

.ott:has(.is-ott-discounted:checked) {
  .ott-price {
    text-decoration: line-through;
  }
}

Step 2: Compute the New Price

Next, we use attr() to read the data attributes and calc() to calculate the discounted amount. However, attr() currently returns a string; to use it in calculations, we need to convert it to a number. A workaround is to use custom properties with attr() inside a calc() context, though browser support is still evolving. An alternative is to set the values as custom properties in CSS (e.g., using --price: 7.99 and --discount: 0.2) instead of data-* attributes. For the sake of this demonstration, we’ll assume a future where attr() works seamlessly with numeric types.

.ott:has(.is-ott-discounted:checked) {
  .ott-price {
    --n: calc(attr(data-price number) * (1 - attr(data-discount number)));
    content: "$" var(--n);
  }
}

(Note: as of 2025, attr() with numeric type is not widely supported; this code illustrates the concept. For production, consider using CSS custom properties defined directly in the stylesheet.)

Step 3: Display the Discounted Price

To show the new price next to the struck‑through original, you might use a ::after pseudo‑element or a separate element. In the demo, the discounted price appears in a span that is conditionally shown when the checkbox is checked, using the :has() selector to toggle visibility.

How to Compute and Display Discounts Purely in CSS: A Practical Guide
Source: css-tricks.com

Adding Interactivity

CSS alone can manage toggling states, but user interactions like checkboxes (or the :target pseudo‑class) are necessary to trigger the discount. The beauty lies in the fact that no JavaScript is needed to recalculate; the browser recomputes the CSS values automatically when the checkbox state changes. This leads to a responsive, lightweight UI that works even with JavaScript disabled.

Limitations and Browser Support

The approach demonstrated relies on cutting‑edge CSS features:

Because of these gaps, the example is more of a proof of concept than a production‑ready solution. For now, developers typically rely on JavaScript to parse data attributes and update the DOM. However, as browser vendors implement the CSS Values and Units Level 4 specification, we can expect native numeric attr() to become standard.

The Future of CSS Math in E‑commerce

This technique shows that CSS can handle tasks previously reserved for scripts. As support matures, you’ll be able to:

The result is a cleaner, more declarative front‑end that’s easier to maintain and faster to render. While we’re not there yet, experimenting with these methods today prepares us for tomorrow’s CSS.

Conclusion

Using CSS to compute and display discounted prices demonstrates the growing power of the styling layer. By combining semantic markup, custom properties, :has(), and mathematical functions, you can create interactive pricing displays that are both lightweight and resilient. Start experimenting now—because soon, CSS math will be an everyday tool for every web developer.

Related Articles

Recommended

Discover More

Critical Role Campaign 4 Debuts Secret Spell Crafted by Ex-D&D Lead DesignerMastering Neural Theorem Proving: A Step-by-Step Guide to DeepSeek-Prover-V2's Training PipelineUbuntu's New Default Terminal Ptyxis Brings Modern Container Support and Tab OverviewsIntuit Enterprise Suite vs QuickBooks Online: 8 Key Differences You Should KnowYour Complete Step-by-Step Guide to Upgrading to Fedora Workstation 44 and Exploring GNOME 50