<?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: Theo</title>
    <description>The latest articles on DEV Community by Theo (@theosoti).</description>
    <link>https://dev.to/theosoti</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%2F3158436%2Fa717e2f7-d45d-45e1-abf0-0993be3cf94c.png</url>
      <title>DEV Community: Theo</title>
      <link>https://dev.to/theosoti</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theosoti"/>
    <language>en</language>
    <item>
      <title>I built a scanner to find JavaScript that modern CSS can replace</title>
      <dc:creator>Theo</dc:creator>
      <pubDate>Mon, 10 Aug 2026 16:35:01 +0000</pubDate>
      <link>https://dev.to/theosoti/i-built-a-scanner-to-find-javascript-that-modern-css-can-replace-1pn5</link>
      <guid>https://dev.to/theosoti/i-built-a-scanner-to-find-javascript-that-modern-css-can-replace-1pn5</guid>
      <description>&lt;p&gt;I spend a lot of time writing about CSS features that replace small pieces of JavaScript. The examples are usually easy to understand in isolation. Finding the same opportunity inside a real website is much harder.&lt;/p&gt;

&lt;p&gt;A dropdown may be buried in a minified bundle. A modal may be a fixed &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with a home-made focus trap. A reveal animation may only exist after you scroll halfway down the page.&lt;/p&gt;

&lt;p&gt;I wanted to paste in a URL and get a useful answer to one question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which parts of this page could use native HTML or modern CSS instead?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So I built &lt;a href="https://cssradar.com/" rel="noopener noreferrer"&gt;CSS Radar&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A class name is not evidence
&lt;/h2&gt;

&lt;p&gt;My first concern was false positives.&lt;/p&gt;

&lt;p&gt;Finding &lt;code&gt;.modal&lt;/code&gt; in a stylesheet proves very little. It might be an image, a legacy rule that no longer matches anything, or a non-modal panel with an unfortunate name. The same problem applies to classes like &lt;code&gt;.dropdown&lt;/code&gt;, &lt;code&gt;.accordion&lt;/code&gt;, and &lt;code&gt;.reveal&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The scanner renders one public page in Chromium. It scrolls through the whole page, hovers controls, and clicks interactions that it can test safely. Form submissions, navigation, and downloads are blocked.&lt;/p&gt;

&lt;p&gt;It also collects the relevant HTML, CSS, and JavaScript around each candidate. A finding is only published when the captured evidence matches a replacement the scanner knows how to verify.&lt;/p&gt;

&lt;p&gt;That makes it conservative. I prefer a missed opportunity to a report full of guesses.&lt;/p&gt;

&lt;h2&gt;
  
  
  A custom modal can become &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Here is a familiar modal setup:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"dialog"&lt;/span&gt; &lt;span class="na"&gt;aria-modal=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;hidden&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"modal__close"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Modal content&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;trigger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;modal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;trapFocus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;modal&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;The code is not necessarily bad. It just rebuilds behavior the browser now provides.&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;button&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"show-modal"&lt;/span&gt; &lt;span class="na"&gt;commandfor=&lt;/span&gt;&lt;span class="s"&gt;"settings-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  Open settings
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"settings-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Modal content&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;command=&lt;/span&gt;&lt;span class="s"&gt;"close"&lt;/span&gt; &lt;span class="na"&gt;commandfor=&lt;/span&gt;&lt;span class="s"&gt;"settings-dialog"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Close
  &lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; gives you modal semantics, the top layer, focus handling, Escape dismissal, and &lt;code&gt;::backdrop&lt;/code&gt;. The newer &lt;code&gt;command&lt;/code&gt; and &lt;code&gt;commandfor&lt;/code&gt; attributes can even connect the buttons without a click listener in supporting browsers.&lt;/p&gt;

&lt;p&gt;This is the kind of finding CSS Radar can verify from several pieces of evidence: &lt;code&gt;aria-modal="true"&lt;/code&gt;, the fixed overlay, its hidden state, and the code that opens it.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/theosoti/embed/WbvJXvZ?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  A class-toggled menu can become a popover
&lt;/h2&gt;

&lt;p&gt;This pattern is everywhere:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"language-selector"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"selector-button"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Language&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"language-menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/fr"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;French&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;open&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.language-menu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&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;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="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.language-selector.open&lt;/span&gt; &lt;span class="nc"&gt;.language-menu&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&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;A modern version can use a real button and the Popover API:&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;button&lt;/span&gt; &lt;span class="na"&gt;popovertarget=&lt;/span&gt;&lt;span class="s"&gt;"language-menu"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Language&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;nav&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"language-menu"&lt;/span&gt; &lt;span class="na"&gt;popover&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/fr"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;French&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Popover handles opening, Escape, light dismissal, and the top layer. CSS Anchor Positioning can attach the menu to its button when you need more control over placement.&lt;/p&gt;

&lt;p&gt;The awkward part for a scanner is that real sites do not always use buttons. Sometimes the trigger is a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; with a click listener. Clicking every &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; on a page would be reckless, so CSS Radar only tests a non-semantic trigger when the surrounding structure or behavior gives it a concrete reason.&lt;/p&gt;

