{"id":9617,"date":"2026-05-12T11:23:42","date_gmt":"2026-05-12T16:23:42","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=9617"},"modified":"2026-05-12T11:23:44","modified_gmt":"2026-05-12T16:23:44","slug":"repeating-square-dots-backgrounds-in-css","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/repeating-square-dots-backgrounds-in-css\/","title":{"rendered":"Repeating Square Dots Backgrounds in CSS"},"content":{"rendered":"\n<p>I saw this reasonable ask for help the other day.<\/p>\n\n\n\n<blockquote class=\"mastodon-embed\" data-embed-url=\"https:\/\/mastodon.social\/@pawelgrzybek\/116510590035197395\/embed\" style=\"background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0 0 2rem 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;\"> <a href=\"https:\/\/mastodon.social\/@pawelgrzybek\/116510590035197395\" target=\"_blank\" style=\"align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;\"> <svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\" width=\"32\" height=\"32\" viewBox=\"0 0 79 75\"><path d=\"M63 45.3v-20c0-4.1-1-7.3-3.2-9.7-2.1-2.4-5-3.7-8.5-3.7-4.1 0-7.2 1.6-9.3 4.7l-2 3.3-2-3.3c-2-3.1-5.1-4.7-9.2-4.7-3.5 0-6.4 1.3-8.6 3.7-2.1 2.4-3.1 5.6-3.1 9.7v20h8V25.9c0-4.1 1.7-6.2 5.2-6.2 3.8 0 5.8 2.5 5.8 7.4V37.7H44V27.1c0-4.9 1.9-7.4 5.8-7.4 3.5 0 5.2 2.1 5.2 6.2V45.3h8ZM74.7 16.6c.6 6 .1 15.7.1 17.3 0 .5-.1 4.8-.1 5.3-.7 11.5-8 16-15.6 17.5-.1 0-.2 0-.3 0-4.9 1-10 1.2-14.9 1.4-1.2 0-2.4 0-3.6 0-4.8 0-9.7-.6-14.4-1.7-.1 0-.1 0-.1 0s-.1 0-.1 0 0 .1 0 .1 0 0 0 0c.1 1.6.4 3.1 1 4.5.6 1.7 2.9 5.7 11.4 5.7 5 0 9.9-.6 14.8-1.7 0 0 0 0 0 0 .1 0 .1 0 .1 0 0 .1 0 .1 0 .1.1 0 .1 0 .1.1v5.6s0 .1-.1.1c0 0 0 0 0 .1-1.6 1.1-3.7 1.7-5.6 2.3-.8.3-1.6.5-2.4.7-7.5 1.7-15.4 1.3-22.7-1.2-6.8-2.4-13.8-8.2-15.5-15.2-.9-3.8-1.6-7.6-1.9-11.5-.6-5.8-.6-11.7-.8-17.5C3.9 24.5 4 20 4.9 16 6.7 7.9 14.1 2.2 22.3 1c1.4-.2 4.1-1 16.5-1h.1C51.4 0 56.7.8 58.1 1c8.4 1.2 15.5 7.5 16.6 15.6Z\" fill=\"currentColor\"\/><\/svg> <div style=\"color: #787588; margin-top: 16px;\">Post by @pawelgrzybek@mastodon.social<\/div> <div style=\"font-weight: 500;\">View on Mastodon<\/div> <\/a> <\/blockquote> <script data-allowed-prefixes=\"https:\/\/mastodon.social\/\" async src=\"https:\/\/mastodon.social\/embed.js\"><\/script>\n\n\n\n<p><span style=\"box-sizing: border-box; margin: 0px; padding: 0px;\">Note that the example above has little\u00a0<em>circular<\/em>\u00a0dots, and what Pawe\u0142 is asking about are little\u00a0<em>square<\/em>\u00a0dots.<\/span> This is the example look from atproto.com:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"361\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-12-at-7.58.48-AM.png?resize=1024%2C361&#038;ssl=1\" alt=\"\" class=\"wp-image-9624\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-12-at-7.58.48-AM.png?resize=1024%2C361&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-12-at-7.58.48-AM.png?resize=300%2C106&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-12-at-7.58.48-AM.png?resize=768%2C271&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-12-at-7.58.48-AM.png?resize=1536%2C541&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/Screenshot-2026-05-12-at-7.58.48-AM.png?resize=2048%2C722&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Repeating a Small Area<\/h2>\n\n\n\n<p>My first thought is we&#8217;re obviously not drawing all these dots in one big graphic. We&#8217;re drawing one, leaving empty space, and using our ol&#8217; pal <code>background-repeat: repeat;<\/code><\/p>\n\n\n\n<p>In order for the repeating to work, we need to define a smaller space via <code>background-size<\/code>. So let&#8217;s say it&#8217;s&#8230;<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">html<\/span> {\n  <span class=\"hljs-attribute\">background-size<\/span>: <span class=\"hljs-number\">100px<\/span> <span class=\"hljs-number\">100px<\/span>;\n  <span class=\"hljs-attribute\">background-repeat<\/span>: repeat;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now we&#8217;ve got a 100px square that will repeat over the entire background. We just need to fill that 100px square with a <em>smaller<\/em> square that repeats. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"614\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/repeating-dots.png?resize=1024%2C614&#038;ssl=1\" alt=\"\" class=\"wp-image-9622\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/repeating-dots.png?resize=1024%2C614&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/repeating-dots.png?resize=300%2C180&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/repeating-dots.png?resize=768%2C461&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/repeating-dots.png?resize=1536%2C922&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/repeating-dots.png?w=2000&amp;ssl=1 2000w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Drawing the Square Dot<\/h2>\n\n\n\n<p>Again my first thought was that we could make it <em>look<\/em> like we&#8217;re drawing a small square dot by actually letting a <code>background-color<\/code> show through and covering up everywhere else. So like a three-layer system: <\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/layers.png?resize=1024%2C512&#038;ssl=1\" alt=\"\" class=\"wp-image-9623\" style=\"width:602px;height:auto\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/layers.png?resize=1024%2C512&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/layers.png?resize=300%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/layers.png?resize=768%2C384&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/layers.png?resize=1536%2C768&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/layers.png?w=1613&amp;ssl=1 1613w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n<\/div>\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">html<\/span> {\n  <span class=\"hljs-attribute\">background<\/span>: \n    <span class=\"hljs-built_in\">linear-gradient<\/span>(to bottom, transparent <span class=\"hljs-number\">10px<\/span>, white <span class=\"hljs-number\">10px<\/span>),\n    <span class=\"hljs-built_in\">linear-gradient<\/span>(to right, transparent <span class=\"hljs-number\">10px<\/span>, white <span class=\"hljs-number\">10px<\/span>),\n    black;\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>If we flatten out that visual, you can see the three shapes smoosh down into a small square, which we then repeat.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"512\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/square.png?resize=1024%2C512&#038;ssl=1\" alt=\"\" class=\"wp-image-9625\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/square.png?resize=1024%2C512&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/square.png?resize=300%2C150&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/square.png?resize=768%2C384&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/square.png?resize=1536%2C768&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/square.png?w=1613&amp;ssl=1 1613w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>That&#8217;s what&#8217;s going on here exactly:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_019e0546-e9bf-7593-85ff-795f9e678a77\" src=\"\/\/codepen.io\/editor\/anon\/embed\/019e0546-e9bf-7593-85ff-795f9e678a77?height=450&amp;theme-id=1&amp;slug-hash=019e0546-e9bf-7593-85ff-795f9e678a77&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 019e0546-e9bf-7593-85ff-795f9e678a77\" title=\"CodePen Embed 019e0546-e9bf-7593-85ff-795f9e678a77\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Uh Oh \u2014 Transparency?<\/h2>\n\n\n\n<p>The problem with the above is that we need a solid color to be the &#8220;mask&#8221; that covers all the area except the mask. This means we can&#8217;t have, for example, one big image behind the dots or a gradient or anything (without more exotic trickery). The problem is we don&#8217;t have proper transparency. <\/p>\n\n\n\n<p>What we want to be doing is drawing the dot with one &#8220;gradient&#8221;, if we can, and leaving the rest of the area empty\/transparent.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Enter Conic Gradients<\/h2>\n\n\n\n<p>I didn&#8217;t think of this! <a href=\"https:\/\/mastodon.social\/@Meyerweb\/116510694762069077\">Eric Meyer had the clever idea.<\/a> The idea is that you can use <code>conic-gradient<\/code> to describe what we want in one go. &#8220;Hard stop&#8221; color stops are in use here, the classic trick to make a gradient just bands of solid color, not actually gradients. But in this case, three-quarters of the area is transparent, and the last bit is the dot color.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">html<\/span> {\n  <span class=\"hljs-attribute\">background-image<\/span>: \n    <span class=\"hljs-built_in\">conic-gradient<\/span>(\n      from <span class=\"hljs-number\">0deg<\/span> at <span class=\"hljs-number\">5px<\/span> <span class=\"hljs-number\">5px<\/span>, \n      transparent <span class=\"hljs-number\">75%<\/span>, black <span class=\"hljs-number\">75%<\/span> <span class=\"hljs-number\">100%<\/span>\n    );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This took me a sec to understand, but it&#8217;s essentially setting the center of the conic gradient at a specific spot, then forcing most of the way around to be transparent and leaving the last bit as the dot.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"510\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/CleanShot-2026-05-12-at-09.12.40%402x.png?resize=1024%2C510&#038;ssl=1\" alt=\"\" class=\"wp-image-9628\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/CleanShot-2026-05-12-at-09.12.40%402x.png?resize=1024%2C510&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/CleanShot-2026-05-12-at-09.12.40%402x.png?resize=300%2C149&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/CleanShot-2026-05-12-at-09.12.40%402x.png?resize=768%2C383&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/CleanShot-2026-05-12-at-09.12.40%402x.png?w=1383&amp;ssl=1 1383w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>Then we use the same concept as before where we set a smaller <code>background-size<\/code> and let it naturally repeat, and we&#8217;ve got square dots with a transparent background! <\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_019e1cdc-4cbb-71ae-9a94-be2e0102a3b5\" src=\"\/\/codepen.io\/editor\/anon\/embed\/019e1cdc-4cbb-71ae-9a94-be2e0102a3b5?height=450&amp;theme-id=1&amp;slug-hash=019e1cdc-4cbb-71ae-9a94-be2e0102a3b5&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 019e1cdc-4cbb-71ae-9a94-be2e0102a3b5\" title=\"CodePen Embed 019e1cdc-4cbb-71ae-9a94-be2e0102a3b5\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We look at a couple of ways to essentially draw a little square dot in a slightly larger area and let it repeat, giving us a nice dotted background effect.<\/p>\n","protected":false},"author":1,"featured_media":9630,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[448,192,7,201],"class_list":["post-9617","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-background-image","tag-conic-gradient","tag-css","tag-gradients"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2026\/05\/dot-bg.png?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/9617","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=9617"}],"version-history":[{"count":7,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/9617\/revisions"}],"predecessor-version":[{"id":9631,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/9617\/revisions\/9631"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/9630"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=9617"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=9617"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=9617"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}