Dynamic Price Calculations in CSS: No JavaScript Required
Introduction
CSS has evolved far beyond simple styling. With modern math functions and attribute selectors, you can perform numeric calculations directly in the browser, eliminating the need for JavaScript in many common scenarios. For example, you can calculate and display a discounted product price using only CSS — a task traditionally handled by scripts. This approach reduces page weight, improves performance, and simplifies the frontend stack.

Demo Overview: Streaming Subscription Discounts
Consider an interface showing several streaming services (Netflix, Disney+, HBO, etc.), each with a base price and an optional student discount of 20%. The user can toggle the discount for each service, and the price updates instantly — all without a single line of JavaScript. The demo relies on data-* attributes to store the original price and discount percentage, and CSS calc() with attr() to compute the final price.
Markup Structure
Each service is a list item containing a label for the service name and price, a checkbox to select the service, and another label for the discount toggle. The price element holds the base price and discount as data-price and data-discount attributes. Here’s a simplified example:
<li class="service">
<label>
<span>Netflix</span>
<div class="price" data-price="7.99" data-discount="0.2">$7.99</div>
<input type="checkbox" class="select-service">
</label>
<label>
<span>Apply Student Discount (20%)</span>
<input type="checkbox" class="apply-discount">
</label>
</li>
The discount toggle (.apply-discount) triggers the CSS that recalculates and displays the new price.
Performing the Calculation in CSS
When the discount checkbox is checked, we first strike through the original price using text-decoration: line-through. Then we compute the discounted price with the attr() function. As of now, attr() works only with content property, but future CSS will expand it to other properties. The formula is:
Discounted Price = data-price × (1 - data-discount)
Because attr() returns a string, we use calc() with attr() inside a --custom-property. The actual implementation requires a workaround until browsers fully support attr() in calc(). The demo uses a @property custom property to perform the math:
/* When discount is active */
.service:has(.apply-discount:checked) .price {
text-decoration: line-through;
--discounted-value: calc(attr(data-price number) * (1 - attr(data-discount number)));
content: "$" var(--discounted-value);
}
Note: The number type hint in attr() is part of the newer spec and not yet universally supported, so the demo uses a polyfill or alternative approach with @property and CSS custom properties.

Styling the Discounted Price
Once the discount is applied, we can style the new price separately using ::after or content. The original price remains visible but crossed out. Additional CSS can add a “Save X%” label by subtracting the discounted price from the original and formatting the difference. The demo uses a pseudo-element to insert “You save” messaging.
Considerations for Real-World Use
This technique showcases the power of modern CSS, but it relies on features that are still experimental or have limited browser support. As of 2025, attr() in calc() is not widely supported, and @property may not be present in all browsers. For production, you’d likely still use JavaScript for such calculations, but the CSS-only approach is an excellent benchmark for how the platform is evolving.
- Performance benefits: No script execution, no reflow beyond what CSS already manages.
- Accessibility: Ensure screen readers can interpret dynamic content changes (use
roleandaria-liveregions if needed). - Fallback: Provide a static price with JavaScript enhancement layered on top.
Conclusion
CSS math is no longer limited to layout — it can compute real-world values like discounted prices. While full browser support is still maturing, experimenting with these techniques today prepares developers for a future where style and logic merge seamlessly. The streaming-service demo is just one example; similar approaches can handle progress bars, score counters, or any numeric display driven by data attributes.
To explore the full code and see it in action, check out the CodePen embed in the original article.
Related Articles
- 5 Critical Things You Must Know About Google's Forced AI in Chrome
- New Chrome Feature Lets Developers Dramatically Speed Up JavaScript Startup
- CSS `corner-shape`: A New Way to Style Corners Beyond Rounded Edges
- How Microsoft Copilot Studio Accelerates with .NET 10 and WebAssembly
- Exploring CSS Color Palettes: A Curated Collection for Vanilla CSS Developers
- Why the Subaru Impreza Is a Smarter Buy Than a New Honda Civic
- Meta Drops 'Instants': Ephemeral Photos Arrive on Instagram, Challenge Snapchat
- How GitHub Turbocharged Performance for Large Pull Requests