Starexe
📖 Tutorial

How to Calculate and Display Sale Prices with Pure CSS

Last updated: 2026-05-19 09:31:51 Intermediate
Complete guide
Follow along with this comprehensive guide

Introduction

CSS is often thought of as a styling language for colors, layouts, and animations. But modern CSS has evolved into a powerful tool for numeric computation as well. You can perform calculations directly in stylesheets, using attributes from your HTML to derive meaningful values. For example, you can calculate and display the discounted price of a product without any JavaScript—just clean, declarative CSS.

How to Calculate and Display Sale Prices with Pure CSS
Source: css-tricks.com

This approach offers instant updates, zero latency, and no additional browser resource consumption. It’s perfect for e-commerce listings, subscription plans, or any situation where you need to show a price reduction dynamically. In this article, we’ll walk through a real-world example: a list of streaming services where applying a student discount automatically slashes the original price and displays the new sale price—all with CSS.

Setting Up the HTML Structure

The foundation of this technique lies in using custom data attributes to store the base price and the discount percentage. Each service item in our list contains a div that holds both the visual price and these hidden values.

Data Attributes for Pricing and Discounts

In the markup below, notice the data-price and data-discount attributes on the .ott-price element. These provide the raw numbers that CSS will later manipulate:

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

The discount toggle (.is-ott-discounted) acts as a switch. When checked, CSS will use the :has() selector to target the parent container and apply discount logic to the price element.

Applying the Discount with CSS Selectors

Once the user checks the “Apply Student Discount” checkbox, we want to visually indicate that the original price is no longer valid. A common pattern is to strike through the base price.

Styling the Original Price

Using the :has() pseudo-class, we can detect when the discounted checkbox is checked anywhere inside the .ott container:

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

This simple rule adds a line through the price element, signaling that the discounted price is now active. No JavaScript needed to toggle a class; the checkbox state is directly reflected in the styles.

Computing the Discounted Price

Now for the main event: calculating the sale price using calc() and the attr() function. While attr() has traditionally been limited to the content property, recent browser support allows it to return numeric values for use in calc()—perfect for our discount scenario.

The calc() Function in Action

Inside the same :has() block, we define a custom property --n that evaluates the new price:

How to Calculate and Display Sale Prices with Pure CSS
Source: css-tricks.com
.ott:has(.is-ott-discounted:checked) {
  .ott-price {
    text-decoration: line-through;
    --n: calc(attr(data-price number) * (1 - attr(data-discount number)));
  }
}

Here, attr(data-price number) retrieves the base price (e.g., 7.99) as a number, and attr(data-discount number) gets the discount factor (e.g., 0.2 for 20%). The calculation price * (1 - discount) yields the discounted amount—6.392 in this case. This value is stored in the --n custom property.

To display this new price, you can use a ::after pseudo-element on the same .ott-price or on a separate element. For instance:

.ott-price::after {
  content: attr(data-price);
}

.ott:has(.is-ott-discounted:checked) .ott-price::after {
  content: "$" counter(var(--n));  /* Simplified; real usage needs rounding */
}

In practice, you might combine it with the counter-reset trick to format the number with two decimal places. The key takeaway is that the math happens entirely in CSS.

Browser Support and Future Potential

As of early 2025, the attr() function with numeric type and the :has() selector are still bleeding-edge features. Browser support is improving (Chrome, Edge, and Safari have made progress), but this technique is best used for progressive enhancement or experimental projects today. However, the underlying concept—using CSS for dynamic calculations—is solid and will become more practical as browser adoption grows.

Imagine building an entire pricing table where every discount, tax, or subscription tier is computed and displayed without a single line of JavaScript. That future is coming, and experimenting now prepares us for it.

Conclusion

CSS has proven it can handle more than just aesthetics. By combining calc(), attr(), and :has(), you can create responsive, server-free price displays that update instantly with user interaction. Whether you’re showing a student discount, a holiday sale, or a volume pricing tier, this pure-CSS approach keeps your pages lightweight and fast.

Start experimenting with your own data-driven styles—you might be surprised how much math CSS can do for you.