<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Webdesign & SEO Notes by Marcus Lux]]></title><description><![CDATA[Practical notes on WordPress, web design, local SEO and AI search visibility by Marcus Lux, founder of Leipzig-Webdesign in Leipzig, Germany.]]></description><link>https://leipzigwebdesign.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sat, 07 Nov 2026 11:17:05 GMT</lastBuildDate><atom:link href="https://leipzigwebdesign.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Build a Responsive Before-and-After Slider with HTML, CSS and JavaScript]]></title><description><![CDATA[Build a responsive before-and-after slider with HTML, CSS and vanilla JavaScript. Includes code, keyboard controls and a working CodePen demo.]]></description><link>https://leipzigwebdesign.hashnode.dev/build-a-responsive-before-and-after-slider-with-html-css-and-javascript</link><guid isPermaLink="true">https://leipzigwebdesign.hashnode.dev/build-a-responsive-before-and-after-slider-with-html-css-and-javascript</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[CSS]]></category><category><![CDATA[HTML]]></category><dc:creator><![CDATA[Marcus Lux | Leipzig-Webdesign]]></dc:creator><pubDate>Thu, 29 Oct 2026 13:22:22 GMT</pubDate><content:encoded><![CDATA[<p>A before-and-after comparison can help explain a website redesign. Visitors can inspect both versions in the same space instead of trying to remember one screenshot while looking at another.</p>
<p>I built a small comparison for my CodePen profile using HTML, CSS and vanilla JavaScript. The preview shows two fictional garden-studio websites. It is a design exercise, not a client result or evidence of higher conversions.</p>
<p><a href="https://codepen.io/editor/leipzigwebdesign/pen/01a187a9-fba1-74db-8bfa-4f8b3cf3913c?show=preview&amp;panel=false">Open the working CodePen demo</a>.</p>
<h2>How the before-and-after slider works</h2>
<p>Both designs occupy the same area. The first stays underneath. CSS clips the second design, and a native range input controls how much of it appears.</p>
<p>I kept the control below the preview. That gives touch users a separate place to drag without covering the design with their finger. The round handle inside the preview is a visual indicator, not a second draggable control.</p>
<p>The example below is a smaller version of the CodePen demo. Save it as index.html and open it in a browser. It needs no build step or external library.</p>
<h2>Add the HTML structure</h2>
<p>The comparison needs a preview container, two layers and a labelled range input. Preset buttons let visitors jump to either complete design or return to the middle.</p>
<pre><code class="language-html">&lt;main&gt;
  &lt;h1&gt;A website redesign, compared&lt;/h1&gt;
  &lt;div class="preview" role="img"
    aria-label="Fictional garden websites: a generic welcome compared with specific garden services."&gt;
    &lt;section class="layer before" aria-hidden="true"&gt;
      &lt;p&gt;BEFORE / GARDEN STUDIO&lt;/p&gt;
      &lt;h2&gt;Welcome to our website.&lt;/h2&gt;
      &lt;p&gt;Professional solutions for your garden needs.&lt;/p&gt;
    &lt;/section&gt;
    &lt;section class="layer after" id="after" aria-hidden="true"&gt;
      &lt;p&gt;AFTER / GARDEN STUDIO&lt;/p&gt;
      &lt;h2&gt;A garden that fits the way you live.&lt;/h2&gt;
      &lt;p&gt;Planting plans, patios and seasonal care in Leipzig.&lt;/p&gt;
    &lt;/section&gt;
    &lt;div id="divider" aria-hidden="true"&gt;&lt;span&gt;↔&lt;/span&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;label for="comparison"&gt;After design visible&lt;/label&gt;
  &lt;input id="comparison" type="range" min="0" max="100"
    step="1" value="50" aria-describedby="instructions"&gt;
  &lt;output id="amount" for="comparison"&gt;50%&lt;/output&gt;
  &lt;div class="presets"&gt;
    &lt;button type="button" data-value="0"&gt;Before&lt;/button&gt;
    &lt;button type="button" data-value="50"&gt;Compare&lt;/button&gt;
    &lt;button type="button" data-value="100"&gt;After&lt;/button&gt;
  &lt;/div&gt;
  &lt;p id="instructions"&gt;Drag the range control or use its arrow keys.
    Home shows before; End shows after.&lt;/p&gt;
  &lt;p&gt;Fictional concepts, not measured client results.&lt;/p&gt;
&lt;/main&gt;
</code></pre>
<h2>Overlay both designs with CSS</h2>
<p>The layers keep their full width. I clip the after layer instead of changing its width, so its text does not reflow as the slider moves. Both layouts still respond to the available preview width.</p>
<p>Place this CSS inside a style element in the document head, or in a stylesheet linked from your HTML. Include a viewport meta tag when testing on a phone.</p>
<pre><code class="language-css">* { box-sizing: border-box; }
body { margin: 0; background: #eef1e9; color: #18352e;
  font: 16px/1.5 Arial, sans-serif; }
