Fizz Buzz in CSS - Susam Pal

3 min read Original article ↗

By Susam Pal on 06 Dec 2025

How many CSS selectors and declarations do we need to produce the Fizz Buzz sequence? Of course we could do this with no CSS at all simply by placing the entire sequence as text in the HTML body. So to make the problem precise as well as to keep it interesting, we require that all text that appears in the Fizz Buzz sequence comes directly from the CSS. Placing any part of the output numbers or words outside the stylesheet is not allowed. JavaScript is not allowed either. With these constraints, I think we need at least four CSS selectors along with four declarations to solve this puzzle, as shown below:

li { counter-increment: n }
li:not(:nth-child(5n))::before { content: counter(n) }
li:nth-child(3n)::before { content: "Fizz" }
li:nth-child(5n)::after { content: "Buzz" }

Here is a complete working example: css-fizz-buzz.html.

The above solution contains four CSS rules with one selector and one declaration in each rule. For example, li { counter-increment: n } is one rule consisting of the selector li and the declaration counter-increment: n.

Seasoned code golfers looking for a challenge can probably shrink this solution further. A common trick to solve this problem is to use an ordered list (<ol>) which provides the integers in the form of list markers automatically, thereby eliminating the need to maintain a counter in the stylesheet. However, this violates the requirement set out in the introduction. We want every integer to be produced directly by the stylesheet. Treating the integers in the list markers as part of the output sequence breaks this rule. Not to mention the output looks untidy because of the unnecessary dot after each marker and also because the numbers and words appear misaligned. See an example of that trick here: css-fizz-buzz-ol.html. Correcting the misaligned output calls for extra code that cancels out the number of declarations saved. In any case, the requirement that all integers of the output must come directly from the stylesheet prevents untidy solutions like this and also forces us to rely on the capabilities of CSS to solve this puzzle.

The intention here was to obtain the smallest possible code in terms of the number of CSS declarations. This example is not crafted to minimise bytes, but for code golfers who enjoy reducing byte count, here is the number of bytes this solution consumes after removing all whitespace:

$ curl -sS https://susam.net/css-fizz-buzz.html | sed -n '/counter/,/after/p' | tr -d '[:space:]' | wc -c
152

Further reduction in byte count can be achieved by using the <p> element instead of <li>, nesting CSS selectors, etc. I'll leave that as an exercise for the reader. Returning to the focus of this post as well as to summarise it, the solution here uses four CSS rules consisting of four selectors and four declarations to render the Fizz Buzz sequence.