<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Snappy Tools</title>
    <description>The latest articles on DEV Community by Snappy Tools (@snappy_tools).</description>
    <link>https://dev.to/snappy_tools</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3863980%2F0cf60988-24da-462f-8d07-47fac7c5b263.png</url>
      <title>DEV Community: Snappy Tools</title>
      <link>https://dev.to/snappy_tools</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/snappy_tools"/>
    <language>en</language>
    <item>
      <title>CSS Box Shadow: The Complete Guide with Examples</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Sat, 20 Jun 2026 10:03:38 +0000</pubDate>
      <link>https://dev.to/snappy_tools/css-box-shadow-the-complete-guide-with-examples-3fm9</link>
      <guid>https://dev.to/snappy_tools/css-box-shadow-the-complete-guide-with-examples-3fm9</guid>
      <description>&lt;p&gt;CSS &lt;code&gt;box-shadow&lt;/code&gt; is one of those properties that looks simple on the surface but has surprising depth. This guide covers everything from the basics to multi-layer shadows, inset shadows, and performance considerations — with ready-to-copy examples throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Syntax
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;offset-x&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;offset-y&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;blur-radius&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;spread-radius&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each value:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;offset-x&lt;/strong&gt; — horizontal shift (positive = right, negative = left)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;offset-y&lt;/strong&gt; — vertical shift (positive = down, negative = up)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;blur-radius&lt;/strong&gt; — higher = softer/larger shadow (can't be negative)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;spread-radius&lt;/strong&gt; — expands or contracts the shadow before blur&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;color&lt;/strong&gt; — any valid CSS colour, including &lt;code&gt;rgba()&lt;/code&gt; for transparency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two values are the minimum required: offset-x and offset-y.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Minimal shadow */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;black&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* Typical card shadow */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Shadow Patterns
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Soft / Subtle
&lt;/h3&gt;

&lt;p&gt;Best for cards and containers where you want depth without drama.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;06&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Raised / Button
&lt;/h3&gt;

&lt;p&gt;Makes an element look clickable — like a physical button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;6&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;06&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Floating / Elevated
&lt;/h3&gt;

&lt;p&gt;For modals, dropdowns, or any element that should appear above the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;25&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deep / Strong
&lt;/h3&gt;

&lt;p&gt;Dramatic elevation — use sparingly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;60&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;6&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inset Shadow
&lt;/h3&gt;

&lt;p&gt;Renders the shadow inside the element, giving a pressed or sunken look.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;inset&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;6&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful for input fields, toggle wells, or pressed button states.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-Layer Shadows
&lt;/h2&gt;

&lt;p&gt;You can stack multiple shadows by comma-separating them. They render front-to-back (first value is on top).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Two-layer shadow: tight dark + wide light */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt;
  &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;24&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Multi-layer shadows look more natural than a single shadow because real-world light creates both a sharp contact shadow near the object and a soft diffuse shadow further away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spread Radius in Practice
&lt;/h2&gt;

&lt;p&gt;The spread radius is often misunderstood. Positive spread expands the shadow before blur is applied; negative shrinks it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Outline effect (0 blur, spread only) */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;#3&lt;/span&gt;&lt;span class="nt"&gt;b82f6&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* Negative spread + large offset = shadow only at bottom */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;-5px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;0 0 0 Xpx color&lt;/code&gt; pattern is a useful trick for adding a coloured ring/outline to any element — including images — without affecting layout (unlike &lt;code&gt;outline&lt;/code&gt;, which can be clipped).&lt;/p&gt;

&lt;h2&gt;
  
  
  Colour and Opacity
&lt;/h2&gt;

&lt;p&gt;Avoid hardcoded black shadows. Use &lt;code&gt;rgba()&lt;/code&gt; with low alpha for realistic depth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Too harsh */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;black&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* Natural */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For coloured glow effects (useful for interactive elements):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Green glow */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;12&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;34&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;197&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;94&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;/* Blue focus ring */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;59&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;130&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;246&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Transition and Animation
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;box-shadow&lt;/code&gt; is animatable. Combine with &lt;code&gt;:hover&lt;/code&gt; or &lt;code&gt;:focus&lt;/code&gt; transitions for responsive depth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;box-shadow&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep transitions under 300ms. Longer delays feel sluggish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Notes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;box-shadow&lt;/code&gt; triggers the browser's composite layer — it is painted, not composited. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Animating &lt;code&gt;box-shadow&lt;/code&gt; is more expensive than animating &lt;code&gt;transform&lt;/code&gt; or &lt;code&gt;opacity&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;For animation-heavy UIs, use a pseudo-element with &lt;code&gt;opacity&lt;/code&gt; transition as a workaround:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;::after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;inset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;opacity&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover::after&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you animate &lt;code&gt;opacity&lt;/code&gt; (GPU-composited) instead of &lt;code&gt;box-shadow&lt;/code&gt; directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dark Mode Shadows
&lt;/h2&gt;

&lt;p&gt;Box shadows over dark backgrounds often disappear or look harsh. Options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use &lt;code&gt;rgba()&lt;/code&gt; white shadows&lt;/strong&gt; for a subtle emboss/lift effect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduce shadow opacity&lt;/strong&gt; — a 0.5 alpha shadow that works on light needs ~0.15 on dark&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a border instead&lt;/strong&gt; — often cleaner on dark UIs
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;th&gt;CSS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Soft card&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 1px 3px rgba(0,0,0,0.1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Raised button&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 4px 6px rgba(0,0,0,0.1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Floating modal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 10px 25px rgba(0,0,0,0.15)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inset (pressed)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inset 0 2px 4px rgba(0,0,0,0.1)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Focus ring&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 0 3px rgba(59,130,246,0.4)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coloured glow&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 12px rgba(34,197,94,0.5)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Try It Live
&lt;/h2&gt;

&lt;p&gt;Rather than tweaking values by hand, use a visual box shadow generator to dial in the exact look you want. &lt;strong&gt;&lt;a href="https://snappytools.app/css-box-shadow-generator/" rel="noopener noreferrer"&gt;SnappyTools CSS Box Shadow Generator&lt;/a&gt;&lt;/strong&gt; lets you add up to 4 independent shadow layers with live preview, export as CSS, and start from one of 5 presets — all in the browser with no signup required.&lt;/p&gt;




&lt;p&gt;Box shadows are one of the easiest ways to add depth and polish to a UI. Master the multi-layer approach and the &lt;code&gt;rgba()&lt;/code&gt; opacity technique, and you'll stop reaching for border hacks to create the same effect.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>NIST Password Guidelines 2024: What Every Developer Needs to Know</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Fri, 19 Jun 2026 10:07:15 +0000</pubDate>
      <link>https://dev.to/snappy_tools/nist-password-guidelines-2024-what-every-developer-needs-to-know-1ge5</link>
      <guid>https://dev.to/snappy_tools/nist-password-guidelines-2024-what-every-developer-needs-to-know-1ge5</guid>
      <description>&lt;p&gt;If you're still telling users to include "at least one uppercase letter, one number, and one special character," you're following outdated advice. The National Institute of Standards and Technology (NIST) updated their password guidance significantly in 2024, and the changes are worth knowing — especially if you build or maintain authentication systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is NIST SP 800-63B?
&lt;/h2&gt;

&lt;p&gt;NIST Special Publication 800-63B is the US federal standard for digital identity and authentication. It's not just for government systems — it's widely cited as the gold standard for password policy in private industry. The fourth revision (800-63B-4) was published in 2024, building on the landmark 2017 update that first reversed decades of conventional wisdom about passwords.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 2024 Updates: What Changed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Minimum length raised to 15 characters
&lt;/h3&gt;

&lt;p&gt;The 2017 guidance set the minimum at 8 characters. The 2024 revision raises this to &lt;strong&gt;15 characters&lt;/strong&gt; for user-chosen passwords. The maximum must be at least 64 characters — and verifiers must not truncate passwords beyond this length.&lt;/p&gt;

&lt;h3&gt;
  
  
  All Unicode is now allowed
&lt;/h3&gt;

&lt;p&gt;Passwords must support all printable Unicode characters, including spaces and emoji. A password like &lt;code&gt;correct horse battery staple&lt;/code&gt; (with spaces) is valid and encouraged. This matters for internationalization — non-English users often use characters from their own language in memorable passphrases.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mandatory breach checking
&lt;/h3&gt;

&lt;p&gt;New passwords must be checked against known-compromised lists. The &lt;a href="https://haveibeenpwned.com/API/v3#PwnedPasswords" rel="noopener noreferrer"&gt;HaveIBeenPwned API&lt;/a&gt; provides a free, privacy-preserving k-anonymity endpoint for this. If a user submits a password found in a breach dataset, reject it with a clear message — not a generic "password is too weak" error.&lt;/p&gt;

&lt;h3&gt;
  
  
  SMS OTP is downgraded
&lt;/h3&gt;

&lt;p&gt;SMS-based one-time passwords are no longer considered acceptable for high-assurance applications. SMS is vulnerable to SIM-swapping attacks and SS7 protocol weaknesses. NIST now recommends authenticator apps (TOTP) or passkeys instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Periodic rotation is explicitly banned
&lt;/h3&gt;

&lt;p&gt;This deserves emphasis: &lt;strong&gt;do not force users to change passwords on a schedule.&lt;/strong&gt; The research is clear — forced rotation leads to predictable changes (Password1 → Password2 → Password3) and makes security worse. Only require a password change if there's evidence of compromise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What NIST Says to Stop Doing
&lt;/h2&gt;

&lt;p&gt;These practices are explicitly discouraged in 800-63B:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complexity rules&lt;/strong&gt;: Requiring uppercase + lowercase + number + symbol. These push users toward predictable substitutions (P@ssw0rd) rather than genuinely random passwords.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password hints&lt;/strong&gt;: Storing hints that make guessing easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge-based authentication&lt;/strong&gt;: Security questions ("What was the name of your first pet?") are banned for high-assurance applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truncating passwords&lt;/strong&gt;: Never silently truncate a password that meets the maximum length. This is a security vulnerability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Password expiration timers&lt;/strong&gt;: Without evidence of compromise, rotating passwords reduces security.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Good Password Policy Looks Like in 2024
&lt;/h2&gt;

&lt;p&gt;If you're building an auth system or updating your password policy, here's the NIST-aligned checklist:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Accept passwords 15–64+ characters&lt;/strong&gt; (set your DB column to 255 to be safe)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept all printable characters&lt;/strong&gt; including spaces — don't strip or reject Unicode&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hash with bcrypt, Argon2, or scrypt&lt;/strong&gt; — never MD5, SHA-1, or unsalted SHA-256&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check against breach databases&lt;/strong&gt; at registration and optionally on login&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No complexity rules&lt;/strong&gt; — length is the only mandatory requirement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No periodic expiration&lt;/strong&gt; — only reset on confirmed breach&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate-limit login attempts&lt;/strong&gt; — throttle or lockout after repeated failures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offer MFA&lt;/strong&gt; — TOTP or passkeys, not SMS&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  A Note on Entropy
&lt;/h2&gt;

&lt;p&gt;The reason NIST focuses on length rather than complexity is entropy. Password strength is measured in bits of entropy — how many guesses would it take to crack it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;8-character all-lowercase: ~38 bits&lt;/li&gt;
&lt;li&gt;8-character with complexity rules: ~52 bits (strong for a 2005 attack, weak today)&lt;/li&gt;
&lt;li&gt;16-character random (mixed): ~105 bits&lt;/li&gt;
&lt;li&gt;20-character random (mixed): ~131 bits — exceeds AES-128 security level&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A random 16-character password generated by a cryptographically secure generator is practically uncrackable by brute force. The real risks are phishing, credential stuffing, and insecure storage — not brute force.&lt;/p&gt;

&lt;p&gt;For generating properly random passwords, use &lt;a href="https://snappytools.app/password-generator/" rel="noopener noreferrer"&gt;this free password generator&lt;/a&gt; — it uses &lt;code&gt;window.crypto.getRandomValues()&lt;/code&gt; (the same CSPRNG your browser uses for HTTPS) and runs entirely in your browser. No data is ever sent to a server.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check If a Password Has Been Breached
&lt;/h2&gt;

&lt;p&gt;The HaveIBeenPwned API uses k-anonymity: you send only the first 5 characters of the SHA-1 hash of the password, and the API returns all matching hash suffixes. Your server (or client) checks if the full hash appears in the list. The password itself never leaves the user's device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib.request&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_pwned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;sha1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suffix&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;sha1&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.pwnedpasswords.com/range/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;urlopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="n"&gt;hash_suffix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hash_suffix&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;is_pwned&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;password123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; breaches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Not found in known breaches&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this check at password creation and optionally on login. If the count is &amp;gt; 0, reject the password with a message like: &lt;em&gt;"This password appeared in a known data breach. Please choose a different one."&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;NIST's 2024 guidance in three sentences: &lt;strong&gt;Use long random passwords.&lt;/strong&gt; &lt;strong&gt;Stop adding friction that doesn't improve security.&lt;/strong&gt; &lt;strong&gt;Check passwords against known breach databases.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For most developers, the key action item is to stop enforcing complexity rules that frustrate users without improving security, and to add HaveIBeenPwned integration to your registration flow.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Need to generate strong random passwords for testing, provisioning, or personal use? &lt;a href="https://snappytools.app/password-generator/" rel="noopener noreferrer"&gt;SnappyTools Password Generator&lt;/a&gt; runs entirely in your browser with no server calls — 8 to 128 characters, customisable character sets, and up to 10 passwords at once.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>beginners</category>
      <category>tools</category>
    </item>
    <item>
      <title>What Is the Automated Readability Index (ARI)? A Developer's Guide</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Thu, 18 Jun 2026 10:03:55 +0000</pubDate>
      <link>https://dev.to/snappy_tools/what-is-the-automated-readability-index-ari-a-developers-guide-1aap</link>
      <guid>https://dev.to/snappy_tools/what-is-the-automated-readability-index-ari-a-developers-guide-1aap</guid>
      <description>&lt;p&gt;If you've ever needed to score the readability of a piece of text programmatically, you've probably encountered the Flesch-Kincaid formula. But there's a lesser-known formula that's actually &lt;em&gt;faster&lt;/em&gt; to compute and produces similarly accurate results: the &lt;strong&gt;Automated Readability Index&lt;/strong&gt;, or ARI.&lt;/p&gt;

&lt;p&gt;This post explains what ARI is, how the formula works, how it compares to other readability metrics, and when to use it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is the Automated Readability Index?
&lt;/h2&gt;

&lt;p&gt;The Automated Readability Index (ARI) is a readability formula developed in 1967 for the &lt;strong&gt;US Air Force&lt;/strong&gt; to evaluate the readability of technical documents and training manuals. It was designed to be computed automatically — without human syllable counting.&lt;/p&gt;

&lt;p&gt;The formula is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ARI = 4.71 × (characters / words) + 0.5 × (words / sentences) − 21.43
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result is a number that maps directly to a &lt;strong&gt;US school grade level&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ARI Score&lt;/th&gt;
&lt;th&gt;Grade Level&lt;/th&gt;
&lt;th&gt;Age Range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Kindergarten&lt;/td&gt;
&lt;td&gt;5–6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;1st Grade&lt;/td&gt;
&lt;td&gt;6–7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;2nd Grade&lt;/td&gt;
&lt;td&gt;7–8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3rd Grade&lt;/td&gt;
&lt;td&gt;8–9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;4th Grade&lt;/td&gt;
&lt;td&gt;9–10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;5th Grade&lt;/td&gt;
&lt;td&gt;10–11&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;6th Grade&lt;/td&gt;
&lt;td&gt;11–12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;7th Grade&lt;/td&gt;
&lt;td&gt;12–13&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;8th Grade&lt;/td&gt;
&lt;td&gt;13–14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;9th Grade&lt;/td&gt;
&lt;td&gt;14–15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;10th Grade&lt;/td&gt;
&lt;td&gt;15–16&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;11th Grade&lt;/td&gt;
&lt;td&gt;16–17&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;12th Grade&lt;/td&gt;
&lt;td&gt;17–18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;College&lt;/td&gt;
&lt;td&gt;18–22&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Why Characters Instead of Syllables?
&lt;/h2&gt;

&lt;p&gt;Most readability formulas (Flesch-Kincaid, Gunning Fog, SMOG) use syllable counts. Counting syllables accurately requires linguistic knowledge — you need a pronunciation dictionary or a syllabification algorithm.&lt;/p&gt;

&lt;p&gt;ARI sidesteps this entirely. It uses &lt;strong&gt;character count per word&lt;/strong&gt; instead. The reasoning: longer words (more characters) tend to have more syllables and be harder to read — so character count is a reasonable proxy, and it's trivially easy to compute.&lt;/p&gt;

&lt;p&gt;In Python, implementing ARI from scratch takes about 10 lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_ari&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[.!?]+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isalnum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;4.71&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;21.43&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No syllable dictionary required.&lt;/p&gt;




&lt;h2&gt;
  
  
  ARI vs. Flesch-Kincaid Grade Level
&lt;/h2&gt;

&lt;p&gt;Both ARI and Flesch-Kincaid Grade Level output a US school grade number. How do they compare?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For most English text, they agree closely&lt;/strong&gt; — typically within 0.5–1.5 grade levels.&lt;/p&gt;

&lt;p&gt;The difference emerges with words that are long but phonetically simple. Consider "algorithm": it has 9 characters but only 3 syllables. Flesch-Kincaid treats it as a moderately complex word; ARI treats it as more complex because of its character length. This means ARI tends to score slightly &lt;em&gt;higher&lt;/em&gt; than Flesch-Kincaid for texts heavy in technical vocabulary.&lt;/p&gt;

&lt;p&gt;For everyday prose, the difference is negligible. Choose based on your use case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ARI&lt;/strong&gt;: faster to compute, no syllable detection needed, designed for technical writing&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flesch-Kincaid&lt;/strong&gt;: more established in academic and educational publishing, better for literary analysis&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Target ARI Scores by Content Type
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Content Type&lt;/th&gt;
&lt;th&gt;Target ARI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Children's content&lt;/td&gt;
&lt;td&gt;3–5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;General web content&lt;/td&gt;
&lt;td&gt;6–9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marketing emails&lt;/td&gt;
&lt;td&gt;6–8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;News articles&lt;/td&gt;
&lt;td&gt;8–10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Business reports&lt;/td&gt;
&lt;td&gt;10–12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Technical documentation&lt;/td&gt;
&lt;td&gt;12–14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Academic papers&lt;/td&gt;
&lt;td&gt;14–18+&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Implementing ARI in Other Languages
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;JavaScript:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateARI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;.!?&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;4.71&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mf"&gt;21.43&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Go:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"regexp"&lt;/span&gt;
    &lt;span class="s"&gt;"strings"&lt;/span&gt;
    &lt;span class="s"&gt;"unicode"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;calculateARI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sentenceRe&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;regexp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MustCompile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`[.!?]+`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentenceRe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;chars&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;unicode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsLetter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;unicode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDigit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;sentences&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;4.71&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chars&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="kt"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sentences&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;21.43&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  When Should You Use ARI?
&lt;/h2&gt;

&lt;p&gt;ARI is a good choice when:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;You need a fast computation&lt;/strong&gt; — no syllable dictionary, just character counting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're analysing technical writing&lt;/strong&gt; — ARI was designed for this use case&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You're building a readability pipeline&lt;/strong&gt; — ARI integrates cleanly as one of several metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You need a grade-level output&lt;/strong&gt; — ARI maps directly to US grade levels without additional conversion&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want to run an ARI check on a piece of text right now without writing any code, you can use a free &lt;a href="https://snappytools.app/readability-checker/" rel="noopener noreferrer"&gt;ARI checker online&lt;/a&gt; that calculates ARI alongside Flesch-Kincaid, Gunning Fog, SMOG, and Coleman-Liau — all in one pass, no signup.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The Automated Readability Index is a 1967 formula designed for fast, automatic readability scoring. It uses character-per-word ratios instead of syllable counts, making it simpler to implement than most alternatives. For most English texts, it produces results very close to Flesch-Kincaid Grade Level.&lt;/p&gt;

&lt;p&gt;If you're building a readability scoring feature and want something lightweight with no linguistic dependencies, ARI is worth considering.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tools</category>
    </item>
    <item>
      <title>Why Your Word Counter Gives Different Results Than Others (And How They All Work)</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Wed, 17 Jun 2026 19:36:09 +0000</pubDate>
      <link>https://dev.to/snappy_tools/why-your-word-counter-gives-different-results-than-others-and-how-they-all-work-9pf</link>
      <guid>https://dev.to/snappy_tools/why-your-word-counter-gives-different-results-than-others-and-how-they-all-work-9pf</guid>
      <description>&lt;p&gt;You paste the same text into two different word counters and get different results. It happens more often than you'd expect. Here's why — and how to know which count to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core problem: what is a "word"?
&lt;/h2&gt;

&lt;p&gt;Every word counter has to answer this question, and there's no single right answer.&lt;/p&gt;

&lt;p&gt;The most common approach is &lt;strong&gt;whitespace splitting&lt;/strong&gt;: split the text on any space or line break, count the chunks. In JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wordCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Python:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;word_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both approaches count &lt;code&gt;don't&lt;/code&gt; as one word, &lt;code&gt;2026&lt;/code&gt; as one word, and &lt;code&gt;well-known&lt;/code&gt; as one word. That's usually what you want.&lt;/p&gt;

&lt;p&gt;But here's where they diverge:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Input&lt;/th&gt;
&lt;th&gt;Whitespace split&lt;/th&gt;
&lt;th&gt;Natural language tokenizer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hello, world&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2 words&lt;/td&gt;
&lt;td&gt;2 words&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;don't&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 word&lt;/td&gt;
&lt;td&gt;1 word (usually)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;well-known&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 word&lt;/td&gt;
&lt;td&gt;2 words (sometimes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;C++&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 word&lt;/td&gt;
&lt;td&gt;1 word&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;$ 100.00&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2 words&lt;/td&gt;
&lt;td&gt;2 words&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;:-)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1 word&lt;/td&gt;
&lt;td&gt;0 words (some tools skip symbols)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(empty line)&lt;/td&gt;
&lt;td&gt;0 words&lt;/td&gt;
&lt;td&gt;0 words&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Natural language tokenizers like Python's &lt;code&gt;nltk.word_tokenize()&lt;/code&gt; or spaCy's tokenizer follow linguistic rules. They'll split &lt;code&gt;I've&lt;/code&gt; into &lt;code&gt;I&lt;/code&gt; and &lt;code&gt;'ve&lt;/code&gt;, which a whitespace splitter won't. This is why NLP tools often produce higher word counts than simple splitters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule of thumb:&lt;/strong&gt; For writing (blog posts, essays, social media), whitespace splitting is fine and produces consistent results. For NLP tasks (training data, linguistic analysis), use a proper tokenizer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The character count you actually need to know
&lt;/h2&gt;

&lt;p&gt;Most people check word count. But character count is what actually matters for most platforms — and it's where most people get tripped up.&lt;/p&gt;

&lt;p&gt;Here are the limits that catch people out:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Limit&lt;/th&gt;
&lt;th&gt;Gotcha&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Twitter / X&lt;/td&gt;
&lt;td&gt;280 characters&lt;/td&gt;
&lt;td&gt;URLs always count as 23 chars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google meta description&lt;/td&gt;
&lt;td&gt;~155 characters&lt;/td&gt;
&lt;td&gt;Truncates in search results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LinkedIn post&lt;/td&gt;
&lt;td&gt;3,000 characters&lt;/td&gt;
&lt;td&gt;Feed truncates at ~210 chars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Instagram caption&lt;/td&gt;
&lt;td&gt;2,200 characters&lt;/td&gt;
&lt;td&gt;Feed shows ~125 chars before "more"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;YouTube description&lt;/td&gt;
&lt;td&gt;5,000 characters&lt;/td&gt;
&lt;td&gt;Shows ~100 chars in search results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Ads headline&lt;/td&gt;
&lt;td&gt;30 characters&lt;/td&gt;
&lt;td&gt;Hard limit, no truncation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Google Ads description&lt;/td&gt;
&lt;td&gt;90 characters&lt;/td&gt;
&lt;td&gt;Hard limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;App Store short description&lt;/td&gt;
&lt;td&gt;80 characters&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Facebook post&lt;/td&gt;
&lt;td&gt;63,206 characters&lt;/td&gt;
&lt;td&gt;Engagement drops after 80 chars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Facebook comment&lt;/td&gt;
&lt;td&gt;8,000 characters&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The Twitter URL rule is particularly confusing: whether you paste a 10-character URL or a 200-character URL, it counts as 23 characters in your post. X's own character counter handles this; most third-party tools don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "characters" is ambiguous too
&lt;/h2&gt;

&lt;p&gt;When a platform says "280 characters", does it mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bytes?&lt;/li&gt;
&lt;li&gt;Unicode code points?&lt;/li&gt;
&lt;li&gt;Grapheme clusters?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most Western text, these are the same. But for emoji and some Unicode characters, they're not.&lt;/p&gt;

&lt;p&gt;The fire emoji 🔥 is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;4 bytes (UTF-8)&lt;/li&gt;
&lt;li&gt;1 Unicode code point (U+1F525)&lt;/li&gt;
&lt;li&gt;1 grapheme cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Twitter counts each emoji as 2 characters (not 1, not 4). Most other platforms count it as 1.&lt;/p&gt;

&lt;p&gt;A skin-tone modified emoji like 👍🏽 is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Unicode code points (U+1F44D + U+1F3FD)&lt;/li&gt;
&lt;li&gt;1 grapheme cluster (visually one emoji)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JavaScript's &lt;code&gt;string.length&lt;/code&gt; counts it as 4 (because it uses UTF-16 with surrogate pairs). Twitter counts it as 2. Humans count it as 1.&lt;/p&gt;

&lt;p&gt;This is why emoji-heavy content can produce surprising character counts depending on which tool you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  The characters-to-words conversion
&lt;/h2&gt;

&lt;p&gt;The standard estimate: &lt;strong&gt;1 word ≈ 6 characters&lt;/strong&gt; (5 letters average + 1 space).&lt;/p&gt;

&lt;p&gt;This works well for conversational English. Adjust for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical writing&lt;/strong&gt; (long words like "authentication", "infrastructure"): closer to 7–8 chars/word, so 1,000 characters ≈ 130–145 words&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversational/casual writing&lt;/strong&gt; (lots of "the", "is", "a"): closer to 5 chars/word, so 1,000 characters ≈ 200 words&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code snippets or URLs&lt;/strong&gt;: ratio breaks down entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Quick reference:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characters&lt;/th&gt;
&lt;th&gt;Words (approx.)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;280&lt;/td&gt;
&lt;td&gt;~45&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;~83&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;~165&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;td&gt;~333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;td&gt;~500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;~833&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8,000&lt;/td&gt;
&lt;td&gt;~1,333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;~1,667&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For an exact count for your specific text: &lt;a href="https://snappytools.app/word-counter/" rel="noopener noreferrer"&gt;SnappyTools Word Counter&lt;/a&gt; updates in real time and shows character counts for major platforms side by side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading time: how accurate are the estimates?
&lt;/h2&gt;

&lt;p&gt;Most tools use 200–225 words per minute as the reading speed average. Medium uses 275 wpm; some tools use 200 wpm. That's a 35% difference in estimated reading time for the same text.&lt;/p&gt;

&lt;p&gt;The research is scattered. A 2019 meta-analysis by Brysbaert found the average silent reading speed is &lt;strong&gt;238 words per minute&lt;/strong&gt; for fiction and &lt;strong&gt;260 wpm&lt;/strong&gt; for non-fiction among proficient adult readers. But comprehension drops significantly above ~300 wpm for complex material.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical guideline for content creators:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use 225 wpm as a conservative baseline&lt;/li&gt;
&lt;li&gt;Add 20% for technical or dense content&lt;/li&gt;
&lt;li&gt;Headlines, bullet points, and white space reduce perceived reading time — a 1,000-word structured how-to article reads faster than a 1,000-word wall of prose&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The SEO word count myth
&lt;/h2&gt;

&lt;p&gt;You've probably heard that longer content ranks better. This is partially true and frequently misapplied.&lt;/p&gt;

&lt;p&gt;What actually correlates with higher rankings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Topical completeness&lt;/strong&gt; — does the content answer the query and related questions?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User intent match&lt;/strong&gt; — is this what the searcher was looking for?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dwell time&lt;/strong&gt; — do readers stay and read?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What does &lt;em&gt;not&lt;/em&gt; directly cause higher rankings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Raw word count above the threshold needed to cover the topic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A 500-word page that completely answers "what is ARP poisoning" will beat a 3,000-word rambling page on the same topic. The first-page average word count for competitive queries is often cited as 1,500–2,000 words, but that's correlation: pages that thoroughly cover complex topics happen to be long, not the other way round.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guideline:&lt;/strong&gt; Write until the topic is covered, then stop. For simple factual queries, 300–600 words is often right. For comprehensive guides covering multiple subtopics, 1,500–3,000 words is common. Don't pad.&lt;/p&gt;




&lt;p&gt;If you need a quick word, character, and reading time check with live platform limits: &lt;a href="https://snappytools.app/word-counter/" rel="noopener noreferrer"&gt;SnappyTools Word Counter&lt;/a&gt; — no signup, runs in the browser.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tools</category>
    </item>
    <item>
      <title>CSS Box Shadow: The Complete Guide (with Copy-Paste Examples)</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Tue, 16 Jun 2026 10:08:40 +0000</pubDate>
      <link>https://dev.to/snappy_tools/css-box-shadow-the-complete-guide-with-copy-paste-examples-3ggg</link>
      <guid>https://dev.to/snappy_tools/css-box-shadow-the-complete-guide-with-copy-paste-examples-3ggg</guid>
      <description>&lt;p&gt;The &lt;code&gt;box-shadow&lt;/code&gt; property sounds simple — but once you start layering shadows, building card elevation systems, or trying to recreate that exact Figma drop shadow in CSS, the syntax gets complicated fast.&lt;/p&gt;

&lt;p&gt;This guide covers everything from the basics to advanced multi-layer techniques, with copy-paste examples throughout.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Basic Syntax
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;offset-x&lt;/span&gt; &lt;span class="nt"&gt;offset-y&lt;/span&gt; &lt;span class="nt"&gt;blur-radius&lt;/span&gt; &lt;span class="nt"&gt;spread-radius&lt;/span&gt; &lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each part explained:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;offset-x&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Horizontal position. Positive = right, negative = left&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;offset-y&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Vertical position. Positive = down, negative = up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;blur-radius&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Edge softness. 0 = crisp, higher = more diffuse&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;spread-radius&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Expands (+) or contracts (−) the shadow before blur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Any valid CSS color, usually &lt;code&gt;rgba()&lt;/code&gt; for opacity control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A simple card shadow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inset Shadows
&lt;/h2&gt;

&lt;p&gt;Add the &lt;code&gt;inset&lt;/code&gt; keyword to flip the shadow inside the element — useful for pressed button states and recessed input fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Pressed button */&lt;/span&gt;
&lt;span class="nc"&gt;.btn&lt;/span&gt;&lt;span class="nd"&gt;:active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Recessed input field */&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multiple Shadow Layers
&lt;/h2&gt;

&lt;p&gt;You can stack multiple shadows with a comma-separated list. The first shadow is drawn on top (closest to the element):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="c"&gt;/* tight inner shadow for crispness */&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;6px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c"&gt;/* wide outer shadow for ambient depth */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This two-layer pattern mimics how real shadows work — a bright direct light source creates a sharp inner shadow, while ambient light creates a soft outer glow.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Four Elevation Levels
&lt;/h2&gt;

&lt;p&gt;Here's a practical elevation scale for UI design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Flat — default state */&lt;/span&gt;
&lt;span class="nc"&gt;.elevation-0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Subtle — cards, sections */&lt;/span&gt;
&lt;span class="nc"&gt;.elevation-1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Standard — hover state, dropdowns */&lt;/span&gt;
&lt;span class="nc"&gt;.elevation-2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Elevated — modals, dialogs */&lt;/span&gt;
&lt;span class="nc"&gt;.elevation-3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.14&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="m"&gt;48px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Glow Effects
&lt;/h2&gt;

&lt;p&gt;Set both offsets to &lt;code&gt;0&lt;/code&gt; and use a saturated colour for a glow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Green glow */&lt;/span&gt;
&lt;span class="nc"&gt;.btn-primary&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Stacked glow for stronger effect */&lt;/span&gt;
&lt;span class="nc"&gt;.notification-badge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;229&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;229&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using box-shadow as a Border
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;box-shadow&lt;/code&gt; can replace a &lt;code&gt;border&lt;/code&gt; without affecting layout — useful for focus rings and outlines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Focus ring that respects border-radius */&lt;/span&gt;
&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="nd"&gt;:focus-visible&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;outline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;153&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 2px green border without layout shift */&lt;/span&gt;
&lt;span class="nc"&gt;.selected-card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;#2f855a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Neumorphism
&lt;/h2&gt;

&lt;p&gt;The neumorphic trend uses two shadows in opposite directions on a matching background:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Element background must match --surface */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#e0e5ec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.neumorphic&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--surface&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;9px&lt;/span&gt; &lt;span class="m"&gt;9px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="m"&gt;#b8bec7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c"&gt;/* dark shadow — bottom-right */&lt;/span&gt;
    &lt;span class="m"&gt;-9px&lt;/span&gt; &lt;span class="m"&gt;-9px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* light shadow — top-left */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Pressed state */&lt;/span&gt;
&lt;span class="nc"&gt;.neumorphic&lt;/span&gt;&lt;span class="nd"&gt;:active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;#b8bec7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;-4px&lt;/span&gt; &lt;span class="m"&gt;-4px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Animating box-shadow
&lt;/h2&gt;

&lt;p&gt;Animating &lt;code&gt;box-shadow&lt;/code&gt; directly triggers a repaint on every frame. For smooth hover transitions, it's still acceptable for most UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;box-shadow&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt; &lt;span class="m"&gt;0.2s&lt;/span&gt; &lt;span class="n"&gt;ease&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:hover&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;translateY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;-2px&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For high-frequency animations (scroll-tied effects), animate &lt;code&gt;opacity&lt;/code&gt; on a &lt;code&gt;::after&lt;/code&gt; pseudo-element instead — this stays on the compositor layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  box-shadow vs filter: drop-shadow()
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;box-shadow&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;filter: drop-shadow()&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Follows&lt;/td&gt;
&lt;td&gt;Element's box&lt;/td&gt;
&lt;td&gt;Actual rendered shape&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports &lt;code&gt;inset&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Supports spread&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple layers&lt;/td&gt;
&lt;td&gt;✅ (comma list)&lt;/td&gt;
&lt;td&gt;❌ (wrap in multiple elements)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best for&lt;/td&gt;
&lt;td&gt;Buttons, cards, divs&lt;/td&gt;
&lt;td&gt;Transparent PNGs, SVGs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Converting Figma Shadows to CSS
&lt;/h2&gt;

&lt;p&gt;Figma's shadow panel maps directly to CSS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;X&lt;/strong&gt; → &lt;code&gt;offset-x&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Y&lt;/strong&gt; → &lt;code&gt;offset-y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blur&lt;/strong&gt; → &lt;code&gt;blur-radius&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spread&lt;/strong&gt; → &lt;code&gt;spread-radius&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colour + opacity&lt;/strong&gt; → &lt;code&gt;rgba()&lt;/code&gt; or &lt;code&gt;hsla()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Inner Shadow&lt;/strong&gt; → add &lt;code&gt;inset&lt;/code&gt; keyword&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Reference: Common Patterns
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Soft card */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;06&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;/* Material elevation 2 */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;12&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;08&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;/* Modal / dialog */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;32&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;20&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;64&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;10&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;/* Focus ring */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;3&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;66&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;153&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;225&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;/* Inset (pressed button) */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;inset&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;2&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;15&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="c"&gt;/* Neumorphic (on #e0e5ec background) */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;9&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;9&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;16&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nf"&gt;#b8bec7&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;-9px&lt;/span&gt; &lt;span class="nt"&gt;-9px&lt;/span&gt; &lt;span class="err"&gt;16&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nf"&gt;#ffffff&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* Remove shadow */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;none&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building Shadows Without Guessing
&lt;/h2&gt;

&lt;p&gt;If you'd rather adjust sliders than type raw CSS, the &lt;a href="https://snappytools.app/css-box-shadow-generator/" rel="noopener noreferrer"&gt;CSS Box Shadow Generator&lt;/a&gt; at SnappyTools gives you a live preview with multi-layer support, Figma-style controls, and a one-click copy button. No install, runs 100% in the browser.&lt;/p&gt;




&lt;p&gt;The key insight with &lt;code&gt;box-shadow&lt;/code&gt; is that single-layer shadows look flat. Stack a tight, slightly opaque shadow with a wider, more transparent one — and you get depth that actually looks right.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Open Graph Meta Tags: What They Are and How to Generate Them Correctly</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Mon, 15 Jun 2026 10:11:20 +0000</pubDate>
      <link>https://dev.to/snappy_tools/open-graph-meta-tags-what-they-are-and-how-to-generate-them-correctly-355o</link>
      <guid>https://dev.to/snappy_tools/open-graph-meta-tags-what-they-are-and-how-to-generate-them-correctly-355o</guid>
      <description>&lt;p&gt;When someone shares a link on Twitter/X, Facebook, LinkedIn, or Slack, you see a preview card with a title, description, and image. Those cards are powered by Open Graph meta tags — small HTML snippets in your page's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Getting them right is one of the highest-leverage quick wins in web development. A good social preview dramatically increases click-through rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core Tags
&lt;/h2&gt;

&lt;p&gt;At minimum, every page needs these four:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Your Page Title"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A 1–2 sentence description of the page."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yourdomain.com/og-image.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yourdomain.com/this-page/"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Four tags. That's it. They get you a functional preview on every major platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extended Tags Worth Adding
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Use "article" for blog posts, "product" for e-commerce --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:site_name"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Your Site Name"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Appears below the title on some platforms --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Makes Twitter use a large image preview instead of a small thumbnail --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Your Page Title"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A 1–2 sentence description."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://yourdomain.com/og-image.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;twitter:&lt;/code&gt; tags are separate because Twitter/X has its own spec. In practice, Twitter falls back to &lt;code&gt;og:&lt;/code&gt; tags when &lt;code&gt;twitter:&lt;/code&gt; tags are absent — but specifying both gives you more control over the Twitter card format.&lt;/p&gt;

&lt;h2&gt;
  
  
  The og:image Tag: Most Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Wrong size:&lt;/strong&gt; og:image should be at least 1200 × 630 pixels. Smaller images appear blurry or get cropped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relative URL:&lt;/strong&gt; The og:image value must be an absolute URL (&lt;code&gt;https://...&lt;/code&gt;). Relative paths (&lt;code&gt;/images/preview.jpg&lt;/code&gt;) don't work for social crawlers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Slow load:&lt;/strong&gt; Social platform crawlers time out quickly. Your og:image should load fast and be under 300 KB. JPEG works best for photographic images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aggressive caching:&lt;/strong&gt; Facebook and LinkedIn cache og:image heavily. After changing it, use their debugging tools (Facebook Sharing Debugger, LinkedIn Post Inspector) to force a re-scrape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifying Your Tags
&lt;/h2&gt;

&lt;p&gt;Every major platform has an official scraping tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Facebook:&lt;/strong&gt; developers.facebook.com/tools/debug/&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; linkedin.com/post-inspector/inspect/&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twitter/X:&lt;/strong&gt; Paste in Twitter cards validator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slack:&lt;/strong&gt; Just paste the URL into a Slack message — it unfurls automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These show you exactly what the platform sees, including which tags it picks up and what the preview will look like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dynamic OG Tags in Common Frameworks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Next.js (App Router):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;openGraph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Page description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://yourdomain.com/og-image.jpg&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;WordPress:&lt;/strong&gt; Yoast SEO generates OG tags automatically from your page title and featured image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static HTML:&lt;/strong&gt; Add the tags manually to each page's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the Tags
&lt;/h2&gt;

&lt;p&gt;Rather than writing the HTML by hand, &lt;a href="https://snappytools.app/og-meta-tag-generator/" rel="noopener noreferrer"&gt;SnappyTools has a free Open Graph Meta Tag Generator&lt;/a&gt; that lets you fill in a form, previews the card for Twitter/X, Facebook, and LinkedIn, and outputs the complete tag block to paste into your &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. No login, runs in your browser.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;tl;dr:&lt;/strong&gt; Four tags get you functional social previews everywhere. Add &lt;code&gt;twitter:card: summary_large_image&lt;/code&gt; for a large Twitter preview. Make your og:image 1200 × 630px, absolute HTTPS URL, under 300 KB.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>beginners</category>
      <category>html</category>
    </item>
    <item>
      <title>URL Slugs Explained: How to Write Clean, SEO-Friendly URLs Every Time</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Sun, 14 Jun 2026 15:45:22 +0000</pubDate>
      <link>https://dev.to/snappy_tools/url-slugs-explained-how-to-write-clean-seo-friendly-urls-every-time-2k0f</link>
      <guid>https://dev.to/snappy_tools/url-slugs-explained-how-to-write-clean-seo-friendly-urls-every-time-2k0f</guid>
      <description>&lt;p&gt;Every URL you publish is either working for you or against you. Most developers get this right by default — lowercase, hyphens, no garbage parameters. But a surprising number of sites still publish URLs like &lt;code&gt;/post?id=8472&lt;/code&gt; or &lt;code&gt;/2026/06/14/untitled-draft-final-v3-copy&lt;/code&gt;. This guide is about doing it right the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is a URL Slug?
&lt;/h2&gt;

&lt;p&gt;The slug is the human-readable part of a URL that identifies a specific page. In:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://snappytools.app/keyword-density-checker/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The slug is &lt;code&gt;keyword-density-checker&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A well-formed slug is lowercase, uses hyphens to separate words, and contains only the words that matter — no filler, no punctuation, no auto-generated noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Slugs Matter for SEO
&lt;/h2&gt;

&lt;p&gt;Google reads URLs as a signal. A slug that matches your target keyword tells the crawler exactly what the page is about before it even reads the content. It's a small signal, but every small signal adds up.&lt;/p&gt;

&lt;p&gt;More importantly: &lt;strong&gt;URLs appear in search results&lt;/strong&gt;. A clean slug like &lt;code&gt;/how-to-write-a-cover-letter/&lt;/code&gt; tells the user what they'll get before they click. A messy slug like &lt;code&gt;/p/46173&lt;/code&gt; tells them nothing. Click-through rates reflect this.&lt;/p&gt;

&lt;p&gt;Three practical rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Match the slug to your page's primary keyword phrase&lt;/li&gt;
&lt;li&gt;Use hyphens, never underscores (Google treats underscores as word joiners: &lt;code&gt;my_page&lt;/code&gt; reads as &lt;code&gt;mypage&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Remove stop words (a, an, the, and, or) unless they're essential to meaning&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Common Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Too long:&lt;/strong&gt; &lt;code&gt;/how-i-discovered-that-the-best-approach-to-writing-short-urls-is-to-remove-unnecessary-words/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Keep it under 5-6 words where possible. Trim everything that doesn't add meaning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auto-generated noise:&lt;/strong&gt; &lt;code&gt;/blog/2026/06/14/post-title-here-draft-revised-final/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Dates in URLs cause problems when content is evergreen — the URL signals the content is old even when the information is still current. Unless your content is explicitly time-sensitive (news, changelogs), skip the date.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyword stuffing:&lt;/strong&gt; &lt;code&gt;/free-best-online-keyword-density-tool-seo-checker-2026/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This looks manipulative and reads badly. One clear keyword phrase per slug, stated naturally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spaces encoded as &lt;code&gt;%20&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;/my%20blog%20post/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Always replace spaces with hyphens during URL generation. Most CMS platforms do this automatically, but if you're building custom routes, handle it explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Generate Good Slugs Programmatically
&lt;/h2&gt;

&lt;p&gt;The algorithm is simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;NFD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;// decompose accented chars&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;̀-ͯ&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// strip accent marks&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;// remove non-alphanumeric&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;           &lt;span class="c1"&gt;// spaces → hyphens&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-+/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           &lt;span class="c1"&gt;// collapse multiple hyphens&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;slugify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What Is a URL Slug? (Complete Guide)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// → "what-is-a-url-slug-complete-guide"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For production, you may also want to remove stop words:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STOP_WORDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;an&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;the&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;and&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;or&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;but&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;on&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;at&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;for&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;of&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;with&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;by&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;from&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;are&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;was&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;were&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;slugifyWithoutStopWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\s&lt;/span&gt;&lt;span class="sr"&gt;+/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;words&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;STOP_WORDS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;filtered&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;a-z0-9-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;slugifyWithoutStopWords&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;What Is a URL Slug and Why Does It Matter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// → "what-url-slug-why-does-matter"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether to strip stop words depends on the phrase. "How to write a blog post" without stop words becomes "write-blog-post" — shorter, but loses the "how to" intent signal that might matter for specific queries. Test before deciding.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Update a Slug
&lt;/h2&gt;

&lt;p&gt;Generally: don't. Changing a URL breaks incoming links, accumulated PageRank, and any bookmarks or social shares pointing at the old URL. If you must change it, set up a 301 redirect from the old URL to the new one immediately.&lt;/p&gt;

&lt;p&gt;The one exception: if a slug contains a time-bound keyword ("best-tools-2024") and you're updating the page annually, it's worth updating the slug and redirecting the old one. Just automate the redirect so you don't forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Checklist Before Publishing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Lowercase only&lt;/li&gt;
&lt;li&gt;[ ] Hyphens as word separators (not underscores, not spaces)&lt;/li&gt;
&lt;li&gt;[ ] Primary keyword included&lt;/li&gt;
&lt;li&gt;[ ] Stop words removed (unless they alter meaning)&lt;/li&gt;
&lt;li&gt;[ ] Under 60 characters&lt;/li&gt;
&lt;li&gt;[ ] No dates unless the content is time-sensitive&lt;/li&gt;
&lt;li&gt;[ ] No special characters, no percent-encoding&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tools That Help
&lt;/h2&gt;

&lt;p&gt;If you're working with keyword-heavy content and want to see whether your slug and page copy are using your target phrase at the right density, &lt;a href="https://snappytools.app/keyword-density-checker/" rel="noopener noreferrer"&gt;SnappyTools Keyword Density Checker&lt;/a&gt; runs entirely in-browser with no upload required. Paste your content, enter your keyword, and you get exact frequency counts and density percentage instantly.&lt;/p&gt;

&lt;p&gt;For content that goes into SEO-focused pages, &lt;a href="https://snappytools.app/word-counter/" rel="noopener noreferrer"&gt;SnappyTools Word Counter&lt;/a&gt; helps verify your content length and reading time before you publish.&lt;/p&gt;




&lt;p&gt;Getting slugs right is one of those foundation tasks that costs almost nothing to do well and consistently costs you if you get it wrong. Set up the slugify function once, apply it everywhere, and move on to the things that are harder to automate.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How Many Words Is [X] Characters? A Complete Reference Guide</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Sat, 13 Jun 2026 10:18:41 +0000</pubDate>
      <link>https://dev.to/snappy_tools/how-many-words-is-x-characters-a-complete-reference-guide-59ke</link>
      <guid>https://dev.to/snappy_tools/how-many-words-is-x-characters-a-complete-reference-guide-59ke</guid>
      <description>&lt;p&gt;One of the most common questions content writers, developers, and social media managers ask is: "how many words is [X] characters?" Whether you're hitting a tweet limit, filling out a meta description, or scoping out a writing project, understanding the character-to-word relationship is genuinely useful.&lt;/p&gt;

&lt;p&gt;Here's the complete reference, plus the rules that govern social platform limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Formula
&lt;/h2&gt;

&lt;p&gt;The standard English word is 4–5 characters long. Add one space between words, and you get roughly 5–6 characters per word. The most commonly used estimate:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;6 characters per word&lt;/strong&gt; (5-character average word + 1 space)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To convert: &lt;code&gt;characters ÷ 6 ≈ words&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This gives you a ballpark. Your actual count depends on writing style — conversational writing uses shorter words, technical writing uses longer ones. For an exact count, paste your text into a &lt;a href="https://snappytools.app/word-counter/" rel="noopener noreferrer"&gt;word counter&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Reference Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characters&lt;/th&gt;
&lt;th&gt;≈ Words&lt;/th&gt;
&lt;th&gt;Context&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;150&lt;/td&gt;
&lt;td&gt;~25&lt;/td&gt;
&lt;td&gt;Google meta description (mobile)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;155&lt;/td&gt;
&lt;td&gt;~26&lt;/td&gt;
&lt;td&gt;Google meta description (max safe)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200&lt;/td&gt;
&lt;td&gt;~33&lt;/td&gt;
&lt;td&gt;Short push notification&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;280&lt;/td&gt;
&lt;td&gt;~47&lt;/td&gt;
&lt;td&gt;Twitter/X post&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;300&lt;/td&gt;
&lt;td&gt;~50&lt;/td&gt;
&lt;td&gt;Short email reply&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;400&lt;/td&gt;
&lt;td&gt;~67&lt;/td&gt;
&lt;td&gt;Google Ads description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;~83&lt;/td&gt;
&lt;td&gt;LinkedIn update&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;600&lt;/td&gt;
&lt;td&gt;~100&lt;/td&gt;
&lt;td&gt;Short blog intro paragraph&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;700&lt;/td&gt;
&lt;td&gt;~117&lt;/td&gt;
&lt;td&gt;Two short paragraphs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;750&lt;/td&gt;
&lt;td&gt;~125&lt;/td&gt;
&lt;td&gt;Instagram caption (before truncation)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;850&lt;/td&gt;
&lt;td&gt;~142&lt;/td&gt;
&lt;td&gt;Brief product description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;~167&lt;/td&gt;
&lt;td&gt;Short FAQ answer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,200&lt;/td&gt;
&lt;td&gt;~200&lt;/td&gt;
&lt;td&gt;Short news article summary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,500&lt;/td&gt;
&lt;td&gt;~250&lt;/td&gt;
&lt;td&gt;App store description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1,700&lt;/td&gt;
&lt;td&gt;~283&lt;/td&gt;
&lt;td&gt;1-minute read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,000&lt;/td&gt;
&lt;td&gt;~333&lt;/td&gt;
&lt;td&gt;Brief article or newsletter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,500&lt;/td&gt;
&lt;td&gt;~417&lt;/td&gt;
&lt;td&gt;Medium-length FAQ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;td&gt;~500&lt;/td&gt;
&lt;td&gt;Short blog post, LinkedIn max&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4,000&lt;/td&gt;
&lt;td&gt;~667&lt;/td&gt;
&lt;td&gt;Typical how-to article section&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5,000&lt;/td&gt;
&lt;td&gt;~833&lt;/td&gt;
&lt;td&gt;3-minute read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6,000&lt;/td&gt;
&lt;td&gt;~1,000&lt;/td&gt;
&lt;td&gt;Standard blog post&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7,000&lt;/td&gt;
&lt;td&gt;~1,167&lt;/td&gt;
&lt;td&gt;Detailed tutorial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8,000&lt;/td&gt;
&lt;td&gt;~1,333&lt;/td&gt;
&lt;td&gt;Long-form article&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9,000&lt;/td&gt;
&lt;td&gt;~1,500&lt;/td&gt;
&lt;td&gt;Pillar content / long post&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10,000&lt;/td&gt;
&lt;td&gt;~1,667&lt;/td&gt;
&lt;td&gt;Long-form guide&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12,000&lt;/td&gt;
&lt;td&gt;~2,000&lt;/td&gt;
&lt;td&gt;8-minute read&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Platform-Specific Limits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Twitter / X
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Posts: &lt;strong&gt;280 characters&lt;/strong&gt; (≈ 47 words)&lt;/li&gt;
&lt;li&gt;Bio: &lt;strong&gt;160 characters&lt;/strong&gt; (≈ 27 words)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  LinkedIn
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Posts: &lt;strong&gt;3,000 characters&lt;/strong&gt; (≈ 500 words)&lt;/li&gt;
&lt;li&gt;Posts truncate in feed after ~210 characters — lead with a hook&lt;/li&gt;
&lt;li&gt;Bio/About: &lt;strong&gt;2,600 characters&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Instagram
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Captions: &lt;strong&gt;2,200 characters&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Captions truncate after &lt;strong&gt;125 characters&lt;/strong&gt; in feed — lead with the important part&lt;/li&gt;
&lt;li&gt;Hashtags count toward the limit&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Meta Descriptions (SEO)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Google truncates at roughly &lt;strong&gt;155–160 characters&lt;/strong&gt; on desktop&lt;/li&gt;
&lt;li&gt;Mobile may truncate earlier, around &lt;strong&gt;120 characters&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Optimal range: &lt;strong&gt;120–155 characters&lt;/strong&gt; (≈ 20–26 words)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Page Titles (SEO)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Google typically shows &lt;strong&gt;50–60 characters&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Optimal range: &lt;strong&gt;50–60 characters&lt;/strong&gt; (≈ 8–10 words)&lt;/li&gt;
&lt;li&gt;Titles longer than 60 characters get cut off with "..."&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Facebook
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Posts: &lt;strong&gt;63,206 characters&lt;/strong&gt; (no practical content limit)&lt;/li&gt;
&lt;li&gt;Post truncate in feed after ~480 characters&lt;/li&gt;
&lt;li&gt;Ad headline: &lt;strong&gt;40 characters&lt;/strong&gt; recommended&lt;/li&gt;
&lt;li&gt;Ad description: &lt;strong&gt;125 characters&lt;/strong&gt; before truncation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  YouTube
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Video descriptions: &lt;strong&gt;5,000 characters&lt;/strong&gt; (≈ 833 words)&lt;/li&gt;
&lt;li&gt;Only the first &lt;strong&gt;100–150 characters&lt;/strong&gt; show without clicking "Show more"&lt;/li&gt;
&lt;li&gt;Channel description: &lt;strong&gt;1,000 characters&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Email (Subject Lines)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Gmail/Outlook preview: &lt;strong&gt;60 characters&lt;/strong&gt; on desktop, &lt;strong&gt;30–40&lt;/strong&gt; on mobile&lt;/li&gt;
&lt;li&gt;Optimal subject line: &lt;strong&gt;40–50 characters&lt;/strong&gt; (≈ 7–8 words)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reading Time Estimates
&lt;/h2&gt;

&lt;p&gt;These assume an average reading speed of 225 words per minute:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Characters&lt;/th&gt;
&lt;th&gt;Words&lt;/th&gt;
&lt;th&gt;Reading Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1,350&lt;/td&gt;
&lt;td&gt;~225&lt;/td&gt;
&lt;td&gt;1 minute&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2,700&lt;/td&gt;
&lt;td&gt;~450&lt;/td&gt;
&lt;td&gt;2 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3,600&lt;/td&gt;
&lt;td&gt;~600&lt;/td&gt;
&lt;td&gt;~2.5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4,500&lt;/td&gt;
&lt;td&gt;~750&lt;/td&gt;
&lt;td&gt;~3 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6,750&lt;/td&gt;
&lt;td&gt;~1,125&lt;/td&gt;
&lt;td&gt;5 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13,500&lt;/td&gt;
&lt;td&gt;~2,250&lt;/td&gt;
&lt;td&gt;10 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  When You Need an Exact Count
&lt;/h2&gt;

&lt;p&gt;The formula is useful for estimating, but for real work you need exact counts. Paste your content into the &lt;a href="https://snappytools.app/word-counter/" rel="noopener noreferrer"&gt;free Word Counter&lt;/a&gt; and you'll see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Word count&lt;/li&gt;
&lt;li&gt;Character count (with and without spaces)&lt;/li&gt;
&lt;li&gt;Sentence and paragraph count&lt;/li&gt;
&lt;li&gt;Estimated reading time&lt;/li&gt;
&lt;li&gt;Platform-specific limits (Twitter/X, meta descriptions, LinkedIn, Instagram, and more) highlighted in real-time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works entirely in your browser — no paste-and-lose-your-text, no account required.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tools</category>
    </item>
    <item>
      <title>Open Graph Tags Explained: Control How Your Pages Look When Shared</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Fri, 12 Jun 2026 10:17:35 +0000</pubDate>
      <link>https://dev.to/snappy_tools/open-graph-tags-explained-control-how-your-pages-look-when-shared-4lnb</link>
      <guid>https://dev.to/snappy_tools/open-graph-tags-explained-control-how-your-pages-look-when-shared-4lnb</guid>
      <description>&lt;p&gt;Every time someone shares a link on Twitter/X, LinkedIn, or Slack, a card appears with an image, title, and description. That card is controlled by Open Graph meta tags — and if you don't set them, the social platform guesses, usually badly.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are Open Graph tags?
&lt;/h2&gt;

&lt;p&gt;Open Graph (OG) is a protocol invented by Facebook that lets you control the "preview card" for your page when shared on social networks. You add &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; tags to your page's &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, and social platforms read them when generating the link preview.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My Page Title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"A one-sentence summary of the page."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/og-image.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/my-page/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:site_name"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My Site"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The minimum required set
&lt;/h2&gt;

&lt;p&gt;These four tags are the most important:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Recommended&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;og:title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Card headline&lt;/td&gt;
&lt;td&gt;Under 60 chars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;og:description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Subtitle text&lt;/td&gt;
&lt;td&gt;Under 155 chars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;og:image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview image&lt;/td&gt;
&lt;td&gt;1200×630px min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;og:url&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Canonical URL of the page&lt;/td&gt;
&lt;td&gt;Full absolute URL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Without &lt;code&gt;og:image&lt;/code&gt;, most platforms either show nothing or scrape a random image from the page. Always provide one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Twitter-specific tags
&lt;/h2&gt;

&lt;p&gt;Twitter/X uses Open Graph as a fallback but has its own tags for finer control:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"My Page Title"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Short summary here."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/og-image.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;twitter:card&lt;/code&gt; has two common values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;summary_large_image&lt;/code&gt; — wide image above title (most common)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;summary&lt;/code&gt; — small square thumbnail to the left of title&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Image size and format
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Recommended&lt;/strong&gt;: 1200×630px (Facebook, Twitter, LinkedIn)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimum&lt;/strong&gt;: 600×315px (lower quality but works)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format&lt;/strong&gt;: JPEG for photos, PNG for graphics with text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File size&lt;/strong&gt;: under 1MB for fast load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Twitter has a 5MB hard limit. LinkedIn accepts JPG, PNG, and GIF.&lt;/p&gt;

&lt;h2&gt;
  
  
  Article-specific tags
&lt;/h2&gt;

&lt;p&gt;For blog posts, add &lt;code&gt;og:type&lt;/code&gt; and the article properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"article"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"article:author"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"article:published_time"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"2026-06-12T10:00:00Z"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For most pages (landing pages, tools, product pages), &lt;code&gt;og:type&lt;/code&gt; should be &lt;code&gt;website&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your tags
&lt;/h2&gt;

&lt;p&gt;After deploying your OG tags, validate them with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Facebook&lt;/strong&gt;: developers.facebook.com/tools/debug/&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Twitter/X&lt;/strong&gt;: cards-dev.twitter.com/validator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn&lt;/strong&gt;: linkedin.com/post-inspector/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tools show exactly what the card looks like and flag any missing required tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Relative URLs for &lt;code&gt;og:image&lt;/code&gt;&lt;/strong&gt;: always use absolute URLs including &lt;code&gt;https://&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Missing &lt;code&gt;og:url&lt;/code&gt;&lt;/strong&gt;: without this, some platforms generate duplicate entries in their cache&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Title too long&lt;/strong&gt;: over 60 chars gets truncated with "…" in most platforms&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No image&lt;/strong&gt;: guaranteed poor-looking share — provide one even if it's just a branded default&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tools
&lt;/h2&gt;

&lt;p&gt;Rather than writing tags from scratch, use a generator to fill in the fields and see a live preview before deploying. The &lt;a href="https://snappytools.app/og-meta-tag-generator/" rel="noopener noreferrer"&gt;OG Meta Tag Generator at SnappyTools&lt;/a&gt; lets you enter your title, description, image URL, and page URL, then shows you what the Twitter card, Facebook card, and LinkedIn card will look like — all in the browser, no URL required.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>CSS box-shadow: The Complete Guide to Multi-Layer Shadows</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Fri, 12 Jun 2026 10:14:49 +0000</pubDate>
      <link>https://dev.to/snappy_tools/css-box-shadow-the-complete-guide-to-multi-layer-shadows-2ini</link>
      <guid>https://dev.to/snappy_tools/css-box-shadow-the-complete-guide-to-multi-layer-shadows-2ini</guid>
      <description>&lt;p&gt;The &lt;code&gt;box-shadow&lt;/code&gt; property is one of the most underused tools in CSS. Most developers use it for a single subtle drop shadow and stop there — but the full syntax supports layered shadows, inset effects, and colour-based glows that can replace entire images.&lt;/p&gt;

&lt;p&gt;This guide covers everything from the basic syntax to advanced multi-layer techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  The full syntax
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;inset&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;offset-x&lt;/span&gt; &lt;span class="nt"&gt;offset-y&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;blur-radius&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;spread-radius&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each part:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;offset-x&lt;/strong&gt; — horizontal distance. Positive = right, negative = left.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;offset-y&lt;/strong&gt; — vertical distance. Positive = down, negative = up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;blur-radius&lt;/strong&gt; — how soft the edge is. &lt;code&gt;0&lt;/code&gt; = crisp edge, &lt;code&gt;20px&lt;/code&gt; = soft fade. Cannot be negative.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;spread-radius&lt;/strong&gt; — expands (+) or contracts (-) the shadow beyond the element size.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;color&lt;/strong&gt; — usually &lt;code&gt;rgba()&lt;/code&gt; so you can control opacity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;inset&lt;/strong&gt; — optional keyword that puts the shadow inside the element.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why rgba() for colour?
&lt;/h2&gt;

&lt;p&gt;Most shadow colours are variations of black with opacity. &lt;code&gt;rgba(0, 0, 0, 0.12)&lt;/code&gt; gives you black at 12% opacity — the element behind shows through, making the shadow look natural regardless of background colour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Avoid this — opaque black shadow looks fake */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;#000000&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* Do this — transparent shadow works on any background */&lt;/span&gt;
&lt;span class="nt"&gt;box-shadow&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt; &lt;span class="err"&gt;4&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="err"&gt;8&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;rgba&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="err"&gt;0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="err"&gt;12&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multiple shadows: the real power
&lt;/h2&gt;

&lt;p&gt;Separate shadows with commas. The first shadow is drawn on top (closest to the element):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.12&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c"&gt;/* tight shadow for sharpness */&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.08&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c"&gt;/* wide shadow for ambient depth */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This two-layer pattern is the basis of Material Design's elevation system. Each layer doubles in size while halving in opacity — the result looks like physically accurate depth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inset shadows
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;inset&lt;/code&gt; keyword flips the shadow inside the element. This is perfect for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Buttons in their active/pressed state&lt;/li&gt;
&lt;li&gt;Input fields with a focus ring&lt;/li&gt;
&lt;li&gt;Recessed UI surfaces
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Pressed button effect */&lt;/span&gt;
&lt;span class="nc"&gt;.btn&lt;/span&gt;&lt;span class="nd"&gt;:active&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;inset&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Input focus ring */&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;3px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;153&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;225&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  box-shadow as a border
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;box-shadow: 0 0 0 2px #2f855a&lt;/code&gt; creates a 2px ring identical to a border — but without affecting layout. Unlike &lt;code&gt;outline&lt;/code&gt;, it respects &lt;code&gt;border-radius&lt;/code&gt; exactly.&lt;/p&gt;

&lt;p&gt;Useful for stacking multiple rings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.card&lt;/span&gt;&lt;span class="nd"&gt;:focus&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;2px&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c"&gt;/* inner white gap */&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;4px&lt;/span&gt; &lt;span class="m"&gt;#2f855a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;       &lt;span class="c"&gt;/* outer green ring */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Glow effects
&lt;/h2&gt;

&lt;p&gt;Zero offset + large blur + saturated colour = glow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.btn-primary&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-shadow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;32px&lt;/span&gt; &lt;span class="n"&gt;rgba&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;133&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;90&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common preset values
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;th&gt;CSS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Soft card&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 2px 8px rgba(0,0,0,0.08)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Material card&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 1px 3px rgba(0,0,0,0.12), 0 2px 4px rgba(0,0,0,0.08)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Floating modal&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 8px 24px rgba(0,0,0,0.14), 0 16px 48px rgba(0,0,0,0.08)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Focus ring&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0 0 0 3px rgba(66,153,225,0.5)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pressed inset&lt;/td&gt;
&lt;td&gt;&lt;code&gt;inset 0 2px 6px rgba(0,0,0,0.2)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Performance note
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;box-shadow&lt;/code&gt; triggers repaint, not reflow. For static use it is fast — most GPUs handle it without any measurable impact. For animated shadows, add &lt;code&gt;will-change: box-shadow&lt;/code&gt; or animate via &lt;code&gt;transform&lt;/code&gt; + a static shadow on a pseudo-element for smoother 60fps results.&lt;/p&gt;




&lt;p&gt;If you want to build shadows visually without writing code, try the &lt;a href="https://snappytools.app/css-box-shadow-generator/" rel="noopener noreferrer"&gt;CSS Box Shadow Generator&lt;/a&gt; — it gives you sliders for every parameter, a live preview card, 5 presets, and copies the complete CSS with one click.&lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Formatted SQL Is Worth the Extra Keystrokes</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:15:11 +0000</pubDate>
      <link>https://dev.to/snappy_tools/why-formatted-sql-is-worth-the-extra-keystrokes-2nj4</link>
      <guid>https://dev.to/snappy_tools/why-formatted-sql-is-worth-the-extra-keystrokes-2nj4</guid>
      <description>&lt;p&gt;Unformatted SQL is a maintenance hazard. A single query stretching across 300 characters with no line breaks is hard to read in a code review, nearly impossible to debug in a log file, and a nightmare to modify six months later.&lt;/p&gt;

&lt;p&gt;Formatting SQL costs nothing and saves significant time. Here's why it matters and what consistent formatting looks like.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "Formatted SQL" Actually Means
&lt;/h2&gt;

&lt;p&gt;Formatted SQL doesn't mean anything fancy — it's just consistent whitespace, capitalisation, and alignment that makes the structure of a query visible at a glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="k"&gt;left&lt;/span&gt; &lt;span class="k"&gt;join&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt; &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'completed'&lt;/span&gt; &lt;span class="k"&gt;order&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;desc&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'2024-01-01'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'completed'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The query is identical — the database doesn't care about whitespace. But the second version makes the joins, conditions, and selected columns immediately scannable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Code Review Argument
&lt;/h2&gt;

&lt;p&gt;SQL in code reviews is often the most poorly reviewed part of a pull request. Reviewers skim past a wall of unformatted SQL because parsing its structure mentally is too much cognitive work. Formatted SQL gets reviewed properly because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can see at a glance which tables are joined and how&lt;/li&gt;
&lt;li&gt;You can spot missing index conditions in the WHERE clause&lt;/li&gt;
&lt;li&gt;You can identify whether SELECT * is being used (it shouldn't be)&lt;/li&gt;
&lt;li&gt;You can check that joins have explicit conditions on the right columns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A reviewer who can read your SQL quickly is more likely to catch bugs — a suboptimal join condition, a missing NULL check, a Cartesian product hiding in a FROM clause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capitalisation Conventions
&lt;/h2&gt;

&lt;p&gt;There are two camps:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPPERCASE keywords&lt;/strong&gt; — &lt;code&gt;SELECT&lt;/code&gt;, &lt;code&gt;FROM&lt;/code&gt;, &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;JOIN&lt;/code&gt;. The traditional SQL style, still the most common in professional environments and documentation. Makes keywords visually distinct from table/column names.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lowercase keywords&lt;/strong&gt; — &lt;code&gt;select&lt;/code&gt;, &lt;code&gt;from&lt;/code&gt;, &lt;code&gt;where&lt;/code&gt;, &lt;code&gt;join&lt;/code&gt;. Preferred by some modern teams, particularly those writing SQL inside application code (Python SQLAlchemy, JavaScript knex.js) where all-caps feels like shouting.&lt;/p&gt;

&lt;p&gt;Pick one and stick to it. The worst option is inconsistency — some queries in uppercase, some in lowercase, mixed within the same file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indentation Rules That Actually Help
&lt;/h2&gt;

&lt;p&gt;The goal of SQL indentation is to make the &lt;em&gt;logical structure&lt;/em&gt; of the query visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Main clauses at the left margin&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
  &lt;span class="n"&gt;column1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;-- Selected columns indented one level&lt;/span&gt;
  &lt;span class="n"&gt;column2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;column3&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;primary_table&lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;secondary_table&lt;/span&gt;
  &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;primary_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secondary_table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fk_id&lt;/span&gt;   &lt;span class="c1"&gt;-- JOIN conditions indented&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;condition1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'value'&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;condition2&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;                             &lt;span class="c1"&gt;-- AND/OR conditions aligned&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sub_condition1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;                           &lt;span class="c1"&gt;-- Grouped conditions indented further&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;sub_condition2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;column1&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The structure tells you: what am I selecting, from where, joined to what, filtered how, sorted how. You shouldn't need to read every word to understand the shape of the query.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Formatting Mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Putting everything on one line.&lt;/strong&gt; The database doesn't care, but your future self will hate you for it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mixing alignment styles.&lt;/strong&gt; If you indent JOIN conditions, indent all JOIN conditions. Inconsistency in the same query is more confusing than no indentation at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No spaces around operators.&lt;/strong&gt; &lt;code&gt;WHERE id=5&lt;/code&gt; is harder to read than &lt;code&gt;WHERE id = 5&lt;/code&gt;. Always space around &lt;code&gt;=&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;!=&lt;/code&gt;, &lt;code&gt;LIKE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not aliasing tables.&lt;/strong&gt; &lt;code&gt;FROM very_long_table_name JOIN another_long_table_name ON very_long_table_name.id = another_long_table_name.fk&lt;/code&gt; is hard to read. Use aliases: &lt;code&gt;FROM orders o JOIN users u ON o.user_id = u.id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Forgetting the semicolon.&lt;/strong&gt; In multi-statement scripts, missing semicolons cause silent failures. Get in the habit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatting Tools
&lt;/h2&gt;

&lt;p&gt;You don't have to format SQL by hand. Most SQL IDEs (DataGrip, DBeaver, VS Code with SQLTools) have built-in formatters. For quick formatting of a query you've copied from a log or a colleague's message, the &lt;a href="https://snappytools.app/sql-formatter-beautifier/" rel="noopener noreferrer"&gt;SQL Formatter &amp;amp; Beautifier at SnappyTools&lt;/a&gt; handles MySQL, PostgreSQL, and Transact-SQL in the browser — paste your query, click Format, copy the result.&lt;/p&gt;

&lt;p&gt;Useful for one-off formatting without leaving your current context.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Note on Dialects
&lt;/h2&gt;

&lt;p&gt;SQL syntax varies between databases. Standard formatting rules apply universally, but some syntax is dialect-specific:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MySQL&lt;/strong&gt;: backtick quoting for identifiers &lt;code&gt;`table_name`&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL&lt;/strong&gt;: double-quote identifiers &lt;code&gt;"table_name"&lt;/code&gt;, strong adherence to SQL standard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transact-SQL (SQL Server)&lt;/strong&gt;: bracket quoting &lt;code&gt;[table_name]&lt;/code&gt;, &lt;code&gt;TOP&lt;/code&gt; instead of &lt;code&gt;LIMIT&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're writing SQL that will run on multiple databases, stick to standard SQL where possible and make the dialect explicit in comments or filenames.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Formatted SQL is professional SQL. It signals that you thought about the query carefully enough to make it readable, which is a reliable indicator that you also thought about whether it's correct and performant.&lt;/p&gt;

&lt;p&gt;The next time you're about to paste a single-line query into a code review, spend 30 seconds formatting it first. Your reviewers will thank you — and your future self will too.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tools</category>
    </item>
    <item>
      <title>YAML vs JSON: When to Use Each (and When They're Interchangeable)</title>
      <dc:creator>Snappy Tools</dc:creator>
      <pubDate>Thu, 11 Jun 2026 10:11:21 +0000</pubDate>
      <link>https://dev.to/snappy_tools/yaml-vs-json-when-to-use-each-and-when-theyre-interchangeable-4g6d</link>
      <guid>https://dev.to/snappy_tools/yaml-vs-json-when-to-use-each-and-when-theyre-interchangeable-4g6d</guid>
      <description>&lt;p&gt;YAML and JSON represent the same data structures. Both support strings, numbers, booleans, arrays, and nested objects. Both are widely used for configuration and data interchange. So why do both exist, and when should you choose one over the other?&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the Difference?
&lt;/h2&gt;

&lt;p&gt;At a structural level, YAML is a superset of JSON — valid JSON is valid YAML. But in practice, YAML's syntax is designed for human readability while JSON's is designed for machine parsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SnappyTools"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"fast"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"no-signup"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"config"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maxRetries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"timeout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The same data in YAML:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SnappyTools&lt;/span&gt;
&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1.0"&lt;/span&gt;
&lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;fast&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;free&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;no-signup&lt;/span&gt;
&lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;maxRetries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The YAML version is shorter and has no curly braces, no commas, and no quotes unless necessary. For configuration files that humans edit frequently, this matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use JSON
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;APIs and HTTP responses&lt;/strong&gt; — JSON is the standard for REST APIs. All HTTP clients handle it natively. It's faster to parse than YAML and has a simpler, unambiguous spec.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data interchange between systems&lt;/strong&gt; — JSON is the lowest common denominator. Every language has a fast, well-tested JSON parser. YAML parsers are more complex and vary in behaviour between implementations (more on this below).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When you don't control both ends&lt;/strong&gt; — If you're sending data to an external service, use JSON. YAML's flexibility (implicit type coercion, aliases, multiple document support) can cause unexpected behaviour when parsed by a library you didn't configure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Structured data files where humans won't edit them&lt;/strong&gt; — package-lock.json, composer.lock, database exports: these are machine-written and machine-read. JSON is the right choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use YAML
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Configuration files&lt;/strong&gt; — Kubernetes manifests, Docker Compose, GitHub Actions workflows, Ansible playbooks, CI/CD configs. These are written once and edited frequently by humans. YAML's clean syntax reduces friction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-line strings&lt;/strong&gt; — YAML handles multi-line strings elegantly with block scalars. This is painful in JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# YAML block scalar — no escaping needed&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;This is a long description.&lt;/span&gt;
  &lt;span class="s"&gt;It spans multiple lines.&lt;/span&gt;
  &lt;span class="s"&gt;No escape sequences needed.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In JSON, the same thing requires &lt;code&gt;\n&lt;/code&gt; escape sequences and double quotes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Comments&lt;/strong&gt; — YAML supports comments (&lt;code&gt;#&lt;/code&gt;). JSON does not. For configuration files, being able to explain why a setting exists is invaluable. This alone makes YAML preferred for config files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hierarchical configuration&lt;/strong&gt; — Deep nesting is more readable in YAML than in deeply-nested JSON objects with closing braces on every line.&lt;/p&gt;

&lt;h2&gt;
  
  
  YAML Gotchas to Know
&lt;/h2&gt;

&lt;p&gt;YAML's flexibility creates some notorious pitfalls:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Norway Problem&lt;/strong&gt; — YAML 1.1 (still used by many parsers) interprets bare &lt;code&gt;NO&lt;/code&gt;, &lt;code&gt;N&lt;/code&gt;, &lt;code&gt;Off&lt;/code&gt;, &lt;code&gt;False&lt;/code&gt; as boolean false. This means country codes like &lt;code&gt;NO&lt;/code&gt; (Norway) get silently converted to &lt;code&gt;false&lt;/code&gt;. YAML 1.2 fixed this, but not all parsers have updated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Implicit type coercion&lt;/strong&gt; — &lt;code&gt;version: 1.0&lt;/code&gt; in YAML becomes a float, &lt;code&gt;version: "1.0"&lt;/code&gt; stays a string. &lt;code&gt;port: 8080&lt;/code&gt; becomes an integer. This is convenient but can surprise you when your port number becomes an integer in a context expecting a string.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tabs vs spaces&lt;/strong&gt; — YAML forbids tabs for indentation. Python developers familiar with spaces-only indentation are used to this, but it trips up others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;String ambiguity&lt;/strong&gt; — &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;yes&lt;/code&gt;, &lt;code&gt;on&lt;/code&gt; are all booleans in YAML 1.1. To be safe with values that look like keywords, quote them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Converting Between the Two
&lt;/h2&gt;

&lt;p&gt;If you're working with a tool that outputs JSON but your config expects YAML (or vice versa), you need a converter. The &lt;a href="https://snappytools.app/yaml-json-converter/" rel="noopener noreferrer"&gt;YAML ↔ JSON Converter at SnappyTools&lt;/a&gt; handles both directions instantly in the browser — paste JSON to get YAML, paste YAML to get JSON. Useful when translating Kubernetes examples to Docker Compose format, or converting API responses to config file format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Decision Guide
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;REST API response&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CI/CD config (GitHub Actions, CircleCI)&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Kubernetes manifest&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm/package.json&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker Compose&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database export/import&lt;/td&gt;
&lt;td&gt;JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ansible playbook&lt;/td&gt;
&lt;td&gt;YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OpenAPI / Swagger spec&lt;/td&gt;
&lt;td&gt;Either (JSON more common in generated code)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human-edited config file&lt;/td&gt;
&lt;td&gt;YAML (comments + readability)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Machine-generated data file&lt;/td&gt;
&lt;td&gt;JSON (simpler parser, less ambiguity)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The general rule: &lt;strong&gt;YAML for humans writing configuration, JSON for machines exchanging data.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>beginners</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