main { max-width: 860px; margin: auto; padding: 24px 16px; }
.preview { position: relative; height: 390px; overflow: hidden;
  border: 1px solid #a8b9aa; border-radius: 12px; margin-bottom: 20px; }
.layer { position: absolute; inset: 0; padding: 28px; }
.layer h2 { max-width: 440px; font-size: clamp(28px, 5vw, 48px);
  line-height: 1.1; }
.before { background: #faf5eb; color: #65594b; font-family: Georgia, serif; }
.after { background: #163e32; color: #f2f4d9;
  clip-path: inset(0 0 0 50%); }
#divider { position: absolute; inset: 0 auto 0 50%;
  width: 2px; background: #f6db50; pointer-events: none; }
#divider span { position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%); display: grid; place-items: center;
  width: 44px; height: 44px; border: 3px solid white;
  border-radius: 50%; background: #f6db50; color: #163e32; }
label { display: block; font-weight: bold; }
input[type="range"] { width: 100%; min-height: 48px; accent-color: #163e32; }
button { min-height: 44px; padding: 10px 16px; margin: 8px 4px 0 0;
  border: 1px solid #8fa391; border-radius: 5px;
  background: transparent; color: #18352e; cursor: pointer; }
button:active { background: #dce5d6; }
:focus-visible { outline: 3px solid #8245a9; outline-offset: 4px; }
@media (max-width: 480px) {
  .layer { padding: 22px 18px; }
  .preview { height: 430px; }
}
</code></pre>
<p>The four inset values represent top, right, bottom and left. At the initial position, inset(0 0 0 50%) hides the left half of the after layer. The before design remains visible there.</p>
<h2>Connect the range input with JavaScript</h2>
<p>Put this script after the HTML, before the closing body tag. The input event updates the preview while you move the range control.</p>
<pre><code class="language-javascript">const slider = document.querySelector("#comparison");
const after = document.querySelector("#after");
const divider = document.querySelector("#divider");
const amount = document.querySelector("#amount");

function updateComparison() {
  const visible = Number(slider.value);
  const split = 100 - visible;
  after.style.clipPath = "inset(0 0 0 " + split + "%)";
  divider.style.left = split + "%";
  amount.textContent = visible + "%";
  slider.setAttribute("aria-valuetext", visible + " percent after visible");
}

slider.addEventListener("input", updateComparison);
document.querySelectorAll("[data-value]").forEach((button) =&gt; {
  button.addEventListener("click", () =&gt; {
    slider.value = button.dataset.value;
    updateComparison();
  });
});
updateComparison();
</code></pre>
<p>The slider value describes how much of the after design is visible. At 0, the left inset is 100% and the after design disappears. At 100, the inset is 0 and the after design fills the preview. The divider follows the same boundary.</p>
<h2>Keep keyboard and touch controls usable</h2>
<p>I use the browser’s native range control rather than a draggable div. It provides built-in keyboard interaction, while the label names the control and aria-valuetext explains the percentage. Exact key behaviour should still be checked in your target browsers and assistive technology.</p>
<p>The preview layers are decorative in this example. A short accessible description explains the comparison. For a real case study, include the important differences as normal text outside the clipped preview so everyone can read them.</p>
<p>The control area is at least 48 pixels high. The buttons provide an alternative to precise dragging. I have not added transitions to the clipping boundary: the preview should follow the input without lag.</p>
<h2>Check the component before using it in a project</h2>
<ul>
<li>Use Before, Compare and After; verify the text does not change its wrapping while the boundary moves.</li>
<li>Reach the slider with Tab and test the arrow keys, Home and End. Check that the focus outline remains visible.</li>
<li>Test a narrow screen and browser zoom. Longer content may need more preview height; this fixed-height example is not a complete website viewer.</li>
<li>Disable JavaScript. The two layers should still show the initial 50/50 comparison, although the controls will no longer update it.</li>
</ul>
<p>If you replace the HTML concepts with screenshots, use matching dimensions and alignment. Keep decorative layers non-interactive: clipping a real link does not necessarily remove it from keyboard navigation.</p>
<h2>Use the comparison to explain a design decision</h2>
<p>In the demo, I changed the generic welcome into a concrete description of garden services and a clearer next step. That makes the intended difference easier to discuss. It does not prove that the revised design produces more enquiries.</p>
<p>I’m Marcus Lux, founder of <a href="https://leipzig-webdesign.com/">Leipzig-Webdesign</a> in Leipzig, Germany. I work on WordPress websites and SEO. I use small examples like this to make website decisions easier to inspect.</p>
<p>You can explore the full layout in the <a href="https://codepen.io/editor/leipzigwebdesign/pen/01a187a9-fba1-74db-8bfa-4f8b3cf3913c?show=preview&amp;panel=false">CodePen demo</a>.</p>
<h3>References</h3>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/range">MDN: HTML range input</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/clip-path">MDN: CSS clip-path</a></li>
</ul>
]]></content:encoded></item></channel></rss>