Calculating Discounted Prices with Pure CSS: A Modern Approach

By

Introduction

CSS has evolved far beyond simply styling elements. With modern mathematical functions and powerful selectors, you can now perform real-time calculations directly in the stylesheet — no JavaScript required. One practical application is calculating and displaying discounted prices on e-commerce or subscription pages. This article walks you through a pure CSS solution that computes the sale price based on a base price and discount percentage, using only HTML and CSS.

Calculating Discounted Prices with Pure CSS: A Modern Approach
Source: css-tricks.com

Why Use CSS for Price Calculations?

Traditionally, dynamic price updates rely on JavaScript to fetch values and manipulate the DOM. But CSS can handle arithmetic operations via the calc() function, read custom data attributes with attr(), and conditionally apply styles using the :has() selector. This approach reduces client-side scripting, eliminates latency, and conserves browser resources. While some features are still gaining browser support, this technique showcases the direction of modern CSS and is a valuable exercise for future-ready web development.

Example Overview: Streaming Service Subscription

Imagine a pricing interface for streaming services — Netflix, Disney+, HBO, etc. Each service has a base monthly price and a student discount (e.g., 20% off). A checkbox toggles the discount, and the CSS automatically strikes through the original price and reveals the discounted price. Everything is driven by data-* attributes and CSS math.

The Markup

Each subscription item is a list element containing a label with the service name, a price element storing the base price and discount as data-price and data-discount, and checkboxes for selection and discount toggle.

<li class="ott">
  <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 (20%)</span>
    <input type="checkbox" class="is-ott-discounted">
  </label>
</li>

The data-price holds the original numeric price, and data-discount stores the discount as a decimal (e.g., 0.2 for 20% off). The original text inside the element is for fallback display before any calculation.

Striking the Original Price

When the student discount checkbox is checked, the original price should be crossed out. The CSS uses the :has() selector to detect the checked state and apply text-decoration: line-through to the .ott-price element.

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

This works because :has() allows styling a parent based on the state of a descendant. In this case, the parent .ott is targeted when it contains a checked discount toggle.

Calculating the Discounted Price

Now we need to display the new price next to (or after) the struck-through original. We can use a pseudo-element such as ::after to show the calculated value. The CSS calc() function performs the arithmetic, while attr() retrieves the numeric values from the data-* attributes.

Calculating Discounted Prices with Pure CSS: A Modern Approach
Source: css-tricks.com
.ott:has(.is-ott-discounted:checked) {
  .ott-price::after {
    content: "$" calc(attr(data-price number) * (1 - attr(data-discount number)));
    margin-left: 0.5em;
    color: green;
    font-weight: bold;
  }
}

Note: The attr() function with a type (e.g., number) is part of the CSS Values and Units Module Level 5, which is still in draft and lacks widespread browser support. However, when fully supported, this will enable seamless numeric extraction. For now, you might need a fallback or a JavaScript polyfill, but the concept remains valid.

Styling the Output

Once the discounted price appears, you can enhance it with visual cues. For example, add a green color to denote savings, or a larger font size to emphasize the deal. You can also conditionally show the discount percentage as a badge using the same attr() approach.

.ott:has(.is-ott-discounted:checked) {
  .ott-price::before {
    content: attr(data-discount) "% off ";
    color: #c00;
  }
}

Limitations and Browser Support

The technique relies on cutting-edge CSS features. As of now, attr() with units or numbers is not supported in any major browser. The :has() selector is available in recent versions of Chrome and Safari but not yet in Firefox (without a flag). Therefore, for production use, you would likely fall back to JavaScript or use this approach as progressive enhancement. Nevertheless, experimenting with these features keeps you ahead of the curve and prepares you for when they become universal.

Conclusion

CSS today is a powerful tool capable of more than just styling — it can perform real-world calculations and conditional displays. By combining :has(), calc(), and attr(), you can create a self-contained price discount system without a single line of JavaScript. While browser support is still growing, this pattern illustrates the potential of CSS as a fully‑fledged logic layer. Start experimenting now to be ready for tomorrow's web standards.

Internal Links

Tags:

Related Articles

Recommended

Discover More

10 Ways Agentic Development is Reshaping Software Engineering: Insights from Spotify & AnthropicBeyond the Gym: Creatine’s Unexpected Benefits for Brain and BodyAndroid April 2026 System Updates: Key Enhancements and Developer HighlightsHow to Control Playback Speed on Spotify for Podcasts and Prepare for MusicHDMI 2.1 FRL Preparation: What the Latest AMDGPU Driver Pull Request Means for Linux 7.2