&lt;p&gt;That rule came from debugging a missed language selector. The scanner saw the &lt;code&gt;open&lt;/code&gt; class and initially treated it like an accordion. Watching the menu become an out-of-flow panel made the correct replacement much clearer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some scroll reveals no longer need an observer
&lt;/h2&gt;

&lt;p&gt;Another common pattern uses &lt;code&gt;IntersectionObserver&lt;/code&gt; to add a class when an element enters the viewport:&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;observer&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;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for &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;entry&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;entries&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&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-visible&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;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.reveal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;observer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;element&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 a decorative entry animation, a view timeline can often do the job in CSS:&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;.reveal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reveal&lt;/span&gt; &lt;span class="n"&gt;linear&lt;/span&gt; &lt;span class="nb"&gt;both&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;animation-timeline&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="py"&gt;animation-range&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="m"&gt;0%&lt;/span&gt; &lt;span class="n"&gt;cover&lt;/span&gt; &lt;span class="m"&gt;30%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@keyframes&lt;/span&gt; &lt;span class="n"&gt;reveal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;from&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="py"&gt;translate&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;2rem&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;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-reduced-motion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.reveal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;animation&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This recommendation only makes sense when the observer controls presentation. If the callback loads data, changes application state, or records a business event, CSS is not a replacement.&lt;/p&gt;

&lt;p&gt;That difference is why the scanner looks for both the viewport observation and a matching visual mutation on the same element.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the report contains
&lt;/h2&gt;

&lt;p&gt;The report does not rewrite the website. I do not think an automated tool should silently replace interaction code after spotting one pattern.&lt;/p&gt;

&lt;p&gt;Instead, each finding shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the element or selector that matched&lt;/li&gt;
&lt;li&gt;the captured code that drives it&lt;/li&gt;
&lt;li&gt;a possible native replacement&lt;/li&gt;
&lt;li&gt;current browser support&lt;/li&gt;
&lt;li&gt;what to verify before shipping the change&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When I have a matching example from my book, I also link to the CodePen. That gives you something working to inspect before touching production code.&lt;/p&gt;

&lt;p&gt;The scanner also catches smaller CSS opportunities such as paired physical spacing declarations that can become logical properties. Repeated occurrences are grouped into one finding because six cards that all say &lt;code&gt;padding-top&lt;/code&gt; plus &lt;code&gt;padding-bottom&lt;/code&gt; should become &lt;code&gt;padding-block&lt;/code&gt; are not six different ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cannot tell you
&lt;/h2&gt;

&lt;p&gt;CSS Radar scans one public page. It cannot enter an account or reach a component hidden behind an application-specific workflow. A component may also appear on another route and never exist on the page you submit.&lt;/p&gt;

&lt;p&gt;It is not a security, performance, or accessibility audit. Native HTML often removes custom code and gives the browser more responsibility, but that does not make every replacement automatically correct.&lt;/p&gt;

&lt;p&gt;You still need to test keyboard behavior, older browsers, analytics hooks, and any state tied to the current implementation. The report is a review list, not a merge button.&lt;/p&gt;

&lt;p&gt;If you have an old page with a suspicious amount of UI glue, you can &lt;a href="https://cssradar.com/" rel="noopener noreferrer"&gt;run a free audit on CSS Radar&lt;/a&gt;. I am especially interested in the patterns it misses. Those failures have been more useful than the easy successes.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Exploring modern CSS: does this concept resonate with you?</title>
      <dc:creator>Theo</dc:creator>
      <pubDate>Tue, 13 May 2025 13:24:13 +0000</pubDate>
      <link>https://dev.to/theosoti/exploring-modern-css-does-this-concept-resonate-with-you-2c0m</link>
      <guid>https://dev.to/theosoti/exploring-modern-css-does-this-concept-resonate-with-you-2c0m</guid>
      <description>&lt;p&gt;Hello,&lt;/p&gt;

&lt;p&gt;I’ve been working on a little side project: a collection of practical, modern CSS-only techniques. Things like toggles, modals, dark mode, etc... with zero JavaScript.&lt;/p&gt;

&lt;p&gt;The idea came from realising how often we default to JS for stuff that CSS can now handle really well. I’m compiling these patterns into an ebook, focused on simplicity, accessibility, and browser-native solutions.&lt;/p&gt;

&lt;p&gt;I’ve put up a small landing page here:&lt;br&gt;
👉 &lt;a href="https://theosoti.com/you-dont-need-js/" rel="noopener noreferrer"&gt;https://theosoti.com/you-dont-need-js/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d love your honest feedback:&lt;/p&gt;

&lt;p&gt;Does this seem useful or interesting to you?&lt;br&gt;
Anything you'd expect to see in something like this?&lt;br&gt;
Or anything that immediately turns you off?&lt;/p&gt;

&lt;p&gt;Also, I’m curious: what’s the most surprising thing you’ve built (or seen) using just CSS?&lt;/p&gt;

&lt;p&gt;Appreciate any thoughts 🙏&lt;/p&gt;

</description>
      <category>showcase</category>
      <category>css</category>
      <category>webdev</category>
      <category>html</category>
    </item>
  </channel>
</rss>
