{"id":3341,"date":"2026-04-18T20:21:04","date_gmt":"2026-04-18T20:21:04","guid":{"rendered":"https:\/\/erikscode.space\/?p=3341"},"modified":"2026-04-18T20:33:03","modified_gmt":"2026-04-18T20:33:03","slug":"how-to-create-a-sparkly-spoiler-effect-like-the-one-in-threads-mobile-app","status":"publish","type":"post","link":"https:\/\/erikscode.space\/index.php\/2026\/04\/18\/how-to-create-a-sparkly-spoiler-effect-like-the-one-in-threads-mobile-app\/","title":{"rendered":"How to Create a Sparkly-Spoiler Effect like the one in Threads Mobile App"},"content":{"rendered":"\n<p class=\"\">If you use Meta&#8217;s Threads app on a mobile device, you may have noticed an interesting effect: the spoiler tag that hides text behind a sparkly veil. In this article, I will show you how to implement this effect in the browser using HTML, CSS, and JavaScript.<\/p>\n\n\n<a class=\"wp-block-read-more\" href=\"https:\/\/erikscode.space\/index.php\/2026\/04\/18\/how-to-create-a-sparkly-spoiler-effect-like-the-one-in-threads-mobile-app\/\" target=\"_self\">Read more<span class=\"screen-reader-text\">: How to Create a Sparkly-Spoiler Effect like the one in Threads Mobile App<\/span><\/a>\n\n\n<p class=\"\"><strong><em>NOTE:<\/em><\/strong> You can scroll to the bottom of this article to find the completed HTML, CSS, and JavaScript code if you don&#8217;t want to read the whole article.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">The Spoiler Effect on Threads in a Nutshell<\/h1>\n\n\n\n<p class=\"\">If you&#8217;re unfamiliar with the &#8220;spoiler&#8221; tag, it is a Threads feature in which users can selectively hide part of their post until a user is ready to see it. Look at my example below where I am about to post &#8220;Highlight the word &#8220;hello&#8221; to mark as a spoiler!&#8221;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1236\" height=\"562\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-4.png?fit=1024%2C466&amp;ssl=1\" alt=\"\" class=\"wp-image-3347\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-4.png?w=1236&amp;ssl=1 1236w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-4.png?resize=300%2C136&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-4.png?resize=1024%2C466&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-4.png?resize=768%2C349&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">Notice how I have highlighted the word &#8220;hello&#8221; and see a button that says &#8220;Mark spoiler.&#8221; I click that and then post the thread. See how it looks on my desktop browser:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1264\" height=\"240\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.png?fit=1024%2C194&amp;ssl=1\" alt=\"\" class=\"wp-image-3342\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.png?w=1264&amp;ssl=1 1264w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.png?resize=300%2C57&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.png?resize=1024%2C194&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.png?resize=768%2C146&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">The word &#8220;hello&#8221; is now obscured by a gray bar. If someone reading my post wants to see the word I&#8217;ve hidden, they will have to click on the gray bar.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1264\" height=\"240\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-1.png?fit=1024%2C194&amp;ssl=1\" alt=\"\" class=\"wp-image-3343\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-1.png?w=1264&amp;ssl=1 1264w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-1.png?resize=300%2C57&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-1.png?resize=1024%2C194&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-1.png?resize=768%2C146&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">The above screenshot is what a reader will see after clicking the gray bar; they can now see the word that I&#8217;ve hidden.&nbsp;<\/p>\n\n\n\n<p class=\"\">In a nutshell, that is how &#8220;Mark spoiler&#8221; works in Threads; the author selects some text to selectively hide and the user must intentionally perform an action to reveal the hidden text. The intended utility of this feature is for when the user wants to talk about a plot twist or conclusion in a story without giving away\u2013or &#8220;spoiling&#8221;&#8211;the surprise for readers who haven&#8217;t yet gotten to that part. It protects readers from passively reading a spoiler by forcing them to deliberately reveal the hidden text.<\/p>\n\n\n\n<p class=\"\">Note, however, this spoiler bar is a little more fun on the mobile app. The next screenshot shows the same post but from the mobile Threads app:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1284\" height=\"540\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.jpeg?fit=1024%2C431&amp;ssl=1\" alt=\"\" class=\"wp-image-3346\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.jpeg?w=1284&amp;ssl=1 1284w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.jpeg?resize=300%2C126&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.jpeg?resize=1024%2C431&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image.jpeg?resize=768%2C323&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">Notice how instead of a gray bar, it&#8217;s now a sparkling obfuscation. How cool! This sparkly spoiler effect is what this article will teach you how to do.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Actual Spoiler Alert!<\/h1>\n\n\n\n<p class=\"\">I am going to be talking about a plot twist from Star Wars: Episode V &#8211; The Empire Strikes Back. Even though the movie came out in 1980, it&#8217;s possible you haven&#8217;t seen it yet and I would hate to ruin the surprise for you. If you plan on watching this movie and have no clue about its plot, this article is definitely going to spoil it for you!<\/p>\n\n\n\n<p class=\"\">Continue at your own risk!<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">How to Achieve this Effect<\/h1>\n\n\n\n<p class=\"\">First, we will plan out how to implement this effect before getting into the technical details. Here are the things we need to do:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"\">Mark text as spoiler<\/li>\n\n\n\n<li class=\"\">Create the effect<\/li>\n\n\n\n<li class=\"\">Apply that effect to appropriately tagged text<\/li>\n\n\n\n<li class=\"\">Remove the effect when a user clicks<\/li>\n<\/ol>\n\n\n\n<p class=\"\">Let&#8217;s begin!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Mark text as spoiler<\/h2>\n\n\n\n<p class=\"\">First, let&#8217;s create an HTML file called &#8220;spoiler_text.html&#8221; and fill it out with some standard HTML boilerplate code:<\/p>\n\n\n\n<div class=\"wp-block-group has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n<pre class=\"wp-block-code\"><code>&lt;body>\n    &lt;p>\n        The biggest plot twist of all time is:\n        &lt;span class=\"spoiler\">\n            Darth Vader is Luke Skywalker's father!\n        &lt;\/span>\n    &lt;\/p>\n&lt;\/body><\/code><\/pre>\n<\/div>\n\n\n\n<p class=\"\">This is just a basic HTML page in which we&#8217;ve added some text about the biggest plot twist of all time. Right now, the page is pretty bare bones and should look like this in your browser:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1188\" height=\"222\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-2.png?fit=1024%2C191&amp;ssl=1\" alt=\"\" class=\"wp-image-3344\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-2.png?w=1188&amp;ssl=1 1188w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-2.png?resize=300%2C56&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-2.png?resize=1024%2C191&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-2.png?resize=768%2C144&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">Since the background and text in Threads is more of a dark theme, let&#8217;s apply that to our HTML page. This isn&#8217;t part of the spoilers effect, it&#8217;s just something that will make it a little more pleasant to look at later. Let&#8217;s create a CSS file called style.css and make the page a little easier to look at. Here&#8217;s what I came up with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>:root {\n\u00a0\u00a0--bg: #0f1115;\n\u00a0\u00a0--text: #f4f7fb;\n}\n\nbody {\n\u00a0\u00a0min-height: 25vh;\n\u00a0\u00a0display: grid;\n\u00a0\u00a0place-items: center;\n\u00a0\u00a0background: var(--bg);\n\u00a0\u00a0color: var(--text);\n}<\/code><\/pre>\n\n\n\n<p class=\"\">First, I create a <code>:root<\/code> rule to store some CSS variables. As of right now, we only have two variables, <code>bg<\/code> and <code>text<\/code>, so we could just use the values instead of variables in the body rule. However, later in this project we&#8217;re going to have a few more variables and I think it&#8217;s best to keep them all in one place, so we&#8217;ll start putting our variables in the <code>:root<\/code> rule early.<\/p>\n\n\n\n<p class=\"\">Next, I set the <code>min-height<\/code>, display, and <code>place-items<\/code> values for the web page. The specific values I&#8217;ve added in the above CSS will make the text appear in the middle and slightly below the very top of the browser window. Finally, I use the <code>bg<\/code> and <code>text<\/code> variables to set the background and color attributes for the webpage. Now, just below the <code>&lt;title><\/code> tag in the HTML file, I add this line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;link rel=\"stylesheet\" href=\"style.css\" \/><\/code><\/pre>\n\n\n\n<p class=\"\">And now the browser should look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1866\" height=\"552\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-3.png?fit=1024%2C303&amp;ssl=1\" alt=\"\" class=\"wp-image-3345\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-3.png?w=1866&amp;ssl=1 1866w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-3.png?resize=300%2C89&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-3.png?resize=1024%2C303&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-3.png?resize=768%2C227&amp;ssl=1 768w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-3.png?resize=1536%2C454&amp;ssl=1 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">Feel free to adjust the bg and text variables so that the page you&#8217;re looking at is aesthetically pleasing to you.<\/p>\n\n\n\n<p class=\"\">Now, we need to mark the spoiler text somehow. For now, I&#8217;m going to put the spoiler part in a span tag of class &#8220;spoiler.&#8221; Doing so won&#8217;t actually make anything change visually yet, we&#8217;re just preemptively marking the spoiler text before creating the effect. The body tag of the HTML file should now look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;body>\n\u00a0\u00a0\u00a0\u00a0&lt;p>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0The biggest plot twist of all time is:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler\">\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Darth Vader is Luke Skywalker's father!\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/span>\n\u00a0\u00a0\u00a0\u00a0&lt;\/p>\n&lt;\/body><\/code><\/pre>\n\n\n\n<p class=\"\">Now, let&#8217;s create the effect!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Create the Effect<\/h2>\n\n\n\n<p class=\"\">To start creating the effect, we&#8217;ll take a small step by just writing a little CSS to blur out the tagged text. In our style.css file, we&#8217;ll need to make a rule for the spoiler class. We&#8217;ll make use of the built-in CSS <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Reference\/Values\/filter-function\/blur\" title=\"\">blur<\/a> function and make the cursor a pointer. Here&#8217;s how my css for the spoiler class looks:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.spoiler {\n\u00a0\u00a0filter: blur(7px);\n\u00a0\u00a0cursor: pointer;\n\u00a0\u00a0position: relative;\n}<\/code><\/pre>\n\n\n\n<p class=\"\">With this CSS code, we set the <code>filter<\/code> attribute on the <code>spoiler<\/code> class to <code>blur(7px)<\/code> and set the <code>cursor<\/code> attribute to <code>pointer<\/code>. As you might guess from the <code>blur<\/code> function, using it to set a <code>filter<\/code> value makes the element blurry. The number you pass to the function defines the radius of the blur; the higher the number, the larger the blur effect. We set the <code>cursor<\/code> attribute to <code>pointer<\/code> so that when the user hovers their mouse over the effect, the cursor changes to a pointer and lets them know the effect will do something if they click on it.<\/p>\n\n\n\n<p class=\"\">Additionally, we set the <code>position<\/code> attribute to relative so that the span doesn&#8217;t interfere with any of the other elements in the page<\/p>\n\n\n\n<p class=\"\">With the new CSS, the page in the browser should now look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1640\" height=\"386\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-5.png?fit=1024%2C241&amp;ssl=1\" alt=\"\" class=\"wp-image-3348\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-5.png?w=1640&amp;ssl=1 1640w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-5.png?resize=300%2C71&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-5.png?resize=1024%2C241&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-5.png?resize=768%2C181&amp;ssl=1 768w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-5.png?resize=1536%2C362&amp;ssl=1 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">The above screenshot shows that our spoiler text is now blurred out thanks to the <code>filter: blur(7px)<\/code> line in our CSS.<\/p>\n\n\n\n<p class=\"\">Before we can finally build the sparkle animation and the toggle feature, we have to make a few adjustments to the structure of our HTML. We should actually put two more span elements inside of this spoiler span: one to wrap the content, and one to contain the blur effect. This step will make implementing the toggle effect along with the sparkle animation a little easier.&nbsp;<\/p>\n\n\n\n<p class=\"\">I will create one span class called <code>spoiler-content<\/code>, and one called <code>spoiler-blur<\/code>. The <code>spoiler-content<\/code> span will wrap the text, while the <code>spoiler-content<\/code> span won&#8217;t wrap anything, it will just sit inside the spoiler span. Here&#8217;s what the HTMLin the body tag looks like now:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;p>\n\u00a0\u00a0\u00a0\u00a0The biggest plot twist of all time is:\n\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler\" data-hidden=\"true\">\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler-content\">\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Darth Vader is Luke Skywalker's father!\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/span>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler-blur\" \/>\n\u00a0\u00a0\u00a0\u00a0&lt;\/span>\n&lt;\/p><\/code><\/pre>\n\n\n\n<p class=\"\">And the CSS now has to be adjusted as such:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.spoiler {\n\u00a0\u00a0cursor: pointer;\n\u00a0\u00a0position: relative;\n}\n\n.spoiler&#91;data-hidden=\"true\"] .spoiler-content {\n\u00a0\u00a0filter: blur(7px);\n}<\/code><\/pre>\n\n\n\n<p class=\"\">With these updates, I&#8217;m making use of the <code>data-hidden<\/code> attribute by setting it to &#8220;true&#8221; on the spoiler span and then creating a CSS rule that applies the blur to any <code>spoiler-content<\/code> span inside of the <code>spoiler<\/code> span. We will later use this attribute when we create the toggling feature of this effect.<\/p>\n\n\n\n<p class=\"\">Now, we&#8217;re ready to start adding the sparkle effect.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Adding the Sparkle Effect<\/h3>\n\n\n\n<p class=\"\">To add the sparkle effect, we&#8217;re going to make use of two things: <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Reference\/At-rules\/@keyframes\" title=\"\">CSS key frames<\/a> and some JavaScript. The general strategy will be like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"\">Create a CSS <code>spark<\/code> class to make each individual <code>sparkle-blur<\/code> span covering the spoiler text<\/li>\n\n\n\n<li class=\"\">Append several <code>spark<\/code> elements as children to the <code>spoiler-blur<\/code> span with JavaScript\n<ol class=\"wp-block-list\">\n<li class=\"\">We will create a function for generating random numbers<\/li>\n\n\n\n<li class=\"\">We will set a few custom properties on the element with random values (from the random function mentioned above) that will be used in the CSS animations\/keyframes to create the overall &#8220;sparkle effect&#8221;<\/li>\n<\/ol>\n<\/li>\n\n\n\n<li class=\"\">Create a twinkle CSS keyframe that will make the sparks appear to be twinkling<\/li>\n\n\n\n<li class=\"\">Create a drift CSS keyframe that will make the sparks appear to be moving<\/li>\n<\/ol>\n\n\n\n<p class=\"\">First, we&#8217;ll create the <code>spark<\/code> class with just a few of its necessary properties. I defined mine like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.spark {\n\u00a0\u00a0position: absolute;\n\u00a0\u00a0width: 4px;\n\u00a0\u00a0height: 4px;\n\u00a0\u00a0border-radius: 50%;\n\u00a0\u00a0background: var(--spoiler-dot);\n}<\/code><\/pre>\n\n\n\n<p class=\"\">The <code>position: absolute<\/code> line will allow each individual sparkle to take up space in its overlay (the <code>spoiler<\/code> span) without disrupting the position of other elements. The three lines for <code>width<\/code>, <code>height<\/code>, and <code>border-radius<\/code> make the sparkles into perfect circles. If you prefer squares, you can remove the <code>border-radius<\/code> line, if you like vertical lines, you can play with the <code>width<\/code> and <code>height<\/code> properties. The <code>background<\/code> uses a CSS variable that you can set in the <code>:root<\/code> rule, I set mine to a white-ish effect like so: <code>--spoiler-dot: rgba(255,255,255,0.85);<\/code>.<\/p>\n\n\n\n<p class=\"\">This element defines the style for each individual &#8220;sparkle&#8221; in our sparkly-spoiler effect. We&#8217;ll need to make several <code>sparkle<\/code> elements of random sizes and append them to random places on the <code>spoiler-blur<\/code> span element. Create a JavaScript file and call it <code>sparkle.js<\/code> then import it into the HTML&#8217;s body like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;script src=\"sparkle.js\">&lt;\/script><\/code><\/pre>\n\n\n\n<p class=\"\"><strong>NOTE:<\/strong> You must put this line inside the body tag of the HTML, it won&#8217;t work if you put it in the head tag.<\/p>\n\n\n\n<p class=\"\">Now, in <a href=\"http:\/\/sparkle.js\"><code>sparkle.js<\/code><\/a>, we&#8217;ll start by making a convenience function for returning random values, since we&#8217;ll rely on randomness to get the sparkle effect. I wrote my <code>random<\/code> function to take a <code>rscale<\/code> variable and multiply it by a number generated by the <code>Math.random<\/code> function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function random(rscale) {\n\u00a0\u00a0\u00a0\u00a0return Math.random() * rscale;\n}<\/code><\/pre>\n\n\n\n<p class=\"\">Next, we&#8217;ll make a function called <code>buildSparkles<\/code> that takes in a span element, and the number of sparkles we want to create. Each sparkle we create will be created with a starting 2-dimensional coordinate (an x and y representing the left and top properties), an ending 2-dimensional coordinate, a duration of time in which we want the sparkle to move between those two coordinates, a duration of time for which the sparkle should &#8220;twinkle&#8221;, and a scale variable to control size; all of these values will be randomly created for each sparkle.<\/p>\n\n\n\n<p class=\"\">Once each <code>sparkle<\/code> element is built, we&#8217;ll append it to <code>spoiler-blur<\/code> span we passed to the function. Here&#8217;s how I wrote my function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function buildSparkles(spoilerBlurSpan, sparkleCount) {\n\u00a0\u00a0\u00a0\u00a0for (let i = 0; i &lt; sparkleCount; i++) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const s = document.createElement(\"span\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.className = \"spark\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const x0 = random(100);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const y0 = random(100);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const x1 = Math.max(0, Math.min(100, x0 + random(18)));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const y1 = Math.max(0, Math.min(100, y0 + random(14)));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.left = `${x0}%`;\ns.style.top = `${y0}%`;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--x0\", \"0px\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--y0\", \"0px\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--x1\", `${x1 - x0}px`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--y1\", `${y1 - y0}px`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--dur\", `${random(60)}s`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--twinkle\", `${random(1.2)}s`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--scale\", `${random(1.5)}`);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0spoilerBlurSpan.appendChild(s)\n\u00a0\u00a0\u00a0\u00a0}\n}<\/code><\/pre>\n\n\n\n<p class=\"\">In the function signature, we take <code>spoilerBlurSpan<\/code> as the first argument. This will be a span somewhere on the web page that has been marked as containing spoiler text. We also take <code>sparkleCount<\/code>, which is how many sparkles we want to put on one span. Then, we enter the <code>for<\/code> loop.<\/p>\n\n\n\n<p class=\"\">Each iteration of the <code>for<\/code> loop creates one <code>spark<\/code> element. The first two lines create a span element and assign it the class name <code>spark<\/code>.<\/p>\n\n\n\n<p class=\"\">Next, we set <code>x0<\/code>, <code>y0<\/code>, <code>x1<\/code>, and <code>y1<\/code>; these variables are basically two sets of random x, y coordinates. Later, we will create a CSS animation called drift that will make the <code>sparkle<\/code> move between those two coordinates.<\/p>\n\n\n\n<p class=\"\">The lines setting <code>left<\/code> and <code>top<\/code> are putting span elements at the randomly generated x and y coordinates we just generated. The next four <code>setProperty<\/code> lines are assigning the properties and initial values of <code>x0<\/code>, <code>y0<\/code>, <code>x1<\/code>, and <code>y1<\/code> on the <code>sparkle<\/code> span we just created. The need for these properties will become clear in a bit when we create the CSS animations.<\/p>\n\n\n\n<p class=\"\">Finally, we use the last three lines to set properties called <code>dur<\/code>, <code>twinkle<\/code>, and <code>scale<\/code>. We have to set these properties and their initial values to be used by the CSS animation we&#8217;re about to create. The <code>dur<\/code> property is going to be used to control the duration of time a s<code>parkle<\/code> spends moving between its two x,y coordinates. The <code>twinkle<\/code> property is going to control the &#8220;speed&#8221; at which each sparkle twinkles (switches between low and high opacity). Finally, the <code>scale<\/code> property is just going to impact the size of each twinkle.<\/p>\n\n\n\n<p class=\"\">After setting all these properties, we then use the built-in<code>appendChild<\/code> method to add the newly created <code>sparkle<\/code> span to the <code>spoilerBlurSpan<\/code> we got in the function signature.<\/p>\n\n\n\n<p class=\"\">Finally, we end the <code>sparkle.js<\/code> file with a few more lines:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function wireSpoiler(spoilerBlurSpan) {\n\u00a0\u00a0\u00a0\u00a0buildSparkles(spoilerBlurSpan, 75);\n}\n\ndocument.querySelectorAll(\".spoiler-blur\").forEach(wireSpoiler);<\/code><\/pre>\n\n\n\n<p class=\"\">We create one more function called <code>wireSpoiler<\/code> that takes a <code>spoilerBlurSpan<\/code> as an argument so that it can send it to the <code>spoilerBlurSpan<\/code> function along with the number of sparkles to make&#8211;in the above example, 75.<\/p>\n\n\n\n<p class=\"\">Finally, we use <code>querySelectorAll<\/code> to get all spans on the web page of the class <code>spoiler-blur<\/code> and pass it to the <code>wireSpoiler<\/code> method. This ensures that every single <code>spoiler<\/code> span on our page will get the sparkle-effect, even though we only have one spoiler span on our page.<\/p>\n\n\n\n<p class=\"\">Now, we move to the CSS.<\/p>\n\n\n\n<p class=\"\">First, lets create the animations using <code>@keyframes<\/code>. We&#8217;ll create two, <code>drift<\/code> and <code>twinkle<\/code>. Add this CSS to the bottom of your <code>style.css<\/code> file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>@keyframes drift {\n\u00a0\u00a0from {\n\u00a0\u00a0\u00a0\u00a0transform: translate(var(--x0), var(--y0)) scale(var(--scale));\n\u00a0\u00a0}\n\u00a0\u00a0to {\n\u00a0\u00a0\u00a0\u00a0transform: translate(var(--x1), var(--y1)) scale(var(--scale));\n\u00a0\u00a0}\n}\n\n@keyframes twinkle {\n\u00a0\u00a0from { opacity: 0.25; }\n\u00a0\u00a0to \u00a0 { opacity: 0.95; }\n}<\/code><\/pre>\n\n\n\n<p class=\"\">The drift keyframe makes use of the CSS function <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Reference\/Values\/transform-function\/translate\" title=\"\">translate<\/a> which moves an element to a given location. Since this will be used in an animation property later, we give it a <code>from<\/code> and <code>to<\/code> property to define the two positions the element should be moved between. In this case we are using the variables <code>x0<\/code> and <code>y0<\/code> to define the <code>sparkle<\/code>&#8216;s starting point, and <code>x1<\/code> and <code>y1<\/code> as their ending point. Remember, we randomly generated these values in the JavaScript file earlier, so each <code>spark<\/code> we attach to the <code>spoiler-blur<\/code> element will have its own starting and ending point.<\/p>\n\n\n\n<p class=\"\">The <code>twinkle<\/code> keyframe just defines an opacity value for the spark elements to oscillate between. Opacity is the level of an element&#8217;s transparency, so going between a low and high value gives the illusion that the element is twinkling.<\/p>\n\n\n\n<p class=\"\">Now, we update the <code>spark<\/code> element&#8217;s CSS to include these keyframes as animations. The element&#8217;s entire CSS rule should look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.spark {\n\u00a0\u00a0position: absolute;\n\u00a0\u00a0width: 4px;\n\u00a0\u00a0height: 4px;\n\u00a0\u00a0border-radius: 50%;\n\u00a0\u00a0background: var(--spoiler-dot);\n\u00a0\u00a0animation:\n\u00a0\u00a0\u00a0\u00a0drift var(--dur) linear infinite,\n\u00a0\u00a0\u00a0\u00a0twinkle var(--twinkle) ease-in-out infinite alternate;\n}<\/code><\/pre>\n\n\n\n<p class=\"\">The change here is the addition of <code>animation<\/code> to the <code>spark<\/code> class and adding <code>drift<\/code> and <code>twinkle<\/code>. For <code>drift<\/code>, we pass the randomly-generated <code>dur<\/code> value we defined in the JavaScript; this value defines how long it takes the spark to move from its starting coordinates to its ending coordinates. We also pass the arguments <code>linear<\/code> and <code>infinite<\/code> to the animation, ensuring the movement is in a straight line and repeats as long as the page is loaded.<\/p>\n\n\n\n<p class=\"\">Similarly, we pass the randomly-generated <code>twinkle<\/code> variable to the <code>twinkle<\/code> keyframe animation, this variable defines the amount of time it takes the spark to go from its starting opacity to its ending opacity. The <code>alternate<\/code> argument ensures the opacity value doesn&#8217;t &#8220;start over&#8221; once it reaches its ending opacity and instead eases back to the starting value.<\/p>\n\n\n\n<p class=\"\">With this final addition, we should have a nice sparkly veil over our spoiler content. Here&#8217;s what mine looks like:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1640\" height=\"386\" src=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-6.png?fit=1024%2C241&amp;ssl=1\" alt=\"\" class=\"wp-image-3349\" srcset=\"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-6.png?w=1640&amp;ssl=1 1640w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-6.png?resize=300%2C71&amp;ssl=1 300w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-6.png?resize=1024%2C241&amp;ssl=1 1024w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-6.png?resize=768%2C181&amp;ssl=1 768w, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/image-6.png?resize=1536%2C362&amp;ssl=1 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"\">Note that since we are randomly generating a lot of values, your example might not look exactly like mine, and if you refresh the page, it&#8217;ll look different again. But as long as you see sparkles twinkling and drifting over your blurred-out spoiler text, you&#8217;ve done everything right so far!<\/p>\n\n\n\n<p class=\"\">The last thing to do is add the toggle effect!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Adding the Toggle Effect<\/h3>\n\n\n\n<p class=\"\">The point of the spoiler tag is to prevent people from seeing something they&#8217;re not ready to see. But for users that are willing to risk spoiling a piece of media, we have to add the ability to remove the sparkly veil and reveal the hidden text. We will add that effect now.<\/p>\n\n\n\n<p class=\"\">The strategy for how we will do this is as follows:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"\">Add a function that sets the <code>spoiler<\/code> span&#8217;s <code>data-hidden<\/code> attribute to the opposite of what it currently is (if it&#8217;s true, set it to false and vice versa)<\/li>\n\n\n\n<li class=\"\">Add this function to the &#8220;click&#8221; event listener on the <code>spoiler<\/code> span<\/li>\n\n\n\n<li class=\"\">Update the CSS of attributes inside of a <code>spoiler<\/code> span with a <code>data-hidden=\"false\"<\/code> attribute<\/li>\n<\/ol>\n\n\n\n<p class=\"\">Part one and two are going to happen simultaneously inside of the <code>wireSpoiler<\/code> function. The first thing we&#8217;ll do is get the <code>spoiler-blur<\/code> element&#8217;s parent element (which should be the <code>spoiler<\/code> span). This is accomplished via this one JavaScript line:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>let spoilerSpan = spoilerBlurSpan.parentElement;<\/code><\/pre>\n\n\n\n<p class=\"\">Now, just below that line, we&#8217;ll create a function called <code>toggle<\/code>. This function will get the <code>data-hidden<\/code> attribute of the <code>spoiler<\/code> and set a variable called <code>hidden<\/code> to the opposite value. Then, we&#8217;ll use the <code>setAttribute<\/code> method to set <code>data-hidden<\/code> to the value of the new <code>hidden<\/code> variable. This is what is meant by &#8220;toggling.&#8221;<\/p>\n\n\n\n<p class=\"\">Finally, we&#8217;ll use the <code>addEventListener<\/code> method to add the toggle method to that element&#8217;s click event. Altogether, the <code>wireSpoiler<\/code> function should now look like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function wireSpoiler(spoilerBlurSpan) {\n\u00a0\u00a0\u00a0\u00a0buildSparkles(spoilerBlurSpan, 75);\n\u00a0\u00a0\u00a0\u00a0let spoilerSpan = spoilerBlurSpan.parentElement;\n\n\u00a0\u00a0\u00a0\u00a0function toggle() {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const hidden = spoilerSpan.getAttribute(\"data-hidden\") === \"true\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0spoilerSpan.setAttribute(\"data-hidden\", String(!hidden))\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0\u00a0spoilerSpan.addEventListener(\"click\", toggle);\n}<\/code><\/pre>\n\n\n\n<p class=\"\">In the above code added a few lines to the <code>wireSpoiler<\/code> function. First,\u00a0 we got the <code>spoilerBlur<\/code> element&#8217;s parent element, which should be the <code>spoiler<\/code> span. Then, we create a <code>toggle<\/code> function, the first line of which grabs the <code>data-hidden<\/code> attribute&#8217;s value and checks if it is true. Since we wrote this line in the HTML:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;span class=\"spoiler\" data-hidden=\"true\"><\/code><\/pre>\n\n\n\n<p class=\"\">The value will be the string value <code>\"true\"<\/code> when the web page initially loads, meaning our <code>hidden<\/code> variable&#8217;s value will be the boolean <code>value<\/code> true.<\/p>\n\n\n\n<p class=\"\">On the next line, we set the attribute to the string representation of whatever the opposite of that value is by using <code>!hidden<\/code>. The <code>!<\/code> operator negates whatever variable is next to it. So <code>!true<\/code> (read &#8220;not true&#8221;) becomes <code>false<\/code> and <code>!false<\/code> (read &#8220;not false&#8221;) becomes <code>true<\/code>.<\/p>\n\n\n\n<p class=\"\">Finally, outside of the <code>toggle<\/code> function, we use the <code>addEventListener<\/code> method to add the <code>toggle<\/code> function to the <code>click<\/code> event, meaning this function will run any time the spoiler span is clicked.<\/p>\n\n\n\n<p class=\"\">As of right now, clicking the <code>spoiler<\/code> tag will just change its <code>data-hidden<\/code> attribute between <code>true<\/code> and <code>false<\/code>. You can view the element in your browser and watch the <code>data-hidden<\/code> value in the HTML change every time you click it. To actually toggle the blur effect on and off, we need to update the CSS and tell elements inside of <code>spoiler<\/code> elements with <code>data-hidden<\/code> attributes of <code>true<\/code> to behave a certain way.<\/p>\n\n\n\n<p class=\"\">We do this by making a block of rules for all <code>spark<\/code> elements inside of a <code>spoiler<\/code> span whose <code>data-hidden<\/code> attribute is false. We&#8217;ll do this by adding the following to our CSS file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>.spoiler&#91;data-hidden=\"false\"] .spark {\n\u00a0\u00a0animation-play-state: paused;\n\u00a0\u00a0display: none;\n}<\/code><\/pre>\n\n\n\n<p class=\"\">The code above targets only those <code>spark<\/code> elements inside of a spoiler element with the <code>data-hidden<\/code> value of <code>\"false\"<\/code>. Then, we set the <code>animation-play-state<\/code> to <code>paused<\/code>, this means the sparkle will stop where it is. We also set the <code>display<\/code> attribute to <code>none<\/code>, which essentially hides the sparkle.<\/p>\n\n\n\n<p class=\"\">Since clicking the <code>spoiler<\/code> tag will transition its <code>data-hidden<\/code> value to <code>false<\/code> if it&#8217;s already true, the new rules we wrote above will kick in on all the <code>spark<\/code> spans, essentially hiding them. It will also unblur the text inside of <code>spoiler-content<\/code> since we set the <code>filter<\/code> attribute to <code>blur(7px)<\/code> only in the rule for a <code>data-hidden=\"true\" <\/code>element.<\/p>\n\n\n\n<p class=\"\">With this final update, you should now be able to toggle the blur on and off in the web page! Refresh your browser and click the blurry spoiler text to see the effect in action.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">On Your Own<\/h1>\n\n\n\n<p class=\"\">Now that you have the basic ideas down for implementing the spoiler effect, there are lots of things you can do to expand upon and improve the code. For starters, the code above is inefficient because it sets the <code>toggle<\/code> function on the <code>spoiler<\/code> span <strong><em>for every sparkle<\/em><\/strong>, how would you fix that? You can also experiment with setting individual <code>spoiler<\/code> tags, each needing their own click to unblur, or set all spoiler tags to unblur when any of them are clicked. There are also tons of things you can do to change the animation style and sparkle appearance. Play around with it!<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Conclusion<\/h1>\n\n\n\n<p class=\"\">In this article, you learned how to mimic the spoiler effect from Threads and used HTML, CSS, and a little JavaScript to make it happen. We used keyframes and learned a little bit about CSS animations. You now know the basic strategies behind conditionally hiding and showing text, you can use this effect on your own website for a variety of reasons.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Final Code<\/h1>\n\n\n\n<p class=\"\">At the end of this article, I had three files called <code>spoiler_text.html<\/code>, <code>style.css<\/code>, and <a href=\"http:\/\/sparkle.js\"><code>sparkle.js<\/code><\/a>. Here are the contents of my files:<\/p>\n\n\n\n<p class=\"\"><code>index.html<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;!doctype html>\n&lt;html>\n&lt;head>\n\u00a0\u00a0\u00a0\u00a0&lt;title>Sparkly Spoiler Effect&lt;\/title>\n\u00a0\u00a0\u00a0\u00a0&lt;link rel=\"stylesheet\" href=\"style.css\" \/>\n&lt;\/head>\n&lt;body>\n\u00a0\u00a0\u00a0\u00a0&lt;p>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0The biggest plot twist of all time is:\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler\" data-hidden=\"true\">\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler-content\">\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Darth Vader is Luke Skywalker's father!\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/span>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;span class=\"spoiler-blur\" \/>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&lt;\/span>\n\u00a0\u00a0\u00a0\u00a0&lt;\/p>\n\u00a0\u00a0\u00a0\u00a0&lt;script src=\"sparkle.js\">&lt;\/script>\n&lt;\/body>\n&lt;\/html><\/code><\/pre>\n\n\n\n<p class=\"\"><code>style.css<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>:root {\n\u00a0\u00a0--bg: #0f1115;\n\u00a0\u00a0--text: #f4f7fb;\n\u00a0\u00a0--spoiler-dot: rgba(255,255,255,0.85);\n}\n\nbody {\n\u00a0\u00a0min-height: 25vh;\n\u00a0\u00a0display: grid;\n\u00a0\u00a0place-items: center;\n\u00a0\u00a0background: var(--bg);\n\u00a0\u00a0color: var(--text);\n}\n\n.spoiler {\n\u00a0\u00a0cursor: pointer;\n\u00a0\u00a0position: relative;\n}\n\n.spoiler&#91;data-hidden=\"true\"] .spoiler-content {\n\u00a0\u00a0filter: blur(7px);\n}\n\n.spark {\n\u00a0\u00a0position: absolute;\n\u00a0\u00a0width: 4px;\n\u00a0\u00a0height: 4px;\n\u00a0\u00a0border-radius: 50%;\n\u00a0\u00a0background: var(--spoiler-dot);\n\u00a0\u00a0animation:\n\u00a0\u00a0\u00a0\u00a0drift var(--dur) linear infinite,\n\u00a0\u00a0\u00a0\u00a0twinkle var(--twinkle) ease-in-out infinite alternate;\n}\n\n.spoiler&#91;data-hidden=\"false\"] .spark {\n\u00a0\u00a0animation-play-state: paused;\n\u00a0\u00a0display: none;\n}\n\n@keyframes drift {\n\u00a0\u00a0from {\n\u00a0\u00a0\u00a0\u00a0transform: translate(var(--x0), var(--y0)) scale(var(--scale));\n\u00a0\u00a0}\n\u00a0\u00a0to {\n\u00a0\u00a0\u00a0\u00a0transform: translate(var(--x1), var(--y1)) scale(var(--scale));\n\u00a0\u00a0}\n}\n\n@keyframes twinkle {\n\u00a0\u00a0from { opacity: 0.25; }\n\u00a0\u00a0to \u00a0 { opacity: 0.95; }\n}<\/code><\/pre>\n\n\n\n<p class=\"\"><code>sparkle.js<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>function random(rscale) {\n\n\u00a0\u00a0\u00a0\u00a0return Math.random() * rscale;\n\n}\n\nfunction buildSparkles(spoilerBlurSpan, sparkleCount) {\n\u00a0\u00a0\u00a0\u00a0for (let i = 0; i &lt; sparkleCount; i++) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const s = document.createElement(\"span\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.className = \"spark\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const x0 = random(100);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const y0 = random(100);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const x1 = Math.max(0, Math.min(100, x0 + random(18)));\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const y1 = Math.max(0, Math.min(100, y0 + random(14)));\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.left = `${x0}%`;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.top = `${y0}%`;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--x0\", \"0px\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--y0\", \"0px\");\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--x1\", `${x1 - x0}px`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--y1\", `${y1 - y0}px`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--dur\", `${random(60)}s`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--twinkle\", `${random(1.2)}s`);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0s.style.setProperty(\"--scale\", `${random(1.5)}`);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0spoilerBlurSpan.appendChild(s)\n\u00a0\u00a0\u00a0\u00a0}\n}\n\nfunction wireSpoiler(spoilerBlurSpan) {\n\u00a0\u00a0\u00a0\u00a0buildSparkles(spoilerBlurSpan, 75);\n\u00a0\u00a0\u00a0\u00a0let spoilerSpan = spoilerBlurSpan.parentElement;\n\n\u00a0\u00a0\u00a0\u00a0function toggle() {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0const hidden = spoilerSpan.getAttribute(\"data-hidden\") === \"true\";\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0spoilerSpan.setAttribute(\"data-hidden\", String(!hidden))\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0spoilerSpan.addEventListener(\"click\", toggle);\n}\n\ndocument.querySelectorAll(\".spoiler-blur\").forEach(wireSpoiler);<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>If you use Meta&#8217;s Threads app on a mobile device, you may have noticed an interesting effect: the spoiler tag that hides text behind a sparkly veil. In this article, I will show you how to implement this effect in the browser using HTML, CSS, and JavaScript. NOTE: You can scroll to the bottom of&#8230;<\/p>\n","protected":false},"author":1,"featured_media":3353,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"nf_dc_page":"","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[82],"tags":[86,84,83],"class_list":["post-3341","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-development","tag-html","tag-javascript","tag-web-development"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2026\/04\/pexels-zba-banner-2156097684-34036475-scaled.jpg?fit=2560%2C1697&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pb90KY-RT","jetpack-related-posts":[{"id":238,"url":"https:\/\/erikscode.space\/index.php\/2020\/04\/24\/stop-worrying-about-which-programming-language-to-learn-first\/","url_meta":{"origin":3341,"position":0},"title":"Stop Worrying About Which Programming Language to Learn First","author":"erik","date":"April 24, 2020","format":false,"excerpt":"I remember when I first decided I wanted to learn to write code, my google search history would look like this: Best first programming languageWhat programming language should I learnHow to avoid Ebola (unrelated)Python good first language? Ultimately, this time I spent was a waste and I\u2019ll tell you why.\u2026","rel":"","context":"In &quot;Language Specific&quot;","block_context":{"text":"Language Specific","link":"https:\/\/erikscode.space\/index.php\/category\/language-specific\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/1_CB6Qim8hbdx2s-jUu39hEQ.jpeg?fit=800%2C533&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/1_CB6Qim8hbdx2s-jUu39hEQ.jpeg?fit=800%2C533&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/1_CB6Qim8hbdx2s-jUu39hEQ.jpeg?fit=800%2C533&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/1_CB6Qim8hbdx2s-jUu39hEQ.jpeg?fit=800%2C533&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":2354,"url":"https:\/\/erikscode.space\/index.php\/2024\/05\/20\/review-naming-things-the-hardest-problem-in-software-engineering\/","url_meta":{"origin":3341,"position":1},"title":"[Review] Naming Things: The Hardest Problem in Software Engineering","author":"erik","date":"May 20, 2024","format":false,"excerpt":"In today's post, I review Naming Things: The Hardest Problem in Software Engineering, by Tom Benner. NOTE: At erikscode.space, book reviews do not contain affiliate links or paid advertisements. They are not written at the request of one of the authors or publishers, paid or otherwise. There are no incentives\u2026","rel":"","context":"In &quot;Book Reviews and Suggested Reading&quot;","block_context":{"text":"Book Reviews and Suggested Reading","link":"https:\/\/erikscode.space\/index.php\/category\/suggested-reading\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2024\/05\/namingthings.jpg?fit=750%2C1200&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2024\/05\/namingthings.jpg?fit=750%2C1200&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2024\/05\/namingthings.jpg?fit=750%2C1200&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2024\/05\/namingthings.jpg?fit=750%2C1200&ssl=1&resize=700%2C400 2x"},"classes":[]},{"id":417,"url":"https:\/\/erikscode.space\/index.php\/2021\/04\/16\/professional-version-control-with-git-pt-3-rebase-and-bisect\/","url_meta":{"origin":3341,"position":2},"title":"Professional Version Control with Git: Pt 3 \u2013 Rebase and Bisect","author":"erik","date":"April 16, 2021","format":false,"excerpt":"Hello everyone and welcome to part 3 of the professional Git series here at Erik's Code Space. In part 1, we learned the basics and got our skills good enough to start version controlling our own projects. In part 2, we learned about the collaboration tools available in git and\u2026","rel":"","context":"In &quot;SVC, CI\/CD, and More&quot;","block_context":{"text":"SVC, CI\/CD, and More","link":"https:\/\/erikscode.space\/index.php\/category\/svc-ci-cd-and-more\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2021\/04\/pexels-rodnae-productions-6069605-scaled.jpg?fit=1200%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2021\/04\/pexels-rodnae-productions-6069605-scaled.jpg?fit=1200%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2021\/04\/pexels-rodnae-productions-6069605-scaled.jpg?fit=1200%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2021\/04\/pexels-rodnae-productions-6069605-scaled.jpg?fit=1200%2C800&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2021\/04\/pexels-rodnae-productions-6069605-scaled.jpg?fit=1200%2C800&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":222,"url":"https:\/\/erikscode.space\/index.php\/2020\/04\/14\/why-you-shouldnt-learn-c\/","url_meta":{"origin":3341,"position":3},"title":"Why You Shouldn&#8217;t Learn C","author":"erik","date":"April 14, 2020","format":false,"excerpt":"Knowledge of the C programming language is often touted as the mark of a \"true\" programmer. You don't really know programming unless you know this language, or so the wisdom goes. Many aspiring programmers have been advised by gatekeepers senior developers to learn C to up their skills and bring\u2026","rel":"","context":"In &quot;C\/C++&quot;","block_context":{"text":"C\/C++","link":"https:\/\/erikscode.space\/index.php\/category\/language-specific\/c-c\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/phil-hearing-YbT8wrbPMug-unsplash-scaled.jpg?fit=1200%2C800&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/phil-hearing-YbT8wrbPMug-unsplash-scaled.jpg?fit=1200%2C800&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/phil-hearing-YbT8wrbPMug-unsplash-scaled.jpg?fit=1200%2C800&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/phil-hearing-YbT8wrbPMug-unsplash-scaled.jpg?fit=1200%2C800&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2020\/04\/phil-hearing-YbT8wrbPMug-unsplash-scaled.jpg?fit=1200%2C800&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":29,"url":"https:\/\/erikscode.space\/index.php\/2019\/07\/20\/how-to-work-with-memory-optimized-objects-in-sql-server\/","url_meta":{"origin":3341,"position":4},"title":"How To Work With Memory Optimized Objects in SQL Server","author":"erik","date":"July 20, 2019","format":false,"excerpt":"Good morning everyone, today I'm going to show you how to make memory optimized tables and natively compiled stored procedures. First, I'll talk about why you might want to use these things, then we'll just dive straight in to how to do it. Relevant Video If you don't feel like\u2026","rel":"","context":"In &quot;Database&quot;","block_context":{"text":"Database","link":"https:\/\/erikscode.space\/index.php\/category\/database\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/07\/fabio-oyXis2kALVg-unsplash.jpg?fit=1200%2C900&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/07\/fabio-oyXis2kALVg-unsplash.jpg?fit=1200%2C900&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/07\/fabio-oyXis2kALVg-unsplash.jpg?fit=1200%2C900&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/07\/fabio-oyXis2kALVg-unsplash.jpg?fit=1200%2C900&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/07\/fabio-oyXis2kALVg-unsplash.jpg?fit=1200%2C900&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":109,"url":"https:\/\/erikscode.space\/index.php\/2019\/09\/27\/getting-started-with-browser-automation-testing-in-python\/","url_meta":{"origin":3341,"position":5},"title":"Getting Started With Browser Automation Testing in Python","author":"erik","date":"September 27, 2019","format":false,"excerpt":"Developers have unit tests to test atomic functionality and integration tests to test system interoperability. Web developers have to take it a step further and test actual browser behavior. This can be done in many ways, but most often it's with some implementation of Selenium webdriver and an xUnit testing\u2026","rel":"","context":"In &quot;Testing&quot;","block_context":{"text":"Testing","link":"https:\/\/erikscode.space\/index.php\/category\/testing\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/09\/david-clode-RAfIk-ZKbPk-unsplash.jpg?fit=1200%2C778&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/09\/david-clode-RAfIk-ZKbPk-unsplash.jpg?fit=1200%2C778&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/09\/david-clode-RAfIk-ZKbPk-unsplash.jpg?fit=1200%2C778&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/09\/david-clode-RAfIk-ZKbPk-unsplash.jpg?fit=1200%2C778&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/erikscode.space\/wp-content\/uploads\/2019\/09\/david-clode-RAfIk-ZKbPk-unsplash.jpg?fit=1200%2C778&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/posts\/3341","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/comments?post=3341"}],"version-history":[{"count":0,"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/posts\/3341\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/media\/3353"}],"wp:attachment":[{"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/media?parent=3341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/categories?post=3341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/erikscode.space\/index.php\/wp-json\/wp\/v2\/tags?post=3341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}