<style> p{counter-increment:n} p:not(:nth-child(5n)):before{content:counter(n)} p:nth-child(3n):before{content:"Fizz"} p:nth-child(5n):after{content:"Buzz"} </style><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p>
<style>p{--n:counter(n);counter-increment:n;&:before{content:var(--n)};&:nth-child(5n){--n:"";&:after{content:"Buzz"}}&:nth-child(3n){--n:"Fizz"</style><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p><p>
data:text/html,<style>:nth-child(3n){list-style:"Fizz"}:nth-child(5n){list-style:"Buzz"}:nth-child(15n){list-style:"FizzBuzz"}</style><ol id=o><script>o.innerHTML='<li>'.repeat(99)</script>
li:nth-child(3n), li:nth-child(5n) { list-style: none }
li:nth-child(3n)::before { content: "Fizz" }
li:nth-child(5n)::after { content: "Buzz" }
Example: https://susam.net/code/web/css-fizz-buzz-ol.html $ curl -sS https://susam.net/code/web/css-fizz-buzz-ol.html | sed -n '/none/,/after/p' | tr -d '[:space:]'
li:nth-child(3n),li:nth-child(5n){list-style:none}li:nth-child(3n)::before{content:"Fizz"}li:nth-child(5n)::after{content:"Buzz"}
$ curl -sS https://susam.net/code/web/css-fizz-buzz-ol.html | sed -n '/none/,/after/p' | tr -d '[:space:]' | wc -c
129
But I don't quite like how misaligned the numbers and the words look in this version. Correcting that would call for extra code that would cancel out the characters saved. list-style-position: inside;I mean, the solution in the original post is 152 characters long.
The <ol> based solution is 129 characters long. Shorter but uglier.
If we add your correction, we get neater output, which is nice, but it comes at the cost of 30 additional characters in the minified code thereby making the solution 159 characters long.
li { list-style-position: inside }
li:nth-child(3n), li:nth-child(5n) { list-style: none }
li:nth-child(3n)::before { content: "Fizz" }
li:nth-child(5n)::after { content: "Buzz" }https://codepen.io/dsmmcken/pen/WbwYOEQ?editors=0100
p{counter-increment:n;--n:counter(n)}p:nth-child(3n){--f:"Fizz"}p:nth-child(5n){--b:"Buzz";--n:''}p::after{content:var(--f,var(--n))var(--b,'')}
Now, arguably it's not a "number or word that appears in the output", that's true, but it is a part of the logic of FizzBuzz. It's the fact that there are 100 and exactly 100 <li> elements in the HTML part.
I mean, it wouldn't be a correct FizzBuzz without precisely that HTML. Having exactly 100 <li> elements is implementing the part of the logic that a. loops, and b. stops at 100.
But of course this is just nitpicking, as I said ;)