Blog

CSS GOLF

What's this about?

I'm a big fan of CSS code golf. The idea is to replicate a given image using only css and html, in as few characters as possible. I play it here. If I score in the top 10, I'll write about it. I'm not good at writing so keep the expectations nice and low.

Here are some general tips:

  • Minify everything
    • whitespace
    • newlines
    • last semicolon
    • last closing bracket
  • Find the shortest possible unit. This means dropping the unit altogether for some properties like margin and padding. Eg: margin: 5; instead of margin: 5px. Use percentage or q value. Some examples:
    • 10px = 11q
    • 20px = 5vw
    • 30px = 32q
    • 40px = 5ch
    • 50px = 54q
    • 80px = 5pc
    • 100px = 25vw
    • 864px = 9in
    There's a fantastic tool built by alexzaworski that can be used to find the shortest possible unit for a given pixel value.
  • Use the shortest possible selector. Eg:
    • html = &
    • body = &>* (although careful with this one if you change the display property of the body)
    • With CSS nesting you can usually get away without classes to select elements by chaining them together with siblings selectors in nested rules, but if you do need a class, rather use a single letter attribute as a selector. For example, instead of this: do this:
    • Not sure how exactly this is used yet but there's a trick where people use this unicode character in combination with some font shorthand to set the font size like this Which can be used to set up the size of an element without using height, width, or padding. Not sure why, but it seems like you can't always copy/ paste this character. Here is the unicode information about this character: "U+00A0 : NO-BREAK SPACE [NBSP]". It seems like the non breaking space character gives the element it is in height. It's not a regular space, which the browser will parse and remove from the DOM if it has no siblings. Often people use this character with a tag. From what I can tell, this is because that heading tag has a default font size of , which gives it extra height.
    • Instead of using the keyword in making a radial gradient, use the shortest length value ( ). This also allows you to drop the last 0 for the last color stop in the gradient.

The blog post format is the target date, and my score on the top 10.

Target (12/08/2025) - tied for 3rd place

Target (12/08/2025) - tied for 3rd place

Solution (175 characters):

Breakdown:

Alright nothing too fancy happening in todays solution. We have 3 elements (html, body, img) all with a white border and a purple background. Html and body elements give us the '0's of this percentage sign, and the img tag takes up the responsibility of the slash. One good trick in this solution is purely using scale to size the img. Since we already need scale to change the size of the border of the img, we can also use it to give it its height. This way we don't need padding or height to set its size.

Here are the styles, unminified:

Target (29/07/2025) - 6th place

Target (29/07/2025) - 6th place

Solution (179 characters):

Honestly I can't believe this actually made top 10. Was not happy with this solution with all px units, decimal places, and high character count.

Breakdown:

Anyway, I'll make this quick because I'm not fond of this solution. Html element makes up the 'arms' (that's what they look like to me at least) with the border property. Same border is applied to body element, but zoom is used to increase the size of the border so that it makes up the 'body' of the target. Finally the p tag takes up the task of becoming the 'head' of the target with a yellow border.

Here are the styles, unminified:

Target (24/07/2025) - 1st place

Target (24/07/2025) - 1st place

Solution (110 characters):

Breakdown:

Along with the html and body elements, this solution uses 1 paragraph element. The universal selector sets the background, padding, and border-radius of all elements to the same value. The only other rules are the one setting the background and margin of the body element, and the zoom on the paragraph.

Background for color, margin for positioning and border radius rules are obvious enough. What I find interesting about this solution is the padding and zoom. The padding property solves two purposes here:

  1. Gives the paragraph some height
  2. Gives some space around the paragraph inside the body

This is very handy because usually you can't use margin to position a block element further down due to margin collapsing. There are several ways around this, and padding is one of them.

The other interesting part of this solution is the zoom property. This increases the size, and border radius of the paragraph, which is exactly what we need.

Here are the styles, unminified:

Target (20/07/2025) - 10th place

Target (20/07/2025) - 10th place

Solution (190 characters):

Breakdown:

Along with the html and body elements, this solution uses 2 paragraphs and an image element. When additional elements are needed, I usually reach for the p tag as it is only 1 character long, and has the nice feature of not needing closing tags, because the browser already auto-closes paragraphs to avoid rendering nested paragraphs. I use the img element along with the p tags, because it is (AFAIK) the element with the least characters that still renders as an inline-block.

The background element has the yellow background, the body element and the p tags have the green rounded background, and the img element gives us the 2 round circles using the border-inline rule.

One rule here whose intention may not be clear is the . Reason I added this in is because you can't position a block element (p tag in this case) down on the vertical axis when it's directly inside of a body tag because the margins collapse. Inverting the body element with scale means that we can have that spacing at the 'top'.

Here are the styles, unminified:

Target (16/07/2025) - tied for 9th place

Target (16/07/2025) - tied for 9th place

Solution (132 characters):

Breakdown:

This solution uses the html and body elements. Both share the same styles but the body element has some additional styles to adjust the position of the box shadow (with the --x variable), the size (zoom) and position (margin).

The zoom propery is an interesting new property. It is similar to the scale property (be it as part of a transform or standalone property). One of the notable differences between zoom and scale is that while both scale the element, zoom causes layout shift while scale does not. Also zoom is 4 chars while scale is 5 so it's generally preferred to use zoom if possible in code golf.

Here are the styles, unminified:

Target (15/07/2025) - tied for 4th place

Target (15/07/2025) - tied for 4th place

Solution (111 characters):

Breakdown:

This solution uses only the html element. Only 3 properties were used here. The border block property gives us the top and bottom yellow bars, margin-left pushes the bars over to the right, and a radial gradient is set with the background property.

The background property is worth exploring here. The background shorthand used is equivalent to:

This sets the background image as a radial gradient. The gradient repeats because the background size is less than the total area the element covers. Because only the first value is set for the background position on the x axis, the y value remains on the default 'center'.

Here are the styles, unminified:

Target (23/06/2025) - tied for 2nd place

Target (23/06/2025) - tied for 2nd place

Solution (135 characters):

Breakdown:

This was achieved with the html and body elements only. The green outer area is achieved with a box-shadow on the html element. The red and yellow areas were achieved with a radial gradient on both elements. A border radius is given, then some margin for positioning. Pretty straightforward.

Interestingly, out of the top 10 the only solutions had either 134 or 135 characters. All the solutions had the exact same rules, but the players with 134 chars where a bit more succinct with their selectors.

The use of box-shadow may not be so intuitive this time, but the reason it is used is because the background/ background color property was already in use, and using outline or border instead would have prevented the overlap of the body element from being visible.

Here are the styles, unminified:

Target (20/06/2025) - 4/10

Target (20/06/2025) - 4/10

Solution (103 characters):

Breakdown:

This challenge was done with only 2 properties (box-shadow and color) and 1 element (html). We have 4 shadows on the html element. The first shadow is the orange around the border. The second shadow is the blue on the left side, and the third and fourth create the blue horizontal bar in the middle.

2 tricks in this one:

  • Because there are 2 blue shadows, we use the color property to set the default box shadow color used. That way we don't have to type out the blue hex twice and save a whopping 1 character.
  • Second trick is to not use the color in the target, and rather use a shorter hex version (the 3 character format) to save 3 characters. The color to use in this one was . I took that color to this website which can be used to find the closest 3 character hex for a given color, and it spat out . This rarely works for me, as you can't get the same accuracy of color most of the time, but it's a nice trick to know.

Here are the styles, unminified:

Target (17/06/2025) - 7/10

Target (17/06/2025) - 7/10

Solution (148 characters):

Breakdown:

Another pretty straightforward challenge. We have 4 elements here. HTML element makes up the lighter outer background, body the inner darker background, and the two p tags become the 6 rectangles. I use padding on all elements, which takes the place of height for the p tags, and also prevents the margin collapsing behavior between the body and p tags. Used box-shadow to create the darker rectangles to the left and right of the p tags.

One more trick worth mentioning is the use of the property. I set the color on the p tags, so that I don't need to repeat it for each box shadow.

Here are the styles, unminified:

The only real difference between my solution and the top solution is the method of positioning for the p tags. My method sets the position of the first one, then has a second rule for the second paragraph. Instead of this, the top solution uses some clever margin positioning to circumvent the need for a second rule.

Here's the code in question: The interesting part about this is that the first paragraph (as ordered in the DOM) appears BELOW the second paragraph. I'll be totally honest, I do not understand how this works.

Target (05/06/2025) - 7/10

Target (05/06/2025) - 7/10

Solution (130 characters):

Breakdown:

This was a pretty simple challenge. The idea here was 3 elements with the same dark blue background and a light border. Only a tag is added, giving us 3 elements total. The html element is given a border radius for the rounded part of the image, and other than that there is just margin for positioning and a height given to the tag.

Here are the styles, unminified:

Looking at the top solutions for this challenge, one major difference stands out to me. Take a look here:

There is no height set for the element added to the page. This saves quite a few characters. The use the non breaking space unicode character which gives the element its height.

Target (04/06/2025) - 5/10

Target (04/06/2025) - 5/10

Solution (111 characters):

Breakdown:

No extra markup was added in this challenge, only used the html and body elements that are already on the page. My plan with this challenge was to create 2 circles with the same background. The shortest way I know this can be done is with a radial gradient as a background image. I'll break down each part of the background rule, seeing as it's the only rule other than the margin used for positioning the body element.

Here is the background shorthand rule, broken up into it's parts:

So the first part is the background image where we have a radial gradient, and the first part of that is the . This is the shape of the gradient. Instead of putting , we can save a few characters by using the length value instead. As mentioned on the MDN page linked above:

When the keyword is omitted, the gradient shape is determined by the size given. One value provides a circle, while two values in units provide an ellipse. A single value is not valid.

Next, we have the gradient code, which uses hard stops to give a solid gray circle on a green background. Then we have the position x and y which is self explanatory. The last important part of this is the background size. I've made this larger than the viewport height, to prevent the circle of the background from being repeated. The alternative to achieving this is giving it a background attachment of fixed (more characters), or setting the background size to be smaller than the viewport (which won't work because it cuts of the green background).

Here are the styles, unminified:

Target (31/05/2025) - 6/10

Target (31/05/2025) - 6/10

Solution (134 characters):

Breakdown:

The idea here was to use 4 elements that all have a rectangle on their left and right sides. The shortest way I know of doing this is with border-inline or border-block. So we give every element (html, body, p, and img) the border styles and background as well as a rotatation. Then there is just margin for positioning and padding to set the size of the img tag.

Markup:

Here are the styles, unminified:

Target (30/05/2025) - 6/10

Target (30/05/2025) - 6/10

Solution (214 characters):

Breakdown:

This is the markup we add to the page, which gives us 2 paragraphs with an image in each.

Here are the styles, unminified:

Some of the tricks used in this one:

  • use 11q instead of 10px for the border radius
  • set the color property, so we don't have to repeat it for each box shadow
  • drop the # from the hex code for the color property
  • use 5vw for 20px
  • use 5ch for 40px
  • use 30vw for 120px
  • use 85Q for 80px
  • use inset 0 0 0 1in for the first box shadow instead of declaring a background color