<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<title>dan—webnotes</title>
	<subtitle>writing about my projects, experiments and ideas</subtitle>
	<link href="https://dan-webnotes.com/public/assets/feed.xml" rel="self"/>
	<link href="https://dan-webnotes.com/" rel="alternate"/>
	<updated>2026-07-14T00:00:00Z</updated>
	<id>https://dan-webnotes.com/</id>
	<author>
		<name>dan dep</name>
		<email>dan.depietri@gmail.com</email>
	</author>
	
	<entry>
		<title>The joy of extending Tailwind</title>
		<link href="https://dan-webnotes.com/posts/2026-07-14-joy-extending-tailwind/"/>
		<updated>2026-07-14T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-07-14-joy-extending-tailwind/</id>
		<content type="html">&lt;p&gt;2026-07-14&lt;/p&gt;
&lt;h1 id=&quot;the-joy-of-extending-tailwind&quot;&gt; The joy of extending Tailwind&lt;/h1&gt;
&lt;p&gt;One of the biggest upgrade that came with Tailwind 4 has been the new CSS-based configuration and extensibility system.&lt;/p&gt;
&lt;p&gt;The CSS configuration came with a new simple syntax, which is very close to the way regular CSS is written. This makes it really easy to integrate Tailwind into a project&#39;s design system.&lt;/p&gt;
&lt;p&gt;Let&#39;s consider a regular CSS class.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.my-class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  display: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  color: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;red&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a perfectly fine class, and here is the same class registered as a tailwind utility using the new directive &lt;code&gt;@utility&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; my-class {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  display: block;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  color: red;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Registering a class as a &lt;code&gt;@utility&lt;/code&gt; brings super-powers to that class, together with nice improvements in developer experience.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can now apply that class arbitrarily whenever the design requires it, whether it is desktop-only &lt;code&gt;md:my-class&lt;/code&gt;, on hover &lt;code&gt;hover:my-class&lt;/code&gt;, when in dark-mode &lt;code&gt;dark:my-class&lt;/code&gt;, and many others.&lt;/li&gt;
&lt;li&gt;The class is added to the final stylesheet only in case the utility is actually used, avoiding unnecessary CSS.&lt;/li&gt;
&lt;li&gt;You can hover a class to lookup its CSS declarations, thanks to the amazing VSCode &lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss-intellisense&quot;&gt;tailwind-intellisense extension.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2026-07-14-joy-extending-tailwind/intellisense-screenshot.png&quot; alt=&quot;A screenshot of a CSS class definition&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;props-in-css&quot;&gt; Props in CSS&lt;/h2&gt;
&lt;p&gt;There aren&#39;t only &lt;em&gt;static&lt;/em&gt; &lt;code&gt;@utility&lt;/code&gt;, Tailwind v4 introduced a whole CSS-like syntax to pass values into the utilities it generates. These props can modify the values of the CSS properties within the class, and they can be numbers, colors, percentages, keywords, etc.&lt;/p&gt;
&lt;p&gt;It&#39;s pretty straightforward to grasp how the new functions work if you are already familiar with CSS syntax and logic. The main functions are &lt;code&gt;--alpha()&lt;/code&gt;, &lt;code&gt;--value()&lt;/code&gt;, &lt;code&gt;--modifier()&lt;/code&gt;, &lt;code&gt;--default()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Check out the official documentation on &lt;a href=&quot;https://tailwindcss.com/docs/adding-custom-styles/&quot;&gt;how to add custom styles&lt;/a&gt;, to see how these functions work together, and how they allow to generate &lt;strong&gt;complex components on-the-fly.&lt;/strong&gt; Here are a few examples.&lt;/p&gt;
&lt;h3 id=&quot;css-shapes&quot;&gt; CSS shapes&lt;/h3&gt;
&lt;p&gt;Using &lt;code&gt;clip-path&lt;/code&gt; and the modern CSS function &lt;code&gt;polygon()&lt;/code&gt;, together with a size prop, we can generate any sort of CSS-only shapes.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; star-* {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	width: calc(--value(number&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--spacing&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	height: calc(--value(number&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--spacing&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	clip-path&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: polygon(50% 0%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 61% 35%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 98% 35%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 68% 57%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 79% 91%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 50% 70%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 21% 91%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 32% 57%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 2% 35%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 39% 35%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	flex-shrink&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: 0;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-colored-shadow-border-that-blends-in&quot;&gt; A colored shadow border that blends in&lt;/h3&gt;
&lt;p&gt;If you are interested in subtle CSS details that make a UI feel polished, you will have probably encountered the &lt;code&gt;border-shadow&lt;/code&gt; trick.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.border-shadow&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	box-shadow:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;		0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.06&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;		0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.06&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;		0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; rgba&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.04&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But now you can have this technique work with any color, and with any opacity modifier.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; border-shadow-* {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  box-shadow&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;    0px 0px 0px 1px --alpha(--value(--color-&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) / &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;--modifier([&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;percentage&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 6%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    0&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;px 1px 2px -1px --alpha(--value(--color-&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) / &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;--modifier([&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;percentage&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 6%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    0&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;px 2px 4px 0px --alpha(--value(--color-&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;color&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) / &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;calc(--modifier([&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;percentage&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 6%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.66&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;a-conditional-rounded-box&quot;&gt; A conditional rounded box&lt;/h3&gt;
&lt;p&gt;Some time ago a &lt;a href=&quot;https://ishadeed.com/article/conditional-border-radius/&quot;&gt;post&lt;/a&gt; by Ahmad Shadeed gained popularity. It described a CSS one-liner which conditionally rounded an element depending whether the element touched the viewport (or its container) or not.&lt;/p&gt;
&lt;p&gt;But for example, with tailwind we can have the one-liner also control how rounded the element initially was.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; conditional-rounded-* {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	border-radius&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: calc(sign(100cqi - 100%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --value(number&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--spacing&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;creating-variants&quot;&gt; Creating variants&lt;/h2&gt;
&lt;p&gt;The last chapter of extending tailwind touches the &lt;strong&gt;modifiers&lt;/strong&gt;, which specify when applying a class.&lt;/p&gt;
&lt;p&gt;These use another new directive &lt;code&gt;@custom-variant&lt;/code&gt;. Tailwind already offers variants for the most used CSS media queries. But creating new ones can still be valuable for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ergonomics,&lt;/strong&gt; create shorter, more clear directives&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@custom-variant&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; touch {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (pointer: coarse) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		@slot&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Patch &lt;strong&gt;browsers shortcomings&lt;/strong&gt;, with ad-hoc inline fixes&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@custom-variant&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; safari {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	@supports&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (font: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;-apple-system-body&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		@slot&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Combining&lt;/strong&gt; multiple directives together&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@custom-variant&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; hocus {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  @media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (hover: hover) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:hover&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      @slot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x26;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:focus-visible&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    @slot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;utility-driven-agents&quot;&gt; Utility-driven agents&lt;/h2&gt;
&lt;p&gt;It&#39;s funny to feel joy in polishing code snippets, while being told you shouldn&#39;t even read code anymore.&lt;/p&gt;
&lt;p&gt;But I think even with AI writing all the code, it&#39;s still valuable to produce abstractions that makes frontend code more expressive and clear. (Granted, you have to like Tailwind)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ultimately if it&#39;s good for humans, it&#39;s good for LLMs too.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Also, I still prefer burning tokens on crafting powerful abstractions that I, the LLMs, and my team can reuse over and over, rather than painfully steering a 100B parameter model into a writing a flex column that takes 2 seconds to type.&lt;/p&gt;
&lt;p&gt;Recently I was getting annoyed at how long it was taking me to position content inside the typical 12-columns layout, and having it adapt to the breakpoints.&lt;/p&gt;
&lt;p&gt;Once I had the right idea, it really took one &lt;s&gt;rant&lt;/s&gt; prompt and pointing the LLMs to the documentation page.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;so i use grid with tailwind css but i get tired of writing a ton of col-start-2 col-span-3 md:col-start-4 md:col-span-6 etc etc&lt;/p&gt;
&lt;p&gt;i want to create a set of @utility that allow me to write for example md:col-2-to-10&lt;/p&gt;
&lt;p&gt;tailwind allows you to create custom utilities with a single parameter not two, so let&#39;s use the parameter only for the second column so @utility col-1-* and then create twelve for col-1-to-1, col-1-to-2, col-1-to-3 etc etc, if possible make the css valid only if * is at least the hardcoded value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And it cooked exactly what I needed to fly through my front-end build.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; col-1-to-* {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  grid-column&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: 1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;calc(--value(&quot;1&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;2&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;3&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;4&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;5&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;6&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;7&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;8&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;9&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;10&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;11&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;12&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) + 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; col-2-to-* {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  grid-column&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: 2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;calc(--value(&quot;2&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;3&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;4&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;5&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;6&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;7&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;8&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;9&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;10&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;11&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;12&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) + 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@utility&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; col-3-to-* {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  grid-column&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: 3&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; / &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;calc(--value(&quot;3&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;4&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;5&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;6&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;7&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;8&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;9&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;10&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;11&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; &quot;12&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) + 1);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PS. I have a few other takes on this topic that I would like to write about, so if you would like to get notified when these posts come out, sign up with with the form below the post to receive it. There is an &lt;a href=&quot;https://dan-webnotes.com/assets/feed.xml&quot;&gt;RSS feed&lt;/a&gt; too.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs/adding-custom-styles&quot;&gt;Adding custom styles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss-intellisense&quot;&gt;tailwindlabs/tailwindcss-intellisense&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>A Self-maintaining filesystem for static blogs</title>
		<link href="https://dan-webnotes.com/posts/2026-07-01-self-maintaining-filesystem-static-blogs/"/>
		<updated>2026-07-01T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-07-01-self-maintaining-filesystem-static-blogs/</id>
		<content type="html">&lt;p&gt;2026-07-01&lt;/p&gt;
&lt;h1 id=&quot;a-self-maintaining-filesystem-for-static-blogs&quot;&gt; A Self-maintaining filesystem for static blogs&lt;/h1&gt;
&lt;p&gt;I&#39;ve just finished revamping the folder structure of this blog&#39;s content to include the date in the file name as in &lt;code&gt;yyyy-mm-dd-post-title.md&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This finally made opening the posts folder manageable as scanning the ever-growing list of titles, was causing me to dreading opening it at all.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Recently, my guiding principle has been to remove any friction from the projects I would like to work on more.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-file-structure&quot;&gt; The file structure&lt;/h2&gt;
&lt;p&gt;The typical Eleventy setup has a &lt;strong&gt;flat-files setup.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    ├── post-title.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  	└── another-post-title.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But in my quest for documenting and portability, I ended up setting up this folder structure instead.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    └── yyyy-mm-dd-post-title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      	├── yyyy-mm-dd-post-title.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      	└── image.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has a few advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Co-location&lt;/strong&gt; of a post&#39;s assets, images, snippets, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Holding meta information&lt;/strong&gt; such as title and date in the file name itself, rather than a generic &lt;code&gt;index.md&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relative links in markdown&lt;/strong&gt; easily map to their html links counterpart, once the site it&#39;s built.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;automating-the-boring-parts&quot;&gt; Automating the boring parts&lt;/h2&gt;
&lt;p&gt;Enter &lt;strong&gt;Claude Code,&lt;/strong&gt; and adapting &lt;s&gt;11ty&lt;/s&gt; &lt;a href=&quot;https://www.11ty.dev/blog/build-awesome/&quot;&gt;Buildawesome&lt;/a&gt; to my needs is just a matter of asking AI to write some scripts that integrate with the internal 11ty &lt;a href=&quot;https://www.11ty.dev/docs/watch-serve/&quot;&gt;Dev Server&lt;/a&gt; watcher.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Updating either the &lt;strong&gt;Frontmatter&lt;/strong&gt; property &lt;code&gt;date&lt;/code&gt; or &lt;code&gt;title&lt;/code&gt; now triggers a name change of both the file name and the folder name.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the folder and filename change affected a live post, eg. with the &lt;strong&gt;Frontmatter&lt;/strong&gt; property &lt;code&gt;draft: false&lt;/code&gt;, a script will update all internal links that reference the updated path, and create a &lt;strong&gt;redirect&lt;/strong&gt;, by adding an entry to &lt;code&gt;redirects.json&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;    &quot;from&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;/posts/2023-02-21-how-build-minimalist-markdown-blog-eleventy/&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;    &quot;to&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;
&lt;p&gt;If I upload an image file into a post folder, it will automatically compress it to a sensible size. No need to worry anymore about git-tracking 5MB pictures straight out of my camera roll.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A simple &lt;code&gt;npm run new post title&lt;/code&gt; command, creates an empty document with the &lt;code&gt;yyyy-mm-dd-post-title.md&lt;/code&gt; title slug, folder, today&#39;s date, set to draft and a scaffolded empty post.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;date&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2026-07-01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;Post title&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;project&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;repository&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;tags&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: []&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;selected&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;draft&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;description&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;2026-07-01&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;# Post title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;### Resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/blog/build-awesome/&quot;&gt;Eleventy is now Build Awesome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/watch-serve/&quot;&gt;Watch and Serve — Eleventy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>CSS tricks for markdown blogs</title>
		<link href="https://dan-webnotes.com/posts/2026-06-28-css-tricks-markdown-blogs/"/>
		<updated>2026-06-28T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-06-28-css-tricks-markdown-blogs/</id>
		<content type="html">&lt;p&gt;2026-06-28&lt;/p&gt;
&lt;h1 id=&quot;css-tricks-for-markdown-blogs&quot;&gt; CSS tricks for markdown blogs&lt;/h1&gt;
&lt;p&gt;All the post content you are reading here comes from a single markdown file converted into HTML and stylized with CSS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reducing what is rendered via template will limit what&#39;s possible in terms of layout and interactivity. But it guarantees that, if I move my site to a different setup, the plain text files will carry most of the content with them.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Also it&#39;s interesting to explore what is possible to get out of CSS alone. Here are a few of the tricks used in this blog.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I&#39;m manually writing the &lt;strong&gt;post date&lt;/strong&gt; and &lt;strong&gt;post title&lt;/strong&gt; for each post. I simply add these to the top of the file.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;2026-06-28&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;# CSS tricks for markdown blogs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, the CSS targets the date, as the first paragraph at the top of each post, adding a custom styling.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; p&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:first-child&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	font-size: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.9&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Whenever an &lt;strong&gt;italic text&lt;/strong&gt; comes right after an image, I want to style it to make it look like a actual caption.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2026-06-28-css-tricks-markdown-blogs/josefin-WS5yjFjycNY-unsplash.jpg&quot; alt=&quot;Picture of lush green leaves&quot;&gt;
&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/@josefin/&quot;&gt;Josefin&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/green-leafed-plant-WS5yjFjycNY/&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The CSS uses the &lt;strong&gt;sibling selector&lt;/strong&gt; &lt;code&gt;img + em&lt;/code&gt; to target the first italic after an image.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;![&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Green leaves&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;josefin-WS5yjFjycNY-unsplash.jpg&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-font-style:italic;--shiki-dark:#C678DD;--shiki-dark-font-style:italic&quot;&gt;_Photo by Josefin on Unsplash_&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;I can make the CSS create a &lt;strong&gt;double column layout&lt;/strong&gt; with two images side-by-side, by simply writing them next to each other in the markdown text.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;![&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Three possums on a red balloon&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;possum.png&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;![&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Three possums on a red balloon&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;possum.png&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Modern CSS makes this possible, by target the images container, with a combination of the &lt;strong&gt;parent selector&lt;/strong&gt; &lt;code&gt;:has()&lt;/code&gt;, &lt;strong&gt;sibling selectors&lt;/strong&gt; and &lt;strong&gt;CSS grid&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;768&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	p&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:has&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; ~&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; img&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		display: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;grid&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		grid-auto-flow: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;column&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		grid-gap: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		grid-template-columns: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;repeat&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;minmax&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;fr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		grid-template-rows: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;repeat&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2026-06-28-css-tricks-markdown-blogs/possum.png&quot; alt=&quot;A possum parent and two possum kids hanging from the iconic red balloon&quot;&gt;
&lt;em&gt;Two pictures of beautiful possums that will be side by side on desktop&lt;/em&gt;
&lt;img src=&quot;https://dan-webnotes.com/posts/2026-06-28-css-tricks-markdown-blogs/possum.png&quot; alt=&quot;A possum parent and two possum kids hanging from the iconic red balloon&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;&lt;strong&gt;Styling numbered lists with&lt;/strong&gt; &lt;code&gt;&amp;lt;ol&amp;gt;&lt;/code&gt;. When doing lists, all the list items&#39; content must fit a single paragraph, even code blocks or images. Splitting the content over multiple paragraphs would make the list number restart.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;ol&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  list-style-type: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;decimal&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;ol&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; li&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::marker&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  content: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;counter&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;list-item&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The markdown parser, &lt;a href=&quot;https://github.com/markdown-it/markdown-it&quot;&gt;markdown-it&lt;/a&gt;, will automatically set the &lt;code&gt;start&lt;/code&gt; attribute on any list that doesn&#39;t start with 1. You can then read that value with &lt;code&gt;counter(list-item)&lt;/code&gt;, if you wish to apply custom styles to the list.&lt;/p&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;I add links and resources at the bottom of the post manually. While there are plugins that do this, it&#39;s nice to have the simplest and most portable setup possible. The markdown parser, &lt;a href=&quot;https://github.com/markdown-it/markdown-it&quot;&gt;markdown-it&lt;/a&gt;, adds automatically the hash link and the &lt;code&gt;id&lt;/code&gt; to all the headings.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;#resources&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; ~&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; ul&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; li&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;(&quot;&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; attr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;)&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, with CSS it&#39;s possible to target the resources list and style them differently from the article&#39;s lists. I also use a &lt;code&gt;::after&lt;/code&gt; pseudo-element and its &lt;code&gt;content&lt;/code&gt; property to have the URL of the link displayed inline, which helps to identify links at a glance.&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;With a &lt;strong&gt;regex formula&lt;/strong&gt; inside the CSS attribute selector, I can target the links that have a certain word inside their &lt;code&gt;href&lt;/code&gt; attribute and style it with a favicon, without fetching data and without javascript.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	a&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;wikipedia.org&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		height: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;em&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		mask-image: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;data:image/svg+xml,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#39;0 0 24 24&#39;%3E%3Cpath d=&#39;.../%3E%3C/svg%3E&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stephango.com/file-over-app&quot;&gt;File over app&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Lessons from a reusable web component</title>
		<link href="https://dan-webnotes.com/posts/2026-06-07-lessons-reusable-web-component/"/>
		<updated>2026-06-07T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-06-07-lessons-reusable-web-component/</id>
		<content type="html">&lt;p&gt;2026-06-07&lt;/p&gt;
&lt;h1 id=&quot;lessons-from-a-reusable-web-component&quot;&gt; Lessons from a reusable web component&lt;/h1&gt;
&lt;p&gt;Many people commented that they expected the
&lt;a href=&quot;https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/&quot; class=&quot;gradient-before&quot;&gt;CSS-native parallax effect&lt;/a&gt; to have an interactive demo, so I re-opened and modernized &lt;a href=&quot;https://github.com/danieledep/code-sandbox&quot;&gt;a small code-sandbox web component&lt;/a&gt; I built last year.&lt;/p&gt;
&lt;p&gt;Since then, I&#39;ve dropped it into a handful of projects. Reusing the thing confirmed some of the choices I&#39;ve made, and gave me some new useful ideas.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Note:
This post doesn&#39;t touch advanced web-components techniques, like the shadow DOM or using &lt;code&gt;&amp;lt;template&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;slot&amp;gt;&lt;/code&gt; elements. The tips in this post can apply broadly to UI components and CSS libraries.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;own-a-short-distinctive-namespace&quot;&gt; Own a short, distinctive namespace&lt;/h3&gt;
&lt;p&gt;Every class and custom property in the component now starts with &lt;code&gt;csb&lt;/code&gt;. For example, I have &lt;code&gt;.csb-header&lt;/code&gt;, &lt;code&gt;.csb-controls&lt;/code&gt;, and so on.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Short,&lt;/strong&gt; because it repeats on every element and every variable, and being short might shave a few bytes and a few minutes of typing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Distinctive,&lt;/strong&gt; because the point of a component is to land in a page you don&#39;t control, and a generic &lt;code&gt;.header&lt;/code&gt; or &lt;code&gt;.button&lt;/code&gt; might collide with the host&#39;s styles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;theme-with-namespaced-css-variables&quot;&gt; Theme with namespaced CSS variables&lt;/h3&gt;
&lt;p&gt;This is the most important. Rather than ship override classes, every value worth changing is a &lt;strong&gt;CSS custom property, with its default written in as the fallback:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.csb-header&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	border-color: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--csb-border-color&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, light-dark(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;ddd&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;6b6b6b&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The component renders correctly with zero configuration, because the fallback is the default. Theming it means setting variables on the root element, or any parent element, and let the cascade do its thing:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	--csb-border-color&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--my-color&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	--csb-editor-bg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;282c34&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;No &lt;code&gt;!important&lt;/code&gt;, no descendant selectors reaching three levels deep, no cascade to fight. The list of variable names is the whole public surface, which also means that you should try to keep these ones stable between versions.&lt;/p&gt;
&lt;h3 id=&quot;let-modern-css-and-js-do-the-magic&quot;&gt; Let modern CSS and JS do the magic&lt;/h3&gt;
&lt;p&gt;A reusable component lands in contexts you can&#39;t predict, so using the modern features that the platform offers is one of the best way to achieve adaptability and resilience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Container queries, not media queries.&lt;/strong&gt; You don&#39;t know if a component will be added in a narrow sidebar or full width. Use &lt;code&gt;container-type: inline-size&lt;/code&gt; on the parent element, so the child can responds to its own width.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;light-dark()&lt;/code&gt; with &lt;code&gt;color-scheme&lt;/code&gt; to have dark mode by default.&lt;/li&gt;
&lt;li&gt;System fonts (&lt;code&gt;system-ui&lt;/code&gt;, &lt;code&gt;ui-monospace&lt;/code&gt;) and system colours (&lt;code&gt;Canvas&lt;/code&gt;) so the default always works, and is consistent as possible with the underlying OS.&lt;/li&gt;
&lt;li&gt;Logical properties (&lt;code&gt;border-block-end&lt;/code&gt;, &lt;code&gt;padding-inline&lt;/code&gt;) so it can support right-to-left layout, if needed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;em&lt;/code&gt; for sizing, so the whole component scales with whatever font size it inherits.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;publish-it-instead-of-pasting-it&quot;&gt; Publish it instead of pasting it&lt;/h3&gt;
&lt;p&gt;While it can sound like a good idea copying the JS and CSS into each project by hand to achieve the final simplicity, copying and pasting gets tiring quite fast. It&#39;s now on &lt;a href=&quot;https://www.npmjs.com/package/@danieledep/code-sandbox/&quot;&gt;NPM&lt;/a&gt;, and it can be imported in a line and updated with a version bump rather than a copy-paste tour of old projects.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; @danieledep/code-sandbox&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Publishing it on NPM gives you for free command-line installing and &lt;strong&gt;CDN hosting&lt;/strong&gt;, useful for the no-build case. So a static HTML page can use it by importing it in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the file.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;https://cdn.jsdelivr.net/npm/@danieledep/code-sandbox@1/src/code-sandbox.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;https://cdn.jsdelivr.net/npm/@danieledep/code-sandbox@1/src/code-sandbox.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;then-document-all-of-it&quot;&gt; Then document all of it&lt;/h3&gt;
&lt;p&gt;A module only counts as reusable once someone other than you can actually use it and customize it. The code-sandbox README carries the theming table, the layout and highlighter guides, and the install instructions.&lt;/p&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/code-sandbox&quot;&gt;danieledep/code-sandbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@danieledep/code-sandbox&quot;&gt;@danieledep/code-sandbox on NPM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API&quot;&gt;Fullscreen API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/system-color&quot;&gt;&lt;system-color&gt;&lt;/system-color&gt; CSS type&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/light-dark&quot;&gt;light-dark() CSS function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/articles/fullscreen&quot;&gt;Making Fullscreen Experiences&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://shiki.style/&quot;&gt;Shiki Syntax highlighter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>CSS-native parallax effect</title>
		<link href="https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/"/>
		<updated>2026-06-02T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/</id>
		<content type="html">&lt;p&gt;2026-06-02&lt;/p&gt;
&lt;h1 id=&quot;css-native-parallax-effect&quot;&gt; CSS-native parallax effect&lt;/h1&gt;
&lt;p&gt;Parallax effects have a long history, and while there are countless ways and libraries to achieve them, a new CSS-native way was recently made possible with &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines&quot;&gt;CSS Scroll-driven animation timelines&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The usual recipe was a scroll event listener in JavaScript, recalculating positions on every frame and nudging an element up and down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Scroll-driven animations&lt;/strong&gt; handle all of that with CSS. Handling parallax animations with CSS has a few advantages: performance should be better as it runs it off the main thread, but my favorite part is the simplicity with which the whole thing becomes a small block of declarative styles, that can be applied with a single utility class. Here is the full code for the class:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.parallax&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	view-timeline-name: --parallax-tl;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	view-timeline-axis: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	overflow: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;hidden&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x26; &gt; * {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		scale: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--parallax-offset&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		animation: parallax &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;auto&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt; linear&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt; both&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		animation-timeline: --parallax-tl;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		animation-range: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;cover&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		will-change: translate;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@keyframes&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; parallax&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	from {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		translate: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--parallax-offset&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	to {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		translate: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--parallax-offset&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;the-timeline&quot;&gt; The timeline&lt;/h2&gt;
&lt;p&gt;The trick is &lt;code&gt;view-timeline-name&lt;/code&gt;. It creates a &lt;strong&gt;view progress timeline&lt;/strong&gt;, a timeline whose progress is measured by how far the &lt;code&gt;.parallax&lt;/code&gt; element has travelled through the scrollport. It reads 0% the moment the element starts to enter the viewport and 100% once it has fully left. &lt;code&gt;view-timeline-axis: block&lt;/code&gt; tells it to track movement along the block axis, which is the vertical one in a normal writing mode.&lt;/p&gt;
&lt;p&gt;On the child, &lt;code&gt;animation-timeline: --parallax-tl&lt;/code&gt; swaps the animation&#39;s clock from time to that timeline. From there the rest of the &lt;code&gt;animation&lt;/code&gt; line falls into place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;auto&lt;/code&gt; for duration, because the duration now comes from the timeline rather than a number of seconds&lt;/li&gt;
&lt;li&gt;&lt;code&gt;linear&lt;/code&gt; so scroll progress maps straight onto movement,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;both&lt;/code&gt; to hold the start and end frames outside the active range&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Note:
The animation-timeline longhand property is not part of the animation shorthand and must be declared separately. Furthermore, animation-timeline must be declared after the animation shorthand as the shorthand will reset non-included longhands to their initial value.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The keyframes do the actual work. With the default offset, the child slides from &lt;code&gt;translate: 0 -20%&lt;/code&gt; to &lt;code&gt;translate: 0 20%&lt;/code&gt; as you scroll past it. Because it moves at a different rate to the container around it, you get that sense of depth.&lt;/p&gt;
&lt;h2 id=&quot;scaling-to-avoid-empty-spots&quot;&gt; Scaling to avoid empty spots&lt;/h2&gt;
&lt;p&gt;The child translates by up to the offset percentage of its own height in each direction, so if the child were exactly the same size as its container, shifting it up or down would expose a strip of empty space.&lt;/p&gt;
&lt;p&gt;The child needs to be scaled up in order to have a margin to move into. It needs the offset&#39;s worth of extra height above and below, so twice the offset overall:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;scale: calc(1 &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--parallax-offset&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; / 100);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the default offset of 20, the child is rendered at 140% of its size, the surplus is clipped by &lt;code&gt;overflow: hidden&lt;/code&gt; on the container, and there is always enough content to cover the box no matter where in the ±20% travel it sits.&lt;/p&gt;
&lt;p&gt;The neat part is that both the translate and the scale read the same &lt;code&gt;--parallax-offset&lt;/code&gt; variable. Turn the offset up for a stronger effect and the scale grows to match it, so the cover stays correct on its own. One value to tune, and the gaps never come back:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;parallax&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; style&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#98C379&quot;&gt;--parallax-offset: 30;&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;…&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;will-change: translate&lt;/code&gt; is the last piece, a hint that this element&#39;s &lt;code&gt;translate&lt;/code&gt; is about to change so the browser can promote it to its own layer ahead of time.&lt;/p&gt;
&lt;h2 id=&quot;motion-preferences&quot;&gt; Motion preferences&lt;/h2&gt;
&lt;p&gt;Parallax is movement tied to scrolling, and some people would rather not have it. It&#39;s good practice to respect that by disabling the animation for anyone with &lt;code&gt;prefers-reduced-motion: reduce&lt;/code&gt;. In this case, we can just turn off the animation and scale:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (prefers-reduced-motion: reduce) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;	.parallax&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		animation: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;none&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		scale: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;update-07-06-2026&quot;&gt; Update: 07-06-2026&lt;/h2&gt;
&lt;p&gt;The day this post was published it got a lot of &lt;a href=&quot;https://news.ycombinator.com/item?id=48368291&quot;&gt;attentions on Hacker News&lt;/a&gt;, even getting up to the first spots of the front page. This was a first time for me, honestly it was fun to receive so much attention, totaling almost &lt;strong&gt;25k views&lt;/strong&gt; in a single day, although it came with a spectrum of all kinds of feedback.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/stats.png&quot; alt=&quot;Analytics dashboard&quot;&gt;&lt;/p&gt;
&lt;p&gt;It made me rediscover a CSS property that I haven&#39;t heard in years. Turns out, also the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/perspective&quot;&gt;perspective CSS property&lt;/a&gt; allows to achieve a CSS-only parallax effect. While I think that using &lt;code&gt;animation-timeline&lt;/code&gt; is cleaner and more configurable, this was great feedback. The more techniques in our toolbox, the better.&lt;/p&gt;
&lt;p&gt;Around half of the comments were about the lack of an interactive demo of the parallax effect. This is something I&#39;ve already had spent time thinking about. When I created this blog I wanted it to be a &lt;a href=&quot;https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/&quot; class=&quot;gradient-before&quot;&gt;minimalistic scratchpad of ideas&lt;/a&gt;, drafted in markdown and stylized with CSS. I feared that the moment I started to add previews, write MDX files or have subroutes for demos, then keeping up this blog would become a drag.&lt;/p&gt;
&lt;p&gt;But given the interest around frontend dev techniques, and future posts that I have in the pipeline, &lt;a href=&quot;https://dan-webnotes.com/posts/2026-06-07-lessons-reusable-web-component/&quot; class=&quot;gradient-before&quot;&gt;I&#39;ve modernized a simple drop-in web-component&lt;/a&gt; that I built for this exact purpose and I&#39;ll see how this works. Here&#39;s the demo.&lt;/p&gt;
&lt;code-sandbox hidden=&quot;&quot; name=&quot;code-sandbox-1&quot;&gt;
	&lt;textarea for=&quot;html&quot;&gt;
	&lt;div class=&quot;text&quot;&gt; Scroll down &amp;#xffec;&lt;/div&gt;
	&lt;div class=&quot;parallax&quot; style=&quot;--parallax-offset: 50;&quot;&gt;
		&lt;img class=&quot;image&quot; eleventy:ignore=&quot;&quot; src=&quot;https://dan-webnotes.com/posts/2026-06-02-css-native-parallax-effect/parallax.jpg&quot; alt=&quot;Green-leafed plant&quot;&gt;
	&lt;/div&gt;
	&lt;/textarea&gt;
	&lt;textarea for=&quot;css&quot; open=&quot;&quot; src=&quot;parallax.css&quot;&gt;&lt;/textarea&gt;
&lt;/code-sandbox&gt;
&lt;p&gt;&lt;em&gt;Photo by &lt;a href=&quot;https://unsplash.com/photos/green-leafed-plant-WS5yjFjycNY/&quot;&gt;Josefin&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/&quot;&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since this post received a lot of attentions, I&#39;ve decided to send out a newsletter every time I post new interesting snippets. &lt;strong&gt;Subscribe with the form below the post to receive it. There is an &lt;a href=&quot;https://dan-webnotes.com/assets/feed.xml&quot;&gt;RSS feed&lt;/a&gt; too!&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.chrome.com/docs/css-ui/scroll-driven-animations&quot;&gt;Animate elements on scroll with Scroll-driven animations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://news.ycombinator.com/item?id=48368291&quot;&gt;CSS-native parallax effect, discussion on HN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/code-sandbox&quot;&gt;danieledep/code-sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/perspective&quot;&gt;perspective CSS property&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Scroll-driven_animations/Timelines&quot;&gt;Scroll-driven animation timelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/scroll-timeline&quot;&gt;scroll-timeline CSS property&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Contrast-proofing colors</title>
		<link href="https://dan-webnotes.com/posts/2026-05-16-contrast-proofing-colors/"/>
		<updated>2026-05-16T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-05-16-contrast-proofing-colors/</id>
		<content type="html">&lt;p&gt;2026-05-16&lt;/p&gt;
&lt;h1 id=&quot;contrast-proofing-colors&quot;&gt; Contrast-proofing colors&lt;/h1&gt;
&lt;p&gt;Previously in &lt;a href=&quot;https://dan-webnotes.com/posts/2023-07-21-text-selection-color/&quot; class=&quot;gradient-before&quot;&gt;Text selection color&lt;/a&gt;, I covered how the most important thing to keep in mind when setting custom highlight colors, is keeping the contrast high enough. Until recently this meant picking a colour, running it through a checker, and revisiting it whenever the brand palette changed.&lt;/p&gt;
&lt;p&gt;In 2026 the &lt;code&gt;contrast-color()&lt;/code&gt; function reached baseline support, and the browser can now handle this part directly.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro has-diff&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::selection&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;target-text&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;search-text&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	background: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;yellow&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff remove&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	color: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;black&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line diff add&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	color: contrast-color(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;yellow&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The function returns black or white, depending on which value has the greatest contrast with the input color.&lt;/strong&gt; When the background colour changes, the text follows, removing one manual step from the design system.&lt;/p&gt;
&lt;h2 id=&quot;uses&quot;&gt; Uses&lt;/h2&gt;
&lt;p&gt;This new function can have its place in a couple of scenarios.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Light/dark themes.&lt;/strong&gt; No manual changes for handling both light and dark themes. Just reference a CSS variable that changes with the dark/light theming and the function will output which text color works best.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	--primary-color&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: light-dark(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;333b3c&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;#&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;efefec&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::selection&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	background: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--primary-color&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	color: contrast-color(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--primary-color&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)); &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;strong&gt;Customizable background-colors.&lt;/strong&gt; Imagine you have a piece of UI, for example an announcement bar above the header, which the site owner can customise its background color from the CMS. After all, they might use their brand color, but occasionally switch to orange during the Halloween sales. In this case &lt;code&gt;contrast-color()&lt;/code&gt; can offer some safety for the site owner to always have a readable result.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;	class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;ticker bg-(--bg-color) text-[contrast-color(var(--bg-color))]&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;	style&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#98C379&quot;&gt;--bg-color: {{ data.background_color }};&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;doesnt-compose-with-color-mix&quot;&gt; Doesn&#39;t compose with color-mix()&lt;/h2&gt;
&lt;p&gt;Nesting inside a &lt;code&gt;color-mix()&lt;/code&gt; could be a nice idea. While the brand color is a solid color, the selection color could use a semi-transparent version of the same hue. But unfortunately that doesn&#39;t work today:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;background-color&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: color-mix(in oklab&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--color-primary&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) 10%, &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;transparent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;color: contrast-color(color-mix(in oklab&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--color-primary&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) 10%, &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;transparent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;accessibility-disclaimer&quot;&gt; Accessibility disclaimer&lt;/h2&gt;
&lt;p&gt;The MDN docs are explicit about the limits of WCAG AA as the basis for the algorithm:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Warning: WCAG AA (4.5:1) contrast is not capable of producing clearly readable text in all cases. Mid-tone background colors generally don&#39;t provide enough contrast with either black or white foreground. For example, contrast-color() on a royal bluish (#2277d3) background produces black text, which is not readable for small text. It is recommended, therefore, to use light or dark colors with the contrast-color() function.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, &lt;code&gt;contrast-color()&lt;/code&gt; is best suited to colours that already sit clearly at one end of the lightness scale. Mid-tones still need a manual judgement call.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/contrast-color&quot;&gt;contrast-color() on MDN&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>PostCSS Clampwind</title>
		<link href="https://dan-webnotes.com/posts/2026-01-17-postcss-clampwind/"/>
		<updated>2026-01-17T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2026-01-17-postcss-clampwind/</id>
		<content type="html">&lt;p&gt;2026-01-17&lt;/p&gt;
&lt;h1 id=&quot;postcss-clampwind&quot;&gt; PostCSS Clampwind&lt;/h1&gt;
&lt;p&gt;In my previous post, &lt;a href=&quot;https://dan-webnotes.com/posts/2025-07-02-generate-fluid-styles-tailwind-plugin/&quot; class=&quot;gradient-before&quot;&gt;Generate fluid styles with a Tailwind plugin&lt;/a&gt; I explored generating fluid styles with a Tailwind v3 plugin. The approach worked, but had significant downsides: massive CSS output, fragile selectors, and limited flexibility. After Tailwind v4 came out, I decided to take a completely different approach.&lt;/p&gt;
&lt;h2 id=&quot;the-idea&quot;&gt; The idea&lt;/h2&gt;
&lt;p&gt;Instead of trying to make Tailwind do all the heavy lifting with custom variants and CSS variables, what if we let Tailwind generate the CSS as it normally would, and then transform the output with PostCSS?&lt;/p&gt;
&lt;p&gt;The key insight is that Tailwind v4 already provides everything we need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Breakpoint variants&lt;/strong&gt; with the &lt;code&gt;md:max-lg:&lt;/code&gt; syntax define the screen range&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Arbitrary values&lt;/strong&gt; with &lt;code&gt;text-[clamp(16px,50px)]&lt;/code&gt; can express the value range&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PostCSS can read both and calculate the fluid formula, this means minimal transformations plugin-side, and leveraging what Tailwind already does well.&lt;/p&gt;
&lt;h2 id=&quot;how-tailwind-v4-handles-breakpoints&quot;&gt; How Tailwind v4 handles breakpoints&lt;/h2&gt;
&lt;p&gt;Looking at how Tailwind generates CSS for a ranged breakpoint utility:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;md:max-lg:text-[24px]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Generates the following CSS&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;max-lg&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  @media (width &gt;= 48rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* 768px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    @media (width &amp;#x3C; 64rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* 1024px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      font-size: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The nested media queries give us exactly what we need: the &lt;code&gt;min&lt;/code&gt; and max screen sizes for the interpolation. Plus:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modern range syntax&lt;/li&gt;
&lt;li&gt;Converts everything to rem&lt;/li&gt;
&lt;li&gt;Generates custom breakpoints too&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;min-[700px]:max-[800px]:text-[24px]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;keeping-the-clamp-function-name&quot;&gt; Keeping the &lt;code&gt;clamp()&lt;/code&gt; function name&lt;/h2&gt;
&lt;p&gt;Writing a non-valid &lt;code&gt;clamp()&lt;/code&gt; still informs Tailwind that I&#39;m using a size property. I first tried a shorter syntax:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[cl(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this makes Tailwind generate the wrong property:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;cl&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  color: cl(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;); &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* Text color */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using the actual &lt;code&gt;clamp()&lt;/code&gt; function name works better&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Right CSS property&lt;/li&gt;
&lt;li&gt;Tailwind handles whitespaces&lt;/li&gt;
&lt;li&gt;I just need to read the values inside the parenthesis, convert everything to rems and write out the formula&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This two-value &lt;code&gt;clamp()&lt;/code&gt; is invalid CSS, but the PostCSS plugin will transform it into the valid three-value version.&lt;/p&gt;
&lt;p&gt;The PostCSS plugins work by walking through the &lt;strong&gt;CSS AST (Abstract Syntax Tree)&lt;/strong&gt; and transforming nodes. The plugin needs to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find all declarations containing two-value &lt;code&gt;clamp()&lt;/code&gt; calls&lt;/li&gt;
&lt;li&gt;Extract the min and max values&lt;/li&gt;
&lt;li&gt;Find the parent media queries to determine the screen range&lt;/li&gt;
&lt;li&gt;Calculate the fluid formula&lt;/li&gt;
&lt;li&gt;Replace the declaration with the valid clamp&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2026-01-17-postcss-clampwind/meta-img.png&quot; alt=&quot;Screenshot of a code editor with utility css classes that output fluid-styled elements&quot;&gt;
&lt;em&gt;See the PostCSS  plugin in action at &lt;a href=&quot;https://clampwind.dev/&quot;&gt;clampwind.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;how-to-use-it&quot;&gt; How to use it&lt;/h2&gt;
&lt;p&gt;To use this plugin you need to use the &lt;code&gt;clamp()&lt;/code&gt; function but with &lt;strong&gt;only two arguments&lt;/strong&gt;, the first one is the minimum value and the second one is the maximum value.&lt;/p&gt;
&lt;h3 id=&quot;clamp-between-smallest-and-largest-breakpoint&quot;&gt; Clamp between smallest and largest breakpoint&lt;/h3&gt;
&lt;p&gt;Write the Tailwind utility you want to make fluid, without any breakpoint modifier, for example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will use Tailwind default largest and smallest breakpoint.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...) , &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clamp-between-two-breakpoints&quot;&gt; Clamp between two breakpoints&lt;/h3&gt;
&lt;p&gt;Simply add regular Tailwind breakpoint modifiers to the utility, for example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;md:max-lg:text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To clamp the CSS property between the two breakpoints you need to use the &lt;code&gt;max-&lt;/code&gt; modifier, in this case the CSS property will be clamped between the &lt;code&gt;md&lt;/code&gt; and &lt;code&gt;lg&lt;/code&gt; breakpoints.&lt;/p&gt;
&lt;p&gt;This will generate the following css:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;max-lg&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  @media (width &gt;= 48rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &gt;= 768px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    @media (width &amp;#x3C; 64rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &amp;#x3C; 1024px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...), &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clamp-from-one-breakpoint&quot;&gt; Clamp from one breakpoint&lt;/h3&gt;
&lt;p&gt;If you want to define a clamp value from a single breakpoint, postcss-clampwind will automatically generate the calculation from the defined breakpoint to the smallest or largest breakpoint depending on the direction, for example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;md:text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate the following css:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    @media (width &gt;= 48rem) {  &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &gt;= 768px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...), &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or if you use the &lt;code&gt;max-&lt;/code&gt; modifier:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.max-md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    @media (width &amp;#x3C; 48rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &amp;#x3C; 768px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...), &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clamp-between-custom-breakpoints&quot;&gt; Clamp between custom breakpoints&lt;/h3&gt;
&lt;p&gt;With Tailwind v4 it&#39;s really easy to use one-time custom breakpoints, and this plugin will automatically detect them and use them to clamp the CSS property.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;min-[1000px]:max-xl:text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate the following css:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.min-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1000px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;max-xl&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  @media (width &gt;= 1000px) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &gt;= 1000px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    @media (width &amp;#x3C; 64rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &amp;#x3C; 1600px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...), &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clamp-between-tailwind-spacing-scale-values&quot;&gt; Clamp between Tailwind spacing scale values&lt;/h3&gt;
&lt;p&gt;A quick way to define two clamped values is to use the Tailwind spacing scale values, for example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(16,50)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bare values size depends on the theme &lt;code&gt;--spacing&lt;/code&gt; size, so if you have have it set to &lt;code&gt;1px&lt;/code&gt; it will generate the following css:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...), &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clamp-custom-properties-values&quot;&gt; Clamp custom properties values&lt;/h3&gt;
&lt;p&gt;You can also use custom properties in your clamped values, for example like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(var(--text-sm),50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(--text-sm,--text-lg)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this won&#39;t work when using two custom properties directly in the CSS with &lt;code&gt;@apply&lt;/code&gt;, so you need to use the &lt;code&gt;var()&lt;/code&gt; function instead.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.h2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  @apply text-[clamp(var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--text-sm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;),var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--text-lg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;))];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;clamp-container-queries&quot;&gt; Clamp container queries&lt;/h3&gt;
&lt;p&gt;Postcss-clampwind supports container queries, just by using the normal Tailwind container query syntax, for example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;@md:text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will generate the following css:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt;.@md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt;16px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;,&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt;50px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;)&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  @container (width &gt;= 28rem) { &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* &gt;= 448px */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(...), &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;configuration&quot;&gt; Configuration&lt;/h2&gt;
&lt;p&gt;Tailwind v4 introduced the new CSS-based configuration and postcss-clampwind embraces it.&lt;/p&gt;
&lt;h3 id=&quot;add-custom-breakpoints&quot;&gt; Add custom breakpoints&lt;/h3&gt;
&lt;p&gt;To add new breakpoints in Tailwind v4 you normally define them inside the &lt;code&gt;@theme&lt;/code&gt; directive.&lt;/p&gt;
&lt;p&gt;But Tailwind by default, will not output in your CSS any custom properties that are not referenced in your CSS, for this reason you should use the &lt;code&gt;@theme static&lt;/code&gt; directive instead of &lt;code&gt;@theme&lt;/code&gt; to create custom breakpoints.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@theme&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; static {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  --breakpoint-4xl: 1600px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;set-a-default-clamp-range&quot;&gt; Set a default clamp range&lt;/h3&gt;
&lt;p&gt;You can set a default clamp range to use when no breakpoint modifier is used, like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To set a default clamp range you need to use the &lt;code&gt;--breakpoint-clamp-min&lt;/code&gt; and &lt;code&gt;--breakpoint-clamp-max&lt;/code&gt; custom properties, defined inside the &lt;code&gt;@theme static&lt;/code&gt; directive.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@theme&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; static {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  --breakpoint-clamp-min: 600px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  --breakpoint-clamp-max: 1200px;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will also apply for utilities that use only one breakpoint modifier. In this example the &lt;code&gt;md&lt;/code&gt; breakpoint will be used as the minimum breakpoint, and &lt;code&gt;--breakpoint-clamp-max&lt;/code&gt; will be used as the maximum breakpoint:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;md:text-[clamp(16px,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default clamp range will let you to simplify your utilities, since usually you don&#39;t need to clamp between the smallest and largest Tailwind breakpoints, but only between two breakpoints.&lt;/p&gt;
&lt;p&gt;You will still be able to clamp between any other Tailwind or custom breakpoints, even if out of the default clamp range.&lt;/p&gt;
&lt;h3 id=&quot;use-custom-properties&quot;&gt; Use custom properties&lt;/h3&gt;
&lt;p&gt;You can use any custom properties in your clamped values, for example:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;text-[clamp(--custom-value,50px)]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You just need to make sure that the custom property is defined in your &lt;code&gt;:root&lt;/code&gt; selector.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --custom-value&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;16&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;pixel-to-rem-conversion&quot;&gt; Pixel to rem conversion&lt;/h3&gt;
&lt;p&gt;If you are using pixel values in your clamped values, clampwind will automatically convert them to rem. For the conversion it scans your generated css and if you have set pixel values for the root &lt;code&gt;font-size&lt;/code&gt; or for your &lt;code&gt;--text-base&lt;/code&gt; custom property in your &lt;code&gt;:root&lt;/code&gt; selector, it will use that value to convert the pixel values to rem values. If you haven&#39;t set a font-size in your &lt;code&gt;:root&lt;/code&gt; selector, it will use the default value of 16px.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  font-size: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* 18px = 1.125rem */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;or like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --text-base&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* 18px = 1.125rem */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/postcss-clampwind&quot;&gt;danieledep/postcss-clampwind&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://clampwind.dev/&quot;&gt;Clampwind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs&quot;&gt;Tailwind CSS v4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Generate fluid styles with a Tailwind plugin</title>
		<link href="https://dan-webnotes.com/posts/2025-07-02-generate-fluid-styles-tailwind-plugin/"/>
		<updated>2025-07-02T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-07-02-generate-fluid-styles-tailwind-plugin/</id>
		<content type="html">&lt;p&gt;2025-07-02&lt;/p&gt;
&lt;h1 id=&quot;generate-fluid-styles-with-a-tailwind-plugin&quot;&gt; Generate fluid styles with a Tailwind plugin&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Tailwind is great and can do a lot of things, but it hasn&#39;t yet been adapted to generate fluid styling.&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Fluid CSS refers to the ability of setting fluid values to CSS properties that change proportionally with the width of the screen, or the container.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When typography and spacing system adapt fluidly to any size, the design can take full advantage of the available space, and always feel right to any screen size.&lt;/p&gt;
&lt;h2 id=&quot;existing-solutions&quot;&gt; Existing solutions&lt;/h2&gt;
&lt;p&gt;It&#39;s already possible to have fluid CSS, here are two of the most used solutions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://utopia.fyi/&quot;&gt;Utopia&lt;/a&gt;&lt;/strong&gt;, it&#39;s a project, open-source library and web-app that, given in input a set of requirements for the largest and smallest screen sizes, the largest and smallest type size (or spacing system size) and the number of steps, it outputs a set of CSS variables.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --step-0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.7955&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0.9091&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.5&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --step-1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.2&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.9239&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.2273&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.875&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --step-2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.44&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.0703&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.6432&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2.3438&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --step-3&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.728&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.2364&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 2.1849&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2.9297&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --space-xs&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.75&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.5966&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0.6818&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.125&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --space-s&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0.7955&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0.9091&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.5&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --space-m&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.5&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.1932&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.3636&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2.25&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --space-l&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1.5909&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.8182&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --space-xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2.3864&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 2.7273&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;4.5&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;rem&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can then use these CSS variables as building blocks to make your design system fluid.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--step-5&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--step-4&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;h3&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--step-3&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.card&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  padding-block: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--space-m&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  padding-inline: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--space-s&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  gap-y: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--space-2xs&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These CSS variables can also be used directly within Tailwind utility classes.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;article&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;py-(--space-m) px-(--space-s) gap-y-(--space-2xs)&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach is robust, but has the downside of not being easy to tweak. For example to change screen widths or the font-size ranges, it requires to generate again all the values. Or setting a different growing ratio, on a specific screen size range, is not possible.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://github.com/barvian/fluid-tailwind&quot;&gt;barvian/fluid-tailwind&lt;/a&gt;&lt;/strong&gt;, this Tailwind plugin generates the fluid css values on the spot, by defining the ranges in the utility classes directly. All the utility classes that have a &lt;code&gt;~&lt;/code&gt; in front of them are fluid. If no breakpoint is specified, the values interpolation takes place from the largest Tailwind breakpoint to the smallest.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;bg-sky-500 ~px-4/8 ~py-2/4 ~text-sm/xl ...&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;Fluid button&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;button&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can also define the starting and ending screen sizes directly in the utility classes, by using the variant modifier, always with a &lt;code&gt;~&lt;/code&gt; in front of them.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;~md/lg:~text-base/4xl&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;Quick increase&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This solution is very flexible and a nice but bespoke syntax. The main downside is that this plugin is not supported in Tailwind v4.&lt;/p&gt;
&lt;h2 id=&quot;plugin-requirements&quot;&gt; Plugin requirements&lt;/h2&gt;
&lt;p&gt;It&#39;s very convenient to use a simple symbol that conveys fluidity as the tilde &lt;code&gt;~&lt;/code&gt;, added in front of the utility classes that we already use.&lt;/p&gt;
&lt;p&gt;But, it would be nice if instead of setting the range of the CSS values in a single class, as &lt;a href=&quot;https://github.com/barvian/fluid-tailwind&quot;&gt;barvian/fluid-tailwind&lt;/a&gt; does, we could to extrapolate the range from the variant modifiers used in a single HTML element. Below is how a normal responsive styling looks like in Tailwind.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;mt-6 md:mt-8 text-base md:text-lg xl:text-xl&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Making these values fluid could be as simple as adding a tilde in front of all the utility classes and variant modifiers that we want to make fluid. That would make it very easy to adopt it incrementally in existing projects, or to remove them if not required anymore, just search all these characters in a codebase and remove them.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;~mt-6 ~md:mt-8 ~text-base ~md:text-lg ~xl:text-xl&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;prototyping&quot;&gt; Prototyping&lt;/h2&gt;
&lt;p&gt;The concept behind this proof-of-concept is to leverage CSS features to let the browser make most of the calculations, rather than the plugin.&lt;/p&gt;
&lt;h3 id=&quot;the-clamping-formula&quot;&gt; The clamping formula&lt;/h3&gt;
&lt;p&gt;The values needed to calculate the interpolation formula of two values within a screen-size range are four:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Min value&lt;/li&gt;
&lt;li&gt;Max value&lt;/li&gt;
&lt;li&gt;Min screen size&lt;/li&gt;
&lt;li&gt;Max screen size&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To set a fluid value in CSS, the standard approach is using the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clamp&quot;&gt;clamp()&lt;/a&gt; function.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;font-size&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: clamp(minValue&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; preferred&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;  maxValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;preferred&lt;/code&gt; value is a CSS &lt;code&gt;calc()&lt;/code&gt; function, where we calculate the ratio with which the CSS value scales, starting at the set minimum screen size.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;font-size&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: clamp(minValue&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; calc(intercept &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; slope &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 100vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;),  &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And both the &lt;code&gt;intercept&lt;/code&gt; and the &lt;code&gt;slope&lt;/code&gt; can be calculated using the four values.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;font-size&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: clamp(minValue&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; calc((minValue - ((maxValue - minValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)/(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxScreen - minScreen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; minScreen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) + ((&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxValue - minValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)/(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxScreen - minScreen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 100vw&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;),  &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;tailwindcss-fluid-variants-v0-0-1&quot;&gt; tailwindcss-fluid-variants v0.0.1&lt;/h2&gt;
&lt;p&gt;To make the browser calculate this style we can express the four values needed for the clamping formula as &lt;strong&gt;CSS custom properties&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Tailwind plugins can easily add CSS properties declarations to a utility class it generates. First, we use the &lt;code&gt;matchVariant()&lt;/code&gt; function from the &lt;a href=&quot;https://v3.tailwindcss.com/docs/plugins&quot;&gt;Tailwind Plugins APIs&lt;/a&gt;, to register custom dynamic variants, such as &lt;code&gt;~md:&lt;/code&gt;, &lt;code&gt;~lg:&lt;/code&gt;, &lt;code&gt;~xl:&lt;/code&gt;,etc. These new custom variants, instead of ouputting a single fixed value for a CSS property will output &lt;strong&gt;3 custom properties&lt;/strong&gt; and a CSS property with a &lt;code&gt;clamp()&lt;/code&gt; value, this is an example.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;lg&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --font-size-lg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* Also this because math */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But to make the calculation happen, without knowing which utility classes will be eventually used in the same HTML element, each fluid utility class should evaluate any possible value for the CSS property it describes.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;minValue = min(--font-size-sm&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-md&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-lg&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxValue = max(--font-size-sm&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-md&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-lg&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;minScreen = min(--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;maxScreen = max(--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; --font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; ...&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final clamp formula with all the terms in place, will look like this.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;lg&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --font-size-lg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;24&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;min&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; min&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;))) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;max&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; min&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)))) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; min&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;999999&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;))) * &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) + calc((max(var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0)) - min(var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999))) / (max(var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0)) - min(var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl-screen&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 999999)))) * 100vw), max(var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-sm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0px), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-md&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0px), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-lg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0px), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0px), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--font-size-2xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 0px)));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Unfortunately this will add more than &lt;strong&gt;2kb of CSS for each utility class.&lt;/strong&gt; Also this works, but only interpolating between a single pair of CSS values, within a single range of screen sizes.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;~md:mt-6 ~lg:mt-10 ~xl:mt-8&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example this will only calculate a clamp from 768px to 1280px, but the range value will be between 24px and 40px, because the value set in &lt;code&gt;~lg:mt-10&lt;/code&gt; is the largest.&lt;/p&gt;
&lt;h2 id=&quot;tailwindcss-fluid-variants-v0-0-2&quot;&gt; tailwindcss-fluid-variants v0.0.2&lt;/h2&gt;
&lt;p&gt;It&#39;s actually possible to have the fluid values respect internal breakpoints when defined, but the plugin needs to generate all the possible breakpoints, whenever I have a fluid utility&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --f-s-md&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --f-s-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;  --f-s-md-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;768&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (max-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;767&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;768&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (max-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1023&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (max-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1279&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;18px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the CSS value needs to use &lt;code&gt;var()&lt;/code&gt; order instead of &lt;code&gt;min()&lt;/code&gt; and &lt;code&gt;max()&lt;/code&gt; where each leg of the internal breakpoints has the CSS variables  to look for the next breakpoint depending on the direction, &lt;strong&gt;with the fallback of each variable, being the variable for the next breakpoint.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To make it easier to understand the mechanism see how the values at the edges are calculated.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* Min value at smaller breakpoint */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;var(--f-s-sm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* Max value at smaller breakpoint */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;var(--f-s-md&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--f-s-lg&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--f-s-xl&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; var(--f-s-2xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;))))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A complete example for the range between two breakpoints would then look like this.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (max-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;767&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;  .&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;), &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; calc&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)))) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-md-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-lg-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-xl-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-2xl-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)))) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;))) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;640&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) * &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) + calc((var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-md-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-lg-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-2xl-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 20)))) - var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm-int&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 20)) / (var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-md-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-lg-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-xl-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-2xl-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 640)))) - var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-sm-scr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, 640))) * 100vw), var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-md&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-lg&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, var(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--f-s-2xl&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)))));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apart from this resulting in some massive CSS, I also encountered some issues where the outer values, for example &lt;code&gt;sm&lt;/code&gt;, &lt;code&gt;2xl&lt;/code&gt;, are missing and there is no CSS variable fallback to calculate the clamping.&lt;/p&gt;
&lt;p&gt;A possible fix would require a fragile solutions like applying the big formula only to elements that actually have the utility classes.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1024&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (max-width: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1279&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;  :is&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;~xl:text&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;~&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;md&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;text-&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;20px&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;&#92;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;~2xl:text&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    font-size: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;clamp&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;...&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This could be handled in the future with CSS &lt;code&gt;if()&lt;/code&gt; function&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;if(--f-s-sm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Eventually this works and I can say lessons where learned, but..&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;More than 4kb for each utility class&lt;/li&gt;
&lt;li&gt;Fragile class selector&lt;/li&gt;
&lt;li&gt;doesn&#39;t work with @apply&lt;/li&gt;
&lt;li&gt;only tailwind v3 compatible&lt;/li&gt;
&lt;li&gt;doesn&#39;t allow for custom ranges&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/barvian/fluid-tailwind&quot;&gt;barvian/fluid-tailwind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/clamp&quot;&gt;clamp() - MDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://v3.tailwindcss.com/docs/plugins&quot;&gt;Plugins - Tailwind CSS (v3)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://utopia.fyi/&quot;&gt;Utopia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Convert any webpage to SVG and plot it</title>
		<link href="https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/"/>
		<updated>2025-02-02T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/</id>
		<content type="html">&lt;p&gt;2025-02-02&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/chrome.png&quot; alt=&quot;A screenshot of a web page converted to gcode&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;convert-any-webpage-to-svg-and-plot-it&quot;&gt; Convert any webpage to SVG and plot it&lt;/h1&gt;
&lt;p&gt;Here is how this was achieved:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run a &lt;strong&gt;Node&lt;/strong&gt; application that fetches a URL, uses &lt;a href=&quot;https://github.com/mozilla/readability&quot;&gt;mozilla/readability&lt;/a&gt; to turn that page to a simplified document with only the minimally-styled page content, what you normally see when you turn on &lt;strong&gt;Reader-mode&lt;/strong&gt; on your browser of choice&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The result of this transformation is written to a client-side &lt;code&gt;index.html&lt;/code&gt;, here is how some CSS splits the result into separate pages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;:root&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	--page-width&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;14&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;cm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	--page-height&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;21&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;cm&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	--page-gutter&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;px&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;#content&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	width: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--page-width&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	height: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--page-height&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	column-width: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--page-width&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	column-gap: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;--page-gutter&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The neat thing about this is that the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/column-width&quot;&gt;column-width&lt;/a&gt; CSS property makes paginating really easy, while using physical units as &lt;code&gt;cm&lt;/code&gt; to control the pages dimensions. These don&#39;t match perfectly with the real world centimeters of course, because its actual size depends from screen pixel density and DPI but it&#39;s good enough for this experiment. The CSS variables are editable with the control panel using &lt;a href=&quot;https://github.com/cocopon/tweakpane&quot;&gt;cocopon/tweakpane&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/tweakpane.png&quot; alt=&quot;A screenshot of the control panel&quot;&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Next, a convoluted recursive function parses the block elements of the DOM, and converts the text to SVG paths. If only parsing this beautiful soup of block and inline elements was easy as it sounds, the browser would have suffered much less.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/screenshot-crash.png&quot; alt=&quot;Node collection handling&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;hershey-text&quot;&gt; Hershey text&lt;/h2&gt;
&lt;p&gt;This project uses  the library &lt;a href=&quot;https://github.com/techninja/hersheytextjs&quot;&gt;techninja/hersheytextjs&lt;/a&gt; to convert the text content to SVG. This library is a javascript port of the great &lt;a href=&quot;https://www.evilmadscientist.com/2011/hershey-text-an-inkscape-extension-for-engraving-fonts&quot;&gt;Hershey Text Inkscape Plugin&lt;/a&gt;. The library reads font data from &lt;strong&gt;SVG font&lt;/strong&gt; files, containing the letter paths of a font family and renders them inside a SVG element.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; renderText&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textContent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	font&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; selectedFont&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; scaleFont&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	pos&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;x&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;y&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; yOffset&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Those fonts are &lt;a href=&quot;https://en.wikipedia.org/wiki/Hershey_fonts&quot;&gt;Hershey fonts&lt;/a&gt;, a set of characters made of single vector paths, developed around 1967 by Dr. Allen Vincent Hershey at the Naval Weapons Laboratory, to be displayed on early cathode ray tube displays.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/hershey-simplex.jpeg&quot; alt=&quot;Hershey letter glyphs&quot;&gt;
&lt;em&gt;Set of Hershey characters&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Their path-only, vector nature makes it very easy drawing text with CNC machines, and  solves a few problems since vectorizing any piece of text creates an empty outline, and it doesn&#39;t work great with very small text.&lt;/p&gt;
&lt;h2 id=&quot;images&quot;&gt; Images&lt;/h2&gt;
&lt;p&gt;It is possible to render images as SVG paths with some algorithms used in the pen-plotter world. Some of the most used ones can be compared with this great browser tool &lt;a href=&quot;https://github.com/mitxela/plotterfun&quot;&gt;mitxela/plotterfun&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After evaluating a few of them, I decided to ditch images for the moment being. While the final effect is visually interesting it&#39;s very hard to convey effectively the content of an image of a typical online article. I wonder if some AI model could get any image in input and then style-transfer it to a realistic simplified line-art image and then convert that to SVG.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/girl-stipples.png&quot; alt=&quot;&#39;Girl with a pearl earring&#39; rendered in SVG using the Stipples algorithm&quot;&gt;
&lt;em&gt;&#39;Girl with a pearl earring&#39; rendered in SVG using the Stipples algorithm&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;layout&quot;&gt; Layout&lt;/h2&gt;
&lt;p&gt;In this project the HTML content is parsed block by block and is rendered using a different set of Hershey fonts. H1, H2, etc headings would use larger bold fonts, &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; are rendered with an italic font and code blocks with a mono-style font.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;switch&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;element&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;parentNode&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;nodeName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;H1&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;fontBold&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontBoldName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.75&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		break&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;H2&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;fontBold&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontBoldName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.5&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		break&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;H3&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;fontBold&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontBoldName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.25&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		break&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;H4&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;H5&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;H6&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;fontBold&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontBoldName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1.1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		break&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;EM&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;fontItalic&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontItalicName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		break&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	case&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;PRE&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;fontMono&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontMonoName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		break&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	default&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		renderedFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; PARAMS&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;font&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;fontName&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		scaleFont&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The output page would have the same dimensions of the HTML content paginated with the CSS properties &lt;code&gt;column-width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;, with the possibility of then downloading the content split in different convenient separate files.&lt;/p&gt;
&lt;h2 id=&quot;gcode&quot;&gt; Gcode&lt;/h2&gt;
&lt;p&gt;The final vision was to download the SVG files of any page and feed these into &lt;strong&gt;Inkscape&lt;/strong&gt; to be converted to a gcode file with the workflow described before,
&lt;a href=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/&quot; class=&quot;gradient-before&quot;&gt;Convert a 3D printer into a pen plotter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-02-02-convert-web-page-svg-plot-it/inkscape.png&quot; alt=&quot;A web page converted to gcode&quot;&gt;
&lt;em&gt;A blog post converted to gcode&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This way, you could technically plot small neat pages of any interesting article, blog post or documentation to be binded together in a sort of &lt;strong&gt;physical reading list.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusions&quot;&gt; Conclusions&lt;/h2&gt;
&lt;p&gt;Few things turned out to be pretty complicated such as parsing inline elements, especially when they would wrap onto new lines, also generally handling DOM nodes with javascript is messy.&lt;/p&gt;
&lt;p&gt;As mentioned above, rendering images to SVG using AI would make for an interesting additional project but I&#39;m wrapping this one up for the moment.&lt;/p&gt;
&lt;p&gt;Many other ideas were continuously coming up out of this project, a browser extension, a markdown input mode, generate gcode directly in the browser, design a bespoke mini-plotter, and many more, but I&#39;ve decided to move on to other projects.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cocopon/tweakpane&quot;&gt;cocopon/tweakpane&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.evilmadsciencontent/posts/pen-plotter-resources/tweakpane.pngtist.com/Hatch_fill&quot;&gt;Hatch fill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://hackaday.com/2021/03/30/hershey-fonts-not-chocolate-the-origin-of-vector-lettering/&quot;&gt;Hershey fonts: not chocolate, the origin of vector lettering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.evilmadscientist.com/Hershey_Text&quot;&gt;Hershey Text&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.evilmadscientist.com/2011/hershey-text-an-inkscape-extension-for-engraving-fonts/&quot;&gt;Hershey Text: An Inkscape extension for engraving fonts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://paulbourke.net/dataformats/hershey/&quot;&gt;Hershey Vector Font&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jankovicsandras/imagetracerjs&quot;&gt;jankovicsandras/imagetracerjs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jvolker/single-line-font-renderer&quot;&gt;jvolker/single-line-font-renderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mitxela/plotterfun&quot;&gt;mitxela/plotterfun&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mozilla/readability&quot;&gt;mozilla/readability&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/msurguy/cnc-text-tool&quot;&gt;msurguy/cnc-text-tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.com/oskay/svg-fonts&quot;&gt;oskay/svg-fonts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/philschmid/clipper.js&quot;&gt;philschmid/clipper.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/plottertools/hatched&quot;&gt;plottertools/hatched&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mattwidmann.net/notes/plotting-raster-images/&quot;&gt;Plotting raster images&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://wiki.evilmadscientist.com/StippleGen&quot;&gt;StippleGen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://benjdd.com/posts/stylized-image-binning-algorithm&quot;&gt;Stylized image binning algorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/techninja/hersheytextjs&quot;&gt;techninja/hersheytextjs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Paper over files: print a blog post in plain markdown</title>
		<link href="https://dan-webnotes.com/posts/2025-01-17-paper-over-file/"/>
		<updated>2025-01-17T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-01-17-paper-over-file/</id>
		<content type="html">&lt;p&gt;2025-01-17&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-01-17-paper-over-file/printer.jpg&quot; alt=&quot;A paper printer printing out the markdown version of this post&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;paper-over-files-print-a-blog-post-in-plain-markdown&quot;&gt; Paper over files: print a blog post in plain markdown&lt;/h1&gt;
&lt;p&gt;Front-end developers spend a lot of time thinking about the way a website content is going to be consumed. Not only a web page must work well on devices of all sizes and formats, but a website content must also take &lt;strong&gt;accessibility&lt;/strong&gt; into consideration. This means the markup should use all the proper semantics and attributes to be parsed effectively by screen readers and other assistive technologies. On top of this content and markup is constructed to be processed by &lt;strong&gt;search engines&lt;/strong&gt; too, which means another set of attributes and metadata to be added to the page.&lt;/p&gt;
&lt;p&gt;Interestingly, another way to consume a website content, which is often overlooked, is by printing it. The CSS specification for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Printing&quot;&gt;printing styles&lt;/a&gt; is actually quite rich has existed for a very long time. It allows to set specific styles for printing a page by using the &lt;code&gt;@media print&lt;/code&gt; rule. This can be used to remove unnecessary elements from the page, like navigation bars, sidebars, and footers, and to style the content in a way that is more suitable for printing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That made me think that printing a blog post, whose content was originally generated from a markdown file, can actually be a way of preserving its original content and make it even portable on the long term.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;With few CSS rules, it is possible to style the content in a way that reflects the plain text which generated it, and it can be done without any JavaScript or server-side processing. This technique uses the CSS pseudo-elements &lt;code&gt;::before&lt;/code&gt; and &lt;code&gt;::after&lt;/code&gt; to add the markdown syntax to the content, like &lt;code&gt;#&lt;/code&gt; for headings, &lt;code&gt;*&lt;/code&gt; for strong text, &lt;code&gt;_&lt;/code&gt; for emphasized text, and &lt;code&gt;-&lt;/code&gt; for list items. Here are some examples of how this can be done.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@media&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt; print&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	h1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;# &quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	strong&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;**&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	strong&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;**&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	em&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	em&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;_&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	ul&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &gt;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; li&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::marker&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;- &quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	pre&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;language-&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;```&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		display: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	pre&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;*=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;language-&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;```&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		display: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This technique can be used to generate the markdown syntax for links by using the &lt;code&gt;attr()&lt;/code&gt; function to get the value of the &lt;code&gt;href&lt;/code&gt; attribute of the link and add it to the content of the pseudo-element.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;[&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;](&quot;&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; attr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;)&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method has some limitations though, as it can&#39;t be used to style images, since replaced elements can&#39;t have pseudo-elements. This means that images will be printed as they are, without any markdown syntax.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;/* Not working because replaced elements can&#39;t have pseudo elements */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;img&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;picture&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::after&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	display: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;![&quot;&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; attr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;alt&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;](&quot;&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; attr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;)&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This experiment is inspired by the original &lt;a href=&quot;https://secretgeek.github.io/html_wysiwyg/html.html/&quot;&gt;html quine&lt;/a&gt;, which uses the same technique to print the HTML tags next to the content.&lt;/p&gt;
&lt;p&gt;This is it! 🖨️ Click &lt;code&gt;CMD&lt;/code&gt; + &lt;code&gt;P&lt;/code&gt; to print this page, and see how the plain markdown of this page looks. If are looking to implement this on your blog too you can grab the file in the repository and let me know how it goes.&lt;/p&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/print-markdown&quot;&gt;danieledep/print-markdown&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stephango.com/file-over-app&quot;&gt;File over app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Printing&quot;&gt;Printing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/secretGeek/html_wysiwyg&quot;&gt;secretGeek/html_wysiwyg&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://secretgeek.github.io/html_wysiwyg/html.html&quot;&gt;This page is a truly naked, brutalist html quine.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>A code-sandbox web component</title>
		<link href="https://dan-webnotes.com/posts/2025-01-11-code-sandbox-web-component/"/>
		<updated>2025-01-11T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-01-11-code-sandbox-web-component/</id>
		<content type="html">&lt;p&gt;2025-01-11&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2025-01-11-code-sandbox-web-component/code-sandbox-screenshot.png&quot; alt=&quot;A screenshot of the code-sandbox web component on a green leafy background&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;a-code-sandbox-web-component&quot;&gt; A code-sandbox web component&lt;/h1&gt;
&lt;p&gt;This is a fork of &lt;a href=&quot;https://gist.github.com/cferdinandi/df9c95ae5f5ebcddf2ab85bb2805ff07&quot;&gt;code-sandbox&lt;/a&gt; web component from &lt;a href=&quot;https://gomakethings.com&quot;&gt;Chris Ferdinandi&lt;/a&gt; for displaying an interactive code sandbox for HTML, CSS and javascript, similar to what &lt;strong&gt;CodePen&lt;/strong&gt; does.&lt;/p&gt;
&lt;p&gt;Having a code sandbox web component can be useful for showing code snippets in a more interactive way, and it doesn&#39;t require any external third-party services like &lt;strong&gt;CodePen&lt;/strong&gt; or &lt;strong&gt;JSFiddle&lt;/strong&gt;. This was worked on to be included in a &lt;a href=&quot;https://dan-webnotes.com/posts/2025-01-04-vanilla-project-starter-template/&quot; class=&quot;gradient-before&quot;&gt;vanilla project-starter template&lt;/a&gt; but it can be easily used in any project.&lt;/p&gt;
&lt;p&gt;Also being a web component, it means it can be used in any framework or vanilla JavaScript and it will always work, since it doesn&#39;t depend on any framework. The only dependency it uses is &lt;a href=&quot;https://prismjs.com/&quot;&gt;PrismJS&lt;/a&gt; for syntax highlighting, which can be included directly in the JavaScript file. This fork adds a few useful features to the original code too.&lt;/p&gt;
&lt;code-sandbox hidden=&quot;&quot; name=&quot;code-sandbox-1&quot;&gt;
&lt;/code-sandbox&gt;
&lt;h3 id=&quot;fetching-files-from-a-url&quot;&gt; Fetching files from a URL&lt;/h3&gt;
&lt;p&gt;By just adding a &lt;code&gt;src&lt;/code&gt; attribute to the &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; inside the web component it will load the content inside the mini-editor. This can allow keeping the code snippets in a separate file and include them only on page load. It can fetch both a local file or a remote file.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;html&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;demo.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;markdown-compatibility&quot;&gt; Markdown compatibility&lt;/h3&gt;
&lt;p&gt;If inside the &lt;code&gt;&amp;lt;code-sandbox&amp;gt;&lt;/code&gt; there is a &lt;code&gt;&amp;lt;pre class=&amp;quot;language-*&amp;quot;&amp;gt;&lt;/code&gt; which is how markdown processors render code blocks, it will use that snippet to populate the code for the editor.&lt;/p&gt;
&lt;p&gt;This can be useful when using markdown files with code snippets because it adds a touch of progressive enhancement, since if the web component is not loaded, the code block will still be displayed.&lt;/p&gt;
&lt;p&gt;Below there is an example of how it can be used within a markdown file.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;code-sandbox&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;```js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;console&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;log&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;Hello, world!&#39;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;```&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/code-sandbox&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;h6&gt;⚠️ Warning:&lt;/h6&gt;
&lt;p&gt;This functionality can be a bit buggy, depending on the markdown processor doing the rendering&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;exclusive-accordions&quot;&gt; Exclusive accordions&lt;/h3&gt;
&lt;p&gt;By adding a &lt;code&gt;name&lt;/code&gt; attribute to the web component, it will attach that name to all the &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; elements in the sandbox, making only one editor open at the time, leveraging the native element behavior.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; name&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;code-sandbox-1&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt; &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;css-container-queries&quot;&gt; CSS Container queries&lt;/h3&gt;
&lt;p&gt;Web components are the ideal use-case for css container queries, since they can be included in different contexts of a web page and their rendered size can change independently of the screen size.&lt;/p&gt;
&lt;p&gt;It&#39;s fairly easy to use container queries to control the sandbox layout, the &lt;code&gt;container-type&lt;/code&gt; just needs to be defined on the root element of the web component.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	container-type: inline-size;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that, the container queries can be used to control the layout of the sandbox.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@container&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (min-width: 768px) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;	.sandbox-content&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		grid-template-columns: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;repeat&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E06C75&quot;&gt;fr&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;empty-playground&quot;&gt; Empty playground&lt;/h3&gt;
&lt;p&gt;If no &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; is present inside the &lt;code&gt;&amp;lt;code-sandbox&amp;gt;&lt;/code&gt; web component it will create an empty editor. This can be useful when you want to show an empty playground for the user to start coding, but at the same time keep control of which editors are displayed. Eg: if only the html editor is present, the css and js editors will not be displayed.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt; &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;attributes&quot;&gt; Attributes&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;console&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;If present displays the console (Optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;hidden&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Used to prevent flashes of unstyled content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The name attribute to be attached to the &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; elements, which makes only one open at the time (Optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;result&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Controls what is displayed on the right side panel, can either be &lt;code&gt;iframe&lt;/code&gt; or &lt;code&gt;console&lt;/code&gt;. Defaults to &lt;code&gt;iframe&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;src&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The URL of the file to fetch and run in the sandbox. Can be on the same origin or a remote file (Optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The title of the code block, defaults to &lt;code&gt;Code sandbox&lt;/code&gt;. (Optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/code-sandbox&quot;&gt;danieledep/code-sandbox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/cferdinandi/df9c95ae5f5ebcddf2ab85bb2805ff07&quot;&gt;cferdinandi/code-sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prismjs.com/&quot;&gt;PrismJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/languages/webc/&quot;&gt;WebC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Serve static files with Eleventy</title>
		<link href="https://dan-webnotes.com/posts/2025-01-06-serve-static-files-eleventy/"/>
		<updated>2025-01-06T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-01-06-serve-static-files-eleventy/</id>
		<content type="html">&lt;p&gt;2025-01-06&lt;/p&gt;
&lt;h1 id=&quot;serve-static-files-with-eleventy&quot;&gt; Serve static files with Eleventy&lt;/h1&gt;
&lt;p&gt;Eleventy is a static site generator that can be configured to do everything that you can imagine. A nice addition for a technical blog can be to serve static files. This is useful when you want to include files like PDFs, or downloadable code snippets in your project. This was a research needed to make the &lt;a href=&quot;https://dan-webnotes.com/posts/2025-01-11-code-sandbox-web-component/&quot; class=&quot;gradient-before&quot;&gt;code-sandbox web component&lt;/a&gt; fetch files correctly.&lt;/p&gt;
&lt;p&gt;The first tool to reach to in this case, is &lt;a href=&quot;https://www.11ty.dev/docs/copy/&quot;&gt;Passthrough File Copy&lt;/a&gt;, the Eleventy utility that allows you to copy files from the input directory to the output directory, otherwise Eleventy will ignore all non-templates files.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;addPassthroughCopy&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;content/posts/*/**/*.{js,pdf}&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command allow you to put the files directly in your posts directory and Eleventy will copy them to the output directory while &lt;strong&gt;preserving the same directory structure&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;bundling-with-vite&quot;&gt; Bundling with Vite&lt;/h2&gt;
&lt;p&gt;Vite is the most recommended bundling tool for Eleventy and this blog too has been originally setup to use Vite to run after the Eleventy build, using the official Eleventy plugin &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite&quot;&gt;eleventy-plugin-vite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This works very well for quickly setting up a feature-rich development environment, because its default configuration provides a lot of features out-of-the-box, like asset hashing, tree-shaking, and of course, bundling and minification of JavaScript and CSS files.&lt;/p&gt;
&lt;p&gt;However, in case you want to serve static files the Vite step can silently work against you, since Vite will remove all files which are not linked in the outputted html files or hash and move, usually in the &lt;code&gt;/asset&lt;/code&gt; folder, the rest of the files during in the production build, and this can break the links to the files in your posts.&lt;/p&gt;
&lt;p&gt;After a tedious debug to figure out which was the issue, a possible solution is funnily another Vite unsolicited feature, the &lt;a href=&quot;https://vite.dev/guide/assets#the-public-directory/&quot;&gt;public directory&lt;/a&gt;. Maybe it&#39;s not widely known that Vite by default will copy the files in the public directory to the output directory without touching them, and it will also flat the &lt;code&gt;/public&lt;/code&gt; directory structure in the project root.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;public&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; assets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; pdf.pdf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; og-image.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will be transformed to this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;dist&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;├──&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; assets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;│&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;   └──&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; pdf.pdf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;└──&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; og-image.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To take advantage of this feature, you can copy all the static files to the &lt;code&gt;/public/asset&lt;/code&gt; directory, which Vite will then move to the root output directory leaving only the existing &lt;code&gt;/asset&lt;/code&gt; folder.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;addPassthroughCopy&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;	&quot;content/posts/*/**/*.{js,pdf}&quot;&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;public/assets&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I can then link the files in the markdown files like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Download PDF&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;demo.pdf&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And transform the link in the final HTML to point to the correct location with &lt;code&gt;eleventy-plugin-markdown-links&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;mdLib&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;markdownItLinks&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	processHTML&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// defaults to false for backwards compatibility&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;	replaceLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;htmlToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		if&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;endsWith&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;.pdf&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;			// add class to the link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; newToken&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; token&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; newLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;/assets/&quot;&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; title&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;split&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;pop&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;			newToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;attrs&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;				[&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;href&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;newLink&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;				[&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;target&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;_blank&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;				[&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;download&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;title&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;			];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; newToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;css-icon&quot;&gt; CSS Icon&lt;/h2&gt;
&lt;p&gt;To display a nice little icon in front of downloadable files, I added a CSS down arrow to the &lt;code&gt;markdown.css&lt;/code&gt;, like this &lt;a href=&quot;https://dan-webnotes.com/posts/2025-01-06-serve-static-files-eleventy/demo.pdf&quot; target=&quot;_blank&quot; download=&quot;demo.pdf&quot;&gt;demo.pdf&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;$=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;.pdf&quot;&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::before&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	content: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	display: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;inline-block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	background-color: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;currentColor&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	mask-image: &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;data:image/svg+xml,%3Csvg ... %3E&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	mask-repeat: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;no-repeat&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	mask-size: &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#D19A66&quot;&gt;contain&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;update-07-06-2026&quot;&gt; Update: 07-06-2026&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;public/assets&lt;/code&gt; trick worked, but it flattened everything. Every match collapsed to its basename and landed in a single folder, so two posts each shipping a &lt;code&gt;demo.js&lt;/code&gt; would clobber each other, and a relative &lt;code&gt;src=&amp;quot;demo.js&amp;quot;&lt;/code&gt; from a code-sandbox had nothing sensible to point at.&lt;/p&gt;
&lt;p&gt;The fix is to stop fighting Vite and lean on how it actually treats &lt;code&gt;public/&lt;/code&gt;: it copies the directory verbatim, structure and all. So instead of remapping with a glob, I mirror each file&#39;s &lt;code&gt;posts/&amp;lt;slug&amp;gt;/&lt;/code&gt; path under &lt;code&gt;public/&lt;/code&gt;. Vite then emits it at &lt;code&gt;/posts/&amp;lt;slug&amp;gt;/&amp;lt;file&amp;gt;&lt;/code&gt;, right next to the post, and a relative &lt;code&gt;src=&amp;quot;demo.js&amp;quot;&lt;/code&gt; just works.&lt;/p&gt;
&lt;p&gt;A glob remap can&#39;t do this on its own, because Eleventy collapses every match down to its basename — which is exactly what was flattening everything in the first place.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;- eleventyConfig.addPassthroughCopy({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;- 	&quot;content/posts/*/**/*.{js,pdf}&quot;: &quot;public/assets&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;- });&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ for (const rel of fs.readdirSync(&quot;content/posts&quot;, { recursive: true })) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ 	const keep = [&quot;.js&quot;, &quot;.css&quot;, &quot;.html&quot;, &quot;.json&quot;, &quot;.pdf&quot;, &quot;.gcode&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ 		&quot;.jpg&quot;, &quot;.jpeg&quot;, &quot;.png&quot;, &quot;.gif&quot;, &quot;.webp&quot;, &quot;.avif&quot;, &quot;.svg&quot;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ 	if (!keep.includes(path.extname(rel).toLowerCase())) continue;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ 	eleventyConfig.addPassthroughCopy({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ 		[path.join(&quot;content/posts&quot;, rel)]: path.posix.join(&quot;public/posts&quot;, rel),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ 	});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;+ }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Images are in the keep list too, so a sandbox demo can load one with a relative &lt;code&gt;src=&amp;quot;…&amp;quot;&lt;/code&gt; — the markdown image pipeline only handles &lt;code&gt;![](…)&lt;/code&gt; syntax.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/crookedneighbor/markdown-it-link-attributes&quot;&gt;crookedneighbor/markdown-it-link-attributes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite&quot;&gt;eleventy-plugin-vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/copy/&quot;&gt;Passthrough File Copy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vite.dev/guide/assets#the-public-directory&quot;&gt;Static Asset Handling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#download&quot;&gt;The Anchor element - Download&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy-plugin-vite/issues/26&quot;&gt;Vite chokes generated *.bib files in production build? #26&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Web components and Eleventy</title>
		<link href="https://dan-webnotes.com/posts/2025-01-04-web-components-eleventy/"/>
		<updated>2025-01-04T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-01-04-web-components-eleventy/</id>
		<content type="html">&lt;p&gt;2025-01-04&lt;/p&gt;
&lt;h2 id=&quot;web-components-and-eleventy&quot;&gt; Web components and Eleventy&lt;/h2&gt;
&lt;p&gt;The curse and the beauty of Eleventy is that there are a many ways to achieve something. At the same time web components lend themselves to be handled pretty freely because after all, it&#39;s just client-side JavaScript.&lt;/p&gt;
&lt;p&gt;Eleventy guides you in their docs to use &lt;a href=&quot;https://www.11ty.dev/docs/languages/webc/&quot;&gt;WebC&lt;/a&gt;, which is their most recommended way to handle web components and offers some benefits like compatibility with server-side rendering and a more structured way to handle web components.&lt;/p&gt;
&lt;p&gt;But the beauty of web components should be that they are framework agnostic, and you can just copy and paste the CSS and javascript file to any project and they will work.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;src/js/my-component.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;src/css/my-component.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;my-component&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It can be that simple. But if you want to just have some basic page size optimization and load the CSS and JS only when the component is present, you can use the following snippet.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; in&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; components&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component_css_url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;src/css/&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;set&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component_js_url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;src/js/&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {%- &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component_css_url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}{%- &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endcss&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {%- &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;js&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; component_js_url&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endjs&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endfor&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then in the front matter of the markdown file you can specify which components to load.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;title: &quot;Web components and Eleventy&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;components: [&quot;my-component&quot;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/languages/webc/&quot;&gt;WebC&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Vanilla project starter template</title>
		<link href="https://dan-webnotes.com/posts/2025-01-04-vanilla-project-starter-template/"/>
		<updated>2025-01-04T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2025-01-04-vanilla-project-starter-template/</id>
		<content type="html">&lt;p&gt;2025-01-04&lt;/p&gt;
&lt;h1 id=&quot;vanilla-project-starter-template&quot;&gt; Vanilla project starter template&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;It&#39;s quite a common experience for front-end developers go picking up a project that&#39;s not been touched for a while and find it hard to get a development environment running in a few minutes.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What usually happens is that the project is using a framework or a build tool that&#39;s not been updated in a while, or wrong project choices were made.&lt;/p&gt;
&lt;p&gt;This project aims to provide a simple starter project using vanilla javascript, few dependencies as possible and following some sensible good practices.&lt;/p&gt;
&lt;h2 id=&quot;no-frameworks&quot;&gt; No frameworks&lt;/h2&gt;
&lt;p&gt;Nowadays frameworks are a must for any project, and full-featured frameworks like React are not the only option, for example &lt;a href=&quot;https://alpinejs.dev&quot;&gt;AlpineJS&lt;/a&gt; is perfect for adding just few interactive components. But for this project the aim is not to use any framework by default, just plain vanilla javascript, and for the few components that need to be interactive, &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;Web Components&lt;/a&gt; will be used, they do not provide the best developer experience, but they are the most future-proof way to create reusable components, and can be ported to any project without any issues.&lt;/p&gt;
&lt;h2 id=&quot;no-build-tools&quot;&gt; No build tools&lt;/h2&gt;
&lt;p&gt;This starter template doesn&#39;t come with a predefined build tool, all assets and dependencies are linked into &lt;code&gt;index.html&lt;/code&gt; directly, leveraging native &lt;strong&gt;ES modules imports&lt;/strong&gt; and web components. Each component or functionality is a separate file that can be imported if needed or commented out if not. All external dependencies are included from &lt;strong&gt;CDN links.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Main CSS --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css/main.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Utils CSS --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css/utils.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Prism CSS --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css/prism-one-dark.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Code sandbox CSS --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css/code-sandbox.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Markdown CSS --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; href&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css/markdown.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; rel&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;stylesheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Tailwind CDN Script --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;https://cdn.tailwindcss.com&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- State management --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/state.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;  &amp;#x3C;!-- Components --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/prism.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/md-block.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/tweakpane.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/code-sandbox.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/counter-display.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js/counter-button.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;script&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, if you need to use build tools, add &lt;strong&gt;npm-installed dependencies,&lt;/strong&gt; add &lt;strong&gt;hot-reloading,&lt;/strong&gt; etc, &lt;a href=&quot;https://vite.dev&quot;&gt;Vite&lt;/a&gt; is the recommended build tool, and I&#39;ve added a light guide on how to set it up in the &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install Vite&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -D&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; vite&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;Run Vite&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;npx&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; vite&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;reusable-components&quot;&gt; Reusable components&lt;/h2&gt;
&lt;p&gt;This starter template is not meant to be the starting point for a production-ready, feature-rich web application, but rather a &lt;strong&gt;playground to test out new ideas,&lt;/strong&gt; or to create small web-based projects, without having to worry about maintaining dependencies and frameworks on the long run.&lt;/p&gt;
&lt;p&gt;Not counting the web-components added for testing, there are only two imported components that I found sensible including, given the scope of the template:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/leaverou/md-block&quot;&gt;leaverou/md-block&lt;/a&gt;, to include and render any markdown file in the page at runtime, like the &lt;code&gt;README.md&lt;/code&gt; or a blog post draft.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;md-block&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;README.md&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;md-block&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;code-sandbox&lt;/strong&gt; web component, for displaying an interactive code sandbox for HTML, CSS and javascript, similar to what &lt;strong&gt;CodePen&lt;/strong&gt; does. I&#39;m using a fork of Chris Ferdinandi&#39;s&lt;a href=&quot;https://gist.github.com/cferdinandi/df9c95ae5f5ebcddf2ab85bb2805ff07&quot;&gt;code-sandbox&lt;/a&gt; web component, with a few added features.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;html&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;js&quot;&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; open&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; src&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;/assets/demo.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;textarea&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;code-sandbox&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The great thing about web-components is that after all it&#39;s just client-side javascript, with the unexpected benefit that if the rendered markdown text contains a web component outside of a code block, it will be rendered as a web component, and not as a string. No need for &lt;strong&gt;MDX&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;# demo.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;This counter button &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-light-font-weight:bold;--shiki-dark:#D19A66;--shiki-dark-font-weight:inherit&quot;&gt;**works!**&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;counter-button&gt;&amp;#x3C;/counter-button&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;dependencies&quot;&gt; Dependencies&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cocopon/tweakpane&quot;&gt;cocopon/tweakpane&lt;/a&gt; for interactive controls. This is optional but plugged with &lt;code&gt;state.js&lt;/code&gt;, which fires events on value changes to update the UI and store values to local storage.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prismjs.com&quot;&gt;PrismJS&lt;/a&gt; for syntax highlighting both in the code sandbox and in the markdown files.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs/installation/play-cdn/&quot;&gt;Tailwind Play CDN&lt;/a&gt; for quick styling and utility classes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/project-starter&quot;&gt;danieledep/project-starter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://maxbo.me/celine/&quot;&gt;@celine/celine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alpinejs.dev&quot;&gt;AlpineJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/cferdinandi/df9c95ae5f5ebcddf2ab85bb2805ff07&quot;&gt;cferdinandi/code-sandbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cocopon/tweakpane&quot;&gt;cocopon/tweakpane&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/leaverou/md-block&quot;&gt;leaverou/md-block&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/mattdesl/canvas-sketch&quot;&gt;mattdesl/canvas-sketch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/MaxwellBo/celine&quot;&gt;MaxwellBo/celine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/morris/vanilla-todo&quot;&gt;morris/vanilla-todo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prismjs.com/&quot;&gt;PrismJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/rodydavis/0f5a10361b96a2bf9b8bc4add8b9ac35&quot;&gt;Signals + Web Components&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com/docs/installation/play-cdn&quot;&gt;Tailwind Play CDN&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tweakpane.github.io/docs/&quot;&gt;Tweakpane Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://vite.dev/guide/&quot;&gt;Vite Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/Web_Components&quot;&gt;Web Components&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Using the new OKLCH colors to remove dependencies</title>
		<link href="https://dan-webnotes.com/posts/2024-07-21-use-oklch-remove-dependencies/"/>
		<updated>2024-07-21T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2024-07-21-use-oklch-remove-dependencies/</id>
		<content type="html">&lt;p&gt;2024-07-21&lt;/p&gt;
&lt;h1 id=&quot;using-new-oklch-colors-to-remove-dependencies&quot;&gt; Using new Oklch colors to remove dependencies&lt;/h1&gt;
&lt;p&gt;Whenever a new web-development feature is released and gradually makes its way into the most used browsers, it can bring excitement to developers.
Not only because of the new possibilities it brings to our craft but also because it can help offload some of the work that had previously required dependencies, to the browser itself.&lt;/p&gt;
&lt;p&gt;When I first built this blog, I used two libraries, &lt;a href=&quot;https://github.com/hsluv/hsluv&quot;&gt;hsluv/hsluv&lt;/a&gt; and &lt;a href=&quot;https://github.com/gka/chroma.js&quot;&gt;gka/chroma.js&lt;/a&gt; to generate and interpolate colors. Their functioning was described in a previous blog post: &lt;a href=&quot;https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/&quot; class=&quot;gradient-before&quot;&gt;A technique for generating beautiful color gradients&lt;/a&gt;. They did their job, but they were also dependencies that I had to carry along in the project, which is in contrast with the idea of a simple and lightweight blog.&lt;/p&gt;
&lt;p&gt;In the last year, support for &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch&quot;&gt;Oklch color notation&lt;/a&gt; has been added to the most used browsers, and it&#39;s a great opportunity to remove those dependencies.&lt;/p&gt;
&lt;h2 id=&quot;what-is-oklch&quot;&gt; What is Oklch?&lt;/h2&gt;
&lt;p&gt;Oklch is a color notation that represents colors the same colors of the &lt;strong&gt;Oklab color space&lt;/strong&gt; in a cylindrical color space. Its strength is that it is designed to be more perceptually uniform than other color spaces like &lt;strong&gt;RGB&lt;/strong&gt; or &lt;strong&gt;HSL.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Oklch color space is defined by three components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Okl&lt;/strong&gt;: is the perceived lightness (0%-100%). “Perceived” means that it has consistent lightness for our eyes, unlike in &lt;code&gt;hsl()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Chroma&lt;/strong&gt;: the colorfulness of the color, ranging from gray to the most saturated color.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hue&lt;/strong&gt;: the hue of the color, ranging from 0 to 360.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;what-is-changing&quot;&gt; What is changing&lt;/h2&gt;
&lt;p&gt;The structure and the logic of the code is remaining the same. I&#39;m not going to need any library to generate colors anymore, I can pick a color from the Oklch space and interpolate it to generate a gradient.&lt;/p&gt;
&lt;p&gt;Here it creates an array of hues to use as a base for the gradient colors, by remaining inside a given range on the hues spectrum:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; huesToPickFrom&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; Array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;round&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;360&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; minHueDiffAngle&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;baseHue&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; minHueDiffAngle&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;%&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 360&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and it then generates the final gradient colors by adding the chroma and lightness values:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; huesToPickFrom&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;hue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;i&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	lightness&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;		minLightness&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 0.1&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;lightnessRange&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;colors&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; i&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	chroma&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; minChroma&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; +&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; Math&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;maxChroma&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; minChroma&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;),&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;	hue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If I want to further interpolate the colors with more step values I can use another recently added feature, the &lt;code&gt;color-mix()&lt;/code&gt; function in CSS, which allows me to interpolate colors in a more controlled way.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;scaleSpreadArray&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;	cssColorStops&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;	colorsFinal&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;percent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;lastValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;nextValue&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;=&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;		`color-mix(in &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;minIn&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;nextValue&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt; ${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;percent&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; 100&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;toFixed&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;			2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		)&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;%, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;lastValue&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;)`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A notable change this update introduced is that the new gradients are more vivid and bright, while previously they were a little more toned down. This is because the Oklch color space is designed to be more perceptually uniform when building a color transition.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-07-21-use-oklch-remove-dependencies/srgb-oklch-gradient-difference.png&quot; alt=&quot;Gradient difference between srgb and oklch color space&quot;&gt;
&lt;em&gt;A visual representation of the difference between the gradients generated in the sRGB and Oklch color spaces from &lt;a href=&quot;https://tailwindcss.com/docs/v4-beta#gradient-interpolation-modifiers/&quot;&gt;TailwindCSS v4.0 Docs&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch&quot;&gt;Oklch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://oklch.com/&quot;&gt;Oklch Color Picker &amp;amp; Converter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl&quot;&gt;OKLCH in CSS: why we moved from RGB and HSL&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Use a 3D printer as a pen plotter</title>
		<link href="https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/"/>
		<updated>2024-02-07T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/</id>
		<content type="html">&lt;p&gt;2024-02-07&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/IMG_2091-3.jpg&quot; alt=&quot;Picture of a 3d printer with a pen attached to the extruder head&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;use-a-3d-printer-as-a-pen-plotter&quot;&gt; Use a 3D printer as a pen plotter&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;I wanted to add to my 3D printer the ability to pick up a pen and start drawing.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Luckily, today it&#39;s pretty easy to use a 3D printer as a pen plotter. The process is very simple since the printer is already a CNC machine to which you can mount a pen holder, maybe even print a custom one.&lt;/p&gt;
&lt;h2 id=&quot;build-requirements&quot;&gt; Build requirements&lt;/h2&gt;
&lt;p&gt;I custom designed the pen holder because I wanted to be able to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;use it without removing the &lt;strong&gt;plastic extruder,&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;take it off easily when it&#39;s not needed,&lt;/li&gt;
&lt;li&gt;plus it had to fit next to the &lt;strong&gt;BLTouch sensor&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/pen-holder.jpeg&quot; alt=&quot;A technical drawing of the components of the pen holder&quot;&gt;
&lt;em&gt;The final design of the pen holder.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As depicted in the picture, the pen holder is made of two main parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;a &lt;strong&gt;base&lt;/strong&gt;, which is attached permanently onto the extruder box,&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;pen holder&lt;/strong&gt;, attached to the base, which can be &lt;strong&gt;removed or replaced&lt;/strong&gt; by just unscrewing the bolt on the front.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;There are &lt;strong&gt;heat set inserts&lt;/strong&gt; on both pieces sides to make the assembly easier and more robust. The pen holder is designed to hold any pen, brush, tool with a &lt;strong&gt;diameter of 15 mm&lt;/strong&gt;, but it can be interchanged with a different one by just changing the &lt;strong&gt;pen holder&lt;/strong&gt; part.&lt;/p&gt;
&lt;h2 id=&quot;generate-g-code-from-svg-files&quot;&gt; Generate G-code from SVG files&lt;/h2&gt;
&lt;p&gt;To draw with a 3D printer, as for any laser-cutter or CNC machine, a vector drawing has to be converted into machine-readable &lt;a href=&quot;https://marlinfw.org/meta/gcode/&quot;&gt;G-code&lt;/a&gt;. Most existing workflows are based on the use of &lt;a href=&quot;https://inkscape.org&quot;&gt;Inkscape&lt;/a&gt;, a free and open-source vector graphics editor, paired with a plugin.&lt;/p&gt;
&lt;p&gt;There are a few plugins available that do this, these seem to be the most popular:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/evil-mad/axidraw&quot;&gt;evil-mad/axidraw&lt;/a&gt; the companion software for &lt;strong&gt;AxiDraw&lt;/strong&gt; machines, which should work for any CNC machine,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JTechPhotonics/J-Tech-Photonics-Laser-Tool&quot;&gt;JTechPhotonics/J-Tech-Photonics-Laser-Tool&lt;/a&gt;, plugin specialized for laser engraving,&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cnc-club/gcodetools&quot;&gt;cnc-club/gcodetools&lt;/a&gt;, a solid plugin that comes bundled with the application.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here I&#39;m using the latter because it looked like the most complete solution, and since it&#39;s bundled with Inkscape, it&#39;s likely to be the most stable and well-maintained long-term.&lt;/p&gt;
&lt;h3 id=&quot;document-setup&quot;&gt; Document setup&lt;/h3&gt;
&lt;p&gt;The first step is to set up the document to match the printer&#39;s bed size. The bed size of the Ender 3 is &lt;strong&gt;240x240 mm&lt;/strong&gt;, so in the &lt;strong&gt;Document Properties&lt;/strong&gt; panel, set the document to the same size, set the document units to &lt;code&gt;mm&lt;/code&gt; and the &lt;strong&gt;Scale&lt;/strong&gt; to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/Screenshot-8.png&quot; alt=&quot;Screenshot of the Inkscape Document Properties panel&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;extension-settings&quot;&gt; Extension settings&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;Gcodetools&lt;/strong&gt; extension comes bundled with Inkscape and can be found under &lt;strong&gt;Extensions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Gcodetools&lt;/strong&gt;. The extension has a few settings that need to be configured before generating the GCode.&lt;/p&gt;
&lt;h5&gt;Select tool&lt;/h5&gt;
&lt;p&gt;First of all, the &lt;strong&gt;Gcodetools&lt;/strong&gt; extension needs a tool to be defined, to create a default one, go to &lt;strong&gt;Extensions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Gcodetools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Tools Library..&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Select the &lt;strong&gt;Default&lt;/strong&gt; and click &lt;strong&gt;Apply&lt;/strong&gt;. The extension will create a new layer with the tool&#39;s settings, which can be edited by double-clicking on the layer. I suggest increasing the &lt;strong&gt;Feed rate&lt;/strong&gt; to &lt;code&gt;3000&lt;/code&gt;, since a pen-plotter can move faster than a CNC machine.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/Screenshot-9.png&quot; alt=&quot;Screenshot of the Gcodetools default tool table&quot;&gt;&lt;/p&gt;
&lt;h5&gt;Orientation points&lt;/h5&gt;
&lt;p&gt;The next step is to create the &lt;strong&gt;Orientation Points&lt;/strong&gt; which will give the extension the reference points needed to produce the GCode. Go to &lt;strong&gt;Extensions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Gcodetools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Orientation Points..&lt;/strong&gt; From the settings panel pick &lt;strong&gt;2-points mode&lt;/strong&gt; and click &lt;strong&gt;Apply&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The extension will create a new layer with the orientation points, which can be edited by double-clicking on the layer. The points should be placed at the bottom-left and bottom-right corners of the artboard.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/screenshot-5.png&quot; alt=&quot;Screenshot of the Inkscape artboard with the 2 orientation points&quot;&gt;&lt;/p&gt;
&lt;p&gt;By testing and measuring the distance between the pen-holder and the hotend extruder, you should find that there is a small offset in the &lt;strong&gt;X and Y axis&lt;/strong&gt; between the vector file and the physical drawing . This can be corrected by either moving the orientation points or by changing their values by double-clicking on the layer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2024-02-07-use-3d-printer-as-pen-plotter/screenshot-6.png&quot; alt=&quot;Screenshot of the Inkscape artboard with the 2 orientation points&quot;&gt;&lt;/p&gt;
&lt;h5&gt;Generate G-code&lt;/h5&gt;
&lt;p&gt;The last step is to generate the GCode. To do so all vector objects need first to be converted to a path, select them and go to &lt;strong&gt;Path&lt;/strong&gt; &amp;gt; &lt;strong&gt;Object to Path&lt;/strong&gt;. These need to be in the same layer as the orientation points.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h6&gt;⚠️ Warning:&lt;/h6&gt;
&lt;p&gt;The new paths need to be in the same layer as the orientation points.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now to &lt;strong&gt;Extensions&lt;/strong&gt; &amp;gt; &lt;strong&gt;Gcodetools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Path to Gcode..&lt;/strong&gt; and it will open a new panel with a few settings to be tweaked according to one&#39;s needs.&lt;/p&gt;
&lt;p&gt;Those are the settings I changed from the default ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;change the output extension to &lt;code&gt;.gcode&lt;/code&gt; instead of &lt;code&gt;.ngc&lt;/code&gt;, by changing the &lt;strong&gt;Output file name&lt;/strong&gt; to &lt;code&gt;output.gcode&lt;/code&gt;, because &lt;strong&gt;Octoprint&lt;/strong&gt; will only recognize that one as a valid extension,&lt;/li&gt;
&lt;li&gt;set the &lt;strong&gt;Offest along Z axis&lt;/strong&gt; to &lt;code&gt;-1&lt;/code&gt; because the tool &lt;code&gt;Depth step&lt;/code&gt; is set to &lt;code&gt;1&lt;/code&gt;, but changing it to &lt;code&gt;0&lt;/code&gt; will throw an error&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Gcodetools&lt;/strong&gt; allows to set custom &lt;strong&gt;Header&lt;/strong&gt; and a &lt;strong&gt;Footer&lt;/strong&gt; in the output file, which can be useful to set custom commands.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h6&gt;⚠️ Warning:&lt;/h6&gt;
&lt;p&gt;To set custom header and footer, we need to create two files in the output folder, without extensions, named &lt;code&gt;header&lt;/code&gt; and &lt;code&gt;footer&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is the custom header:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;M420 S1 ; Enable Jyers Mesh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;M75 ; Start print timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;G28 ; home all axis&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;G01 Z0.100000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;M0 ; Pause to set pen height&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And this is the custom footer:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;G1 Z20.00 F600 ; Move print head up&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;G1 X5 Y180 F9000 ; present print&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;M84 X Y E ; disable motors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;M77 ; Stop print timer&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I found useful to add the &lt;code&gt;M0&lt;/code&gt; command in the header to pause the print while I set the pen height and tighten the pen holder screw.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h6&gt;⚠️ Warning:&lt;/h6&gt;
&lt;p&gt;Note that Octoprint by default actually blocks the &lt;code&gt;M0&lt;/code&gt; &lt;strong&gt;Pause&lt;/strong&gt; command from being sent to the printer.
Instead it performs a software pause from within Octoprint which works just as fine, the only difference is that the &lt;strong&gt;Resume&lt;/strong&gt; command needs to come from Octoprint, instead that from the printer LCD panel.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now click &lt;strong&gt;Apply&lt;/strong&gt; to generate the GCode.&lt;/p&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/ender-plotter&quot;&gt;danieledep/ender-plotter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/appliedengdesign/vscode-gcode-syntax&quot;&gt;appliedengdesign/vscode-gcode-syntax&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cnc-club/gcodetools&quot;&gt;cnc-club/gcodetools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nickwhyte.com/post/2022/ender-3-v2-pen-plotter&quot;&gt;Ender 3 v2 Pen Plotter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/evil-mad/axidraw&quot;&gt;evil-mad/axidraw&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://marlinfw.org/meta/gcode/&quot;&gt;G-code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://inkscape.org/&quot;&gt;Inkscape&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://forums.maslowcnc.com/t/inkscape-for-gcode-generation-quick-instructions-to-get-started/12049&quot;&gt;Inkscape for GCODE generation - quick instructions to get started&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/JTechPhotonics/J-Tech-Photonics-Laser-Tool&quot;&gt;JTechPhotonics/J-Tech-Photonics-Laser-Tool&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ncviewer.com/&quot;&gt;NC Viewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.octoprint.org/t/octoprint-can-draw-too/2457&quot;&gt;Octoprint can draw, too&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/OctoPrint/OctoPrint/issues/1513&quot;&gt;[Request] Option to allow sending of M0/M1 to the printer #1513&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Wiring the Sonoff inside the Ender Power Supply Unit</title>
		<link href="https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/"/>
		<updated>2023-12-29T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/</id>
		<content type="html">&lt;p&gt;2023-12-29&lt;/p&gt;
&lt;h1 id=&quot;wiring-the-sonoff-inside-the-ender-power-supply-unit&quot;&gt; Wiring the Sonoff inside the Ender Power Supply Unit&lt;/h1&gt;
&lt;p&gt;The last missing piece to this project is to wire the Sonoff to have it sit nicely inside the Ender Power Supply Unit. But of course they wouldn&#39;t both fit inside the original case, so I had to design and print a new one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/technical-drawing.jpeg&quot; alt=&quot;Technical drawing of the 3d-printed case&quot;&gt;
&lt;em&gt;Technical drawing of the 3d-printed case&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The goal of this project is to have a 3D printer that can auto-shutdown, I explained how in this post: &lt;a href=&quot;https://dan-webnotes.com/posts/2023-12-02-auto-shutdown-3d-printer-raspberry-pi/&quot; class=&quot;gradient-before&quot;&gt;Auto-shutdown a 3D printer with Raspberry Pi and ESPHome&lt;/a&gt;. To achieve this I have to make the power cable go through the Sonoff before it reaches the &lt;strong&gt;Ender Power Supply Unit&lt;/strong&gt;, the PSU in turn powers the Ender and the Raspberry Pi running &lt;strong&gt;Octoprint.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/graph.png&quot; alt=&quot;A graph of the described system&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Octoprint server, once a print is done will be able to turn off the whole system by sending a MQTT message to a &lt;strong&gt;MQTT topic&lt;/strong&gt; the Sonoff is subscribed to. I found this Octoprint plugin that suits my needs, &lt;a href=&quot;https://github.com/OctoPrint/OctoPrint-MQTT&quot;&gt;OctoPrint/OctoPrint-MQTT&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I haven&#39;t put in place a system to turn the printer on remotely. If I wanted to, I&#39;d need to setup another MQTT broker on another device and have the Sonoff subscribe to another topic, but I&#39;m not interested in doing that at the moment, so i opted to add a &lt;strong&gt;momentary button&lt;/strong&gt; to the Sonoff to turn the printer on and off. It is fairly easy to add one using the available pins on the PCB.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/sonoff-button.jpg&quot; alt=&quot;Schematics for adding a button to the Sonoff PCB&quot;&gt;
&lt;em&gt;Schematics for adding a button to the Sonoff PCB&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Also &lt;strong&gt;Esphome&lt;/strong&gt; makes it very easy to add a physical button by configuring it as a &lt;strong&gt;Binary sensor&lt;/strong&gt;, just add this snippet to the configuration file, recompile the project and flash it to the device.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;binary_sensor&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;platform&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;gpio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;    name&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;button&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;    pin&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;      number&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;GPIO0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;    filters&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;delayed_on&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;10ms&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;    on_press&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;      then&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;        - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;            condition&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;              switch.is_on&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;mains&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;            then&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;mqtt.publish&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;                  topic&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;octoprint/shutdown&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;                  payload&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;OFF&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;delay&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;60s&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;switch.turn_off&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;mains&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;            else&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;logger.log&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;start up mains&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;              - &lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;switch.turn_on&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;mains&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I enjoyed the physical part of this project, I had to combine some coding with some 3D design, plus the necessary crimping and soldering of the electronics. I&#39;m happy with the result.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/IMG_1943.jpg&quot; alt=&quot;The internal bottom of the 3d-printed case&quot;&gt;
&lt;em&gt;The Sonoff at the bottom of the case&lt;/em&gt;
&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-29-wiring-sonoff-inside-ender-psu/IMG_1941.jpg&quot; alt=&quot;An external view of the 3d-printed case&quot;&gt;
&lt;em&gt;The final result&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=SLw1NczPtYA&quot;&gt;3D model to technical drawing - 3D design for 3D printing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/OctoPrint/OctoPrint-MQTT&quot;&gt;OctoPrint/OctoPrint-MQTT&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.tldraw.com/&quot;&gt;tldraw&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Auto-shutdown a 3D printer with Raspberry Pi and ESPHome</title>
		<link href="https://dan-webnotes.com/posts/2023-12-02-auto-shutdown-3d-printer-raspberry-pi/"/>
		<updated>2023-12-02T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-12-02-auto-shutdown-3d-printer-raspberry-pi/</id>
		<content type="html">&lt;p&gt;2023-12-02&lt;/p&gt;
&lt;h1 id=&quot;auto-shutdown-a-3d-printer-with-raspberry-pi-and-esphome&quot;&gt; Auto-shutdown a 3D printer with Raspberry Pi and ESPHome&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;One thing that I am not a fan of, is the 3d printer&#39;s fan staying on for hours after the print is finished. I know that the power consumption is not that high, but I like the feeling of waking up in the morning and finding the printer turned off and the finished print waiting for me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This apparently simple project also introduced me to a bunch of new topics, like &lt;a href=&quot;https://esphome.io&quot;&gt;ESPHome&lt;/a&gt;, &lt;a href=&quot;https://nodered.org&quot;&gt;NodeRED&lt;/a&gt; and &lt;strong&gt;MQTT&lt;/strong&gt;. Everything started with watching this fantastic video: &lt;a href=&quot;https://www.youtube.com/watch?v=WR0WdTBQJGo&quot;&gt;Save Energy by automating your 3D-printer&lt;/a&gt; by Andreas Spiess.&lt;/p&gt;
&lt;p&gt;I already owned a cheap 3d printer, the OG workhorse &lt;strong&gt;Ender 3&lt;/strong&gt;, and I had a spare &lt;strong&gt;Raspberry Pi 4B&lt;/strong&gt; so I decided to give it a try.&lt;/p&gt;
&lt;p&gt;In my previous post, &lt;a href=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/&quot; class=&quot;gradient-before&quot;&gt;A single enclosure for the Raspberry Pi and the Ender 3 electronics&lt;/a&gt;, I shown how I already moved the electronics to the back of the printer, so I had the perfect spot to place the Raspberry Pi.&lt;/p&gt;
&lt;h2 id=&quot;components&quot;&gt; Components&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Raspberry Pi 4&lt;/li&gt;
&lt;li&gt;Ender 3&lt;/li&gt;
&lt;li&gt;2-to-1 &lt;strong&gt;XT60 adaptor&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sonoff Basic RF R2 v1.3&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;USB to Serial adapter&lt;/strong&gt; with FTDI FT232RL chip, like this one: &lt;a href=&quot;https://www.amazon.com/DSD-TECH-Adapter-FT232RL-Compatible/dp/B07BBPX8B8/ref=sr_1_3?crid=T37WPRBNX2BY/&quot;&gt;DSD TECH SH-U09C&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Momentary switch button&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-02-auto-shutdown-3d-printer-raspberry-pi/sonoff_BASICR2_1.3_front.png&quot; alt=&quot;Sonoff Basic RF R2 v1.3&quot;&gt;
&lt;em&gt;&lt;a href=&quot;https://templates.blakadder.com/sonoff_BASICR2.html&quot;&gt;Sonoff Basic RF R2 v1.3&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;install-the-project-on-raspberry-pi&quot;&gt; Install the project on Raspberry Pi&lt;/h2&gt;
&lt;p&gt;Use &lt;strong&gt;Raspberry Pi Imager&lt;/strong&gt; to install on the microSD the &lt;strong&gt;Raspbian OS&lt;/strong&gt; with preinstalled &lt;strong&gt;Octoprint&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a new user and login by connecting with a computer in the same network to &lt;code&gt;http://octopi.local&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After that you will be able to &lt;strong&gt;ssh&lt;/strong&gt; into the Raspberry Pi, if you kept the default settings you can just type:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; octoprint@octopi.local&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Download the repo from Github via &lt;strong&gt;https&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; https://github.com/danieledep/raspberry-remote-shutdown.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Go into the downloaded folder&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; raspberry-remote-shutdown/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the script &lt;strong&gt;executable&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;chmod&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; +x&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; install.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Run the &lt;strong&gt;install script&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; ./install.sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;flash-the-sonoff-with-esphome&quot;&gt; Flash the Sonoff with ESPHome&lt;/h2&gt;
&lt;p&gt;Install desktop environment to use &lt;strong&gt;Esphome&lt;/strong&gt; and &lt;strong&gt;NodeRED&lt;/strong&gt; on the Raspberry Pi&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; /home/octoprint/scripts/install-desktop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set &lt;strong&gt;Desktop GUI&lt;/strong&gt; to boot at startup and set the resolution at least at 1280x720px&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; raspi-config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install &lt;strong&gt;Chromium&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; apt-get&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; chromium-browser&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; --yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Attach a screen, keyboard and mouse to the Raspberry Pi&lt;/p&gt;
&lt;p&gt;Install the &lt;a href=&quot;https://ftdichip.com/drivers/d2xx-drivers/&quot;&gt;D2XX Drivers&lt;/a&gt; for using the &lt;strong&gt;FTDI chips&lt;/strong&gt; plugged into the Raspberry Pi&lt;/p&gt;
&lt;p&gt;Go into the project folder:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; raspberry-remote-shutdown/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Last time I tryed installing &lt;strong&gt;Esphome&lt;/strong&gt; with &lt;code&gt;pip&lt;/code&gt; it failed to install &lt;code&gt;cryptography&lt;/code&gt; because of incompatible dependencies, this fixed it:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; pip3&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; esphome&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; cryptography==&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3.3.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Start up &lt;strong&gt;Esphome&lt;/strong&gt;, use sudo to have write permission for &lt;code&gt;secrets.yaml&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; esphome&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; dashboard&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; /config&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open &lt;strong&gt;Esphome&lt;/strong&gt; web ui at &lt;code&gt;octopi.local:6052&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Press on &lt;strong&gt;Secrets&lt;/strong&gt; to save wifi configuration&lt;/p&gt;
&lt;p&gt;Create a project name &lt;code&gt;sonoff&lt;/code&gt; and copy the content of &lt;code&gt;sonoff.yaml&lt;/code&gt; into the file&lt;/p&gt;
&lt;p&gt;Hit &lt;strong&gt;Save&lt;/strong&gt; and then &lt;strong&gt;Install.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first time you flash a new firmware you&#39;ll need to connect the Raspberry PI to the Sonoff via the &lt;strong&gt;FTDI Module&lt;/strong&gt; wiring the pin like the following diagram.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;FTDI      Sonoff&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;GND ----&gt; GND&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;VCC ----&gt; 3V3&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;TXD ----&gt; RX&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;RXD ----&gt; TX&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-02-auto-shutdown-3d-printer-raspberry-pi/sonoff-ftdi.jpg&quot; alt=&quot;Sonoff wiring for flashing&quot;&gt;
&lt;em&gt;Sonoff wiring for flashing&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The first time you flash a new firmware you&#39;ll also need to keep pressed the &lt;strong&gt;physical button&lt;/strong&gt; of the Sonoff.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Newer Raspberry Pi with installed 64bit OS might need to disable temporarely the 64 bit capabilities at boot time, in order to compile the binaries due to compatibility issues with Platformio tooling. To do so edit the &lt;code&gt;config.txt&lt;/code&gt; :&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; nano&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; /boot/config.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;add to the part titled &lt;code&gt;[pi4]&lt;/code&gt; a new line like this&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;[pi4]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;arm_64bit=0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;setup-nodered-and-mqtt&quot;&gt; Setup NodeRED and MQTT&lt;/h2&gt;
&lt;p&gt;Open &lt;strong&gt;NodeRED&lt;/strong&gt; at &lt;code&gt;octopi.local:1880&lt;/code&gt; import our flow &lt;code&gt;nodered-flow.json&lt;/code&gt; and click &lt;strong&gt;Deploy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-12-02-auto-shutdown-3d-printer-raspberry-pi/nodered-flow.png&quot; alt=&quot;The NodeRED flow&quot;&gt;
&lt;em&gt;The NodeRED flow&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Finally let&#39;s enable remote access to the &lt;strong&gt;MQTT broker&lt;/strong&gt; without requiring authentication. Open the configuration file&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; nano&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; /etc/mosquitto/mosquitto.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the end of the file add these two lines:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;listener 1883&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;allow_anonymous true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file and restart Mosquitto for the changes to take effect.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; systemctl&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; restart&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; mosquitto&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;configure-octoprint&quot;&gt; Configure Octoprint&lt;/h2&gt;
&lt;p&gt;Open Octoprint, install the &lt;strong&gt;MQTT&lt;/strong&gt; plugin, tick &lt;strong&gt;Activate event messages&lt;/strong&gt;, and let&#39;s only keep &lt;strong&gt;Printing events&lt;/strong&gt; messages enabled.&lt;br&gt;
Add &lt;code&gt;octopi.local&lt;/code&gt; as the Broker host.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ By default the MQTT plugin has the &lt;strong&gt;Enable retain flag&lt;/strong&gt; option checked.
This is normally the preferred choice but for our setup where the MQTT broker shut itself down multiple times from the same machine, we don&#39;t want to have our server turn on and find retained messages from the previous session.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;notes&quot;&gt; Notes&lt;/h3&gt;
&lt;p&gt;Since I&#39;m running the MQTT Broker directly on the same Raspberry PI that runs Octoprint too, which effectively self-shutdown, I don&#39;t need to run the &lt;strong&gt;systemd service&lt;/strong&gt; &lt;code&gt;shutdown.service&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The service was used by the original author to listen for the MQTT message coming from a different server running the MQTT Broker telling the Raspberry PI running Octoprint to shutdown.&lt;/p&gt;
&lt;p&gt;But since they both run on the same device I can simply run the &lt;strong&gt;Exec&lt;/strong&gt; node from within NodeRED, which upon receiving the &lt;code&gt;octoprint/shutodwn&lt;/code&gt; MQTT message, it launches the command &lt;code&gt;sudo shutdown now&lt;/code&gt; to the OS.&lt;/p&gt;
&lt;p&gt;I still have an updated version of the necessary files and NodeRED nodes in this repository, in case I wanted to change my setup in the future.&lt;/p&gt;
&lt;h3 id=&quot;testing-mqtt&quot;&gt; Testing MQTT&lt;/h3&gt;
&lt;p&gt;Check the &lt;strong&gt;systemd&lt;/strong&gt; services are enabled and running&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;systemctl&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; list-unit-files&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From terminal send MQTT messages to the NodeRED client which sends them to the Sonoff.&lt;/p&gt;
&lt;p&gt;To turn on:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;mosquitto_pub&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; sonoff/switch/mains/command&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;on&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To turn off:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;mosquitto_pub&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; sonoff/switch/mains/command&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;off&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To turn off after 30 seconds delay:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;mosquitto_pub&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; sonoff/mains&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;off&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;troubleshooting&quot;&gt; Troubleshooting&lt;/h3&gt;
&lt;p&gt;To read log messages from NodeRED in real-time&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;node-red-log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To read Mosquitto logs file&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; cat&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; /var/log/mosquitto/mosquitto.log&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To read NodeRED logs file&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; cat&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; /var/log/syslog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/raspberry-remote-shutdown&quot;&gt;danieledep/raspberry-remote-shutdown&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=yW9ovo9CHi0&quot;&gt;Buck converters: Quieten your 3D printer with a Noctua fan &amp;amp; directly power your Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://ftdichip.com/drivers/d2xx-drivers/&quot;&gt;D2XX Drivers - FTDI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://esphome.io/index.html&quot;&gt;ESPHome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://esphome.io/components/binary_sensor/gpio.html&quot;&gt;GPIO Binary Sensor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://randomnerdtutorials.com/how-to-flash-a-custom-firmware-to-sonoff/&quot;&gt;How to Flash a Custom Firmware to Sonoff&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://randomnerdtutorials.com/how-to-install-mosquitto-broker-on-raspberry-pi/&quot;&gt;Install Mosquitto MQTT Broker on Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.sparkfun.com/tutorials/make-your-own-fritzing-parts&quot;&gt;Make your own Fritzing parts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://nodered.org&quot;&gt;NodeRED&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://randomnerdtutorials.com/reprogram-sonoff-smart-switch-with-web-server/&quot;&gt;Reprogram Sonoff Smart Switch with Web Server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=WR0WdTBQJGo&quot;&gt;Save Energy by automating your 3D-printer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://randomnerdtutorials.com/sonoff-5-wifi-wireless-smart-switch-introduction/&quot;&gt;Sonoff – $5 WiFi Wireless Smart Switch Introduction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://templates.blakadder.com/sonoff_BASICR2.html&quot;&gt;Sonoff Basic RF R2 v1.3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://randomnerdtutorials.com/testing-mosquitto-broker-and-client-on-raspbbery-pi/&quot;&gt;Testing Mosquitto Broker and Client on Raspberry Pi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://esphome.io/devices/sonoff_basic.html&quot;&gt;Using ESPHome With Sonoff Basic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>A single enclosure for the Raspberry Pi and the Ender 3 electronics</title>
		<link href="https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/"/>
		<updated>2023-11-24T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/</id>
		<content type="html">&lt;p&gt;2023-11-24&lt;/p&gt;
&lt;h1 id=&quot;a-single-enclosure-for-the-raspberry-pi-and-the-ender-3-electronics&quot;&gt; A single enclosure for the Raspberry Pi and the Ender 3 electronics&lt;/h1&gt;
&lt;p&gt;Since I never wanted to have a separate box for the Raspberry Pi, I searched on &lt;a href=&quot;https://www.thingiverse.com&quot;&gt;Thingiverse&lt;/a&gt; for a case that could fit together the &lt;strong&gt;Raspberry Pi,&lt;/strong&gt; a few &lt;strong&gt;buck converters&lt;/strong&gt; and the &lt;strong&gt;Creality Silent Motherboard v4.2.7&lt;/strong&gt; that I had upgraded to from the stock one.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/SilentBoard.jpg&quot; alt=&quot;Creality Silent Motherboard v4.2.7&quot;&gt;
&lt;em&gt;Creality Silent Motherboard v4.2.7&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;From my experience, switching to the silent motherboard is a must. The printer is much quieter and the quality of the prints is better. On a pursuit to silence the printer, I also replaced the stock fans with &lt;strong&gt;Noctua fans&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Thingiverse is a wonderful trove full of &lt;strong&gt;all-in-one&lt;/strong&gt; case for the Ender 3 printer but to fit my needs, I ended up mixing together a few of them.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;This great project &lt;a href=&quot;https://www.thingiverse.com/thing:4184689/&quot;&gt;Ender 3/Pro Case [EZABL, BLTouch, Raspberry Pi 3, Mosfet]&lt;/a&gt;, an all-in-one case to be positioned on the back of the printer, below the print bed. It fitted the &lt;strong&gt;Raspberry Pi 4&lt;/strong&gt;, the &lt;strong&gt;buck converters&lt;/strong&gt; and the &lt;strong&gt;Creality Silent Motherboard v4.2.7&lt;/strong&gt; and the &lt;strong&gt;Noctua fans&lt;/strong&gt; perfectly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/large_display_Front_RPi.png&quot; alt=&quot;Ender 3/Pro Case by Akanar&quot;&gt;
&lt;em&gt;Ender 3/Pro Case by Akanar&lt;/em&gt;&lt;/p&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;After moving all the electronics to the back of the printer, I wanted to fill the empty space on the front, with useful parts. I was happy to find this nice project &lt;a href=&quot;https://www.thingiverse.com/thing:3970720/&quot;&gt;Ender 3 / Ender 3 Pro - A Better Left Front Drawer with micro SD Card Slot&lt;/a&gt; by &lt;strong&gt;gweep&lt;/strong&gt;, to have again the &lt;strong&gt;micro SD card slot&lt;/strong&gt; on the front, after moving the electronics to the back made it annoying to use. I knew I wanted to use &lt;strong&gt;OctoPrint&lt;/strong&gt; to control the printer, but I still wanted to have the SD card slot available, just in case. Plus the big drawer is a nice addition to store the tools and the spare parts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For the front, on the right side, I reached for this project, &lt;a href=&quot;https://www.thingiverse.com/thing:3372977/&quot;&gt;Ender 3 Double Drawer&lt;/a&gt; by &lt;strong&gt;Littlefiver&lt;/strong&gt;. A nice simple drawer to store smaller tools.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/IMG_1591.jpg&quot; alt=&quot;front-side Ender 3, closed drawers&quot;&gt;
&lt;em&gt;Ender 3 from the front, closed drawers&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/IMG_1590.jpg&quot; alt=&quot;front-side Ender 3, open drawers&quot;&gt;
&lt;em&gt;Ender 3 from the front, open drawers&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/IMG_1584.jpg&quot; alt=&quot;back-side Ender 3, sealed enclosure&quot;&gt;
&lt;em&gt;Ender 3 from the back, sealed enclosure&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-11-24-single-enclosure-raspberry-ender/IMG_1583.jpg&quot; alt=&quot;back-side Ender 3, open enclosure&quot;&gt;
&lt;em&gt;Ender 3 from the back, open enclosure&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;repository&quot;&gt; Repository&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/danieledep/ender-3-upgrades&quot;&gt;danieledep/ender-3-upgrades&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thingiverse.com/thing:3372977&quot;&gt;Ender 3 Double Drawer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thingiverse.com/thing:3970720&quot;&gt;Ender 3 / Ender 3 Pro - A Better Left Front Drawer with micro SD Card Slot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.thingiverse.com/thing:4184689/&quot;&gt;Ender 3/Pro Case [EZABL, BLTouch, Raspberry Pi 3, Mosfet]&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Text selection color</title>
		<link href="https://dan-webnotes.com/posts/2023-07-21-text-selection-color/"/>
		<updated>2023-07-21T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-07-21-text-selection-color/</id>
		<content type="html">&lt;p&gt;2023-07-21&lt;/p&gt;
&lt;h1 id=&quot;text-selection-color&quot;&gt; Text selection color&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Utilities is one of those words that make web developers recall when you needed complex tricks to have a rounded button or a nice gradient. This is a collection of utilities and snippets I created and refined during my job as front-end developer&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Today browsers got a lot better, tailwind and javascript framework made life easier and utilities snippets are not that common anymore. But with web development constantly evolving, new opportunities arise to learn new tricks and get some new tools in the toolbox.&lt;/p&gt;
&lt;p&gt;Adding the feature of highlighting words with a custom &lt;strong&gt;on-brand color&lt;/strong&gt;, different from the default one, is one of them and can be a nice touch to add when polishing a new website.&lt;/p&gt;
&lt;p&gt;It&#39;s very easy to add a &lt;code&gt;::selection&lt;/code&gt; highlight color to the CSS. Just add the following code to the CSS file:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#56B6C2&quot;&gt;::selection&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;target-text&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;search-text&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	background: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;yellow&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	color: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;black&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;::target-text&lt;/code&gt; and &lt;code&gt;::search-text&lt;/code&gt; are newer pseudo-elements that are used when the user clicks on a link containing &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/URI/Fragment/Text_fragments&quot;&gt;Text fragments&lt;/a&gt; and when they searche for a word on the page. They are not supported in all browsers, but it&#39;s a nice touch to add them to the CSS file.&lt;/p&gt;
&lt;p&gt;The most important thing to keep in mind when working with this feature is to make sure the &lt;strong&gt;color contrast&lt;/strong&gt; is high enough, for &lt;strong&gt;accessibility&lt;/strong&gt; reasons. Generally you want to use a light highlight color on a dark text.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/URI/Fragment/Text_fragments&quot;&gt;Text fragments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Update the SVG favicon and pseudo-elements dynamically</title>
		<link href="https://dan-webnotes.com/posts/2023-04-23-update-favicon-and-pseudo-elements/"/>
		<updated>2023-04-23T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-04-23-update-favicon-and-pseudo-elements/</id>
		<content type="html">&lt;p&gt;2023-04-23&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-04-23-update-favicon-and-pseudo-elements/favicon.png&quot; alt=&quot;Screenshot of the browser tab favicon&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;update-the-svg-favicon-and-pseudo-elements-dynamically&quot;&gt; Update the SVG favicon and pseudo-elements dynamically&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;I really like the tiny coloured circle, this post explains what I learned from trying to put it in places that require some hacks to have it change colors dynamically.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The gradient inside the circle is generated as a &lt;code&gt;background-image&lt;/code&gt; css property, and it&#39;s a combination of a &lt;strong&gt;radial gradient&lt;/strong&gt; and a &lt;strong&gt;linear gradient&lt;/strong&gt;. I explained this technique in a previous post:
&lt;a href=&quot;https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/&quot; class=&quot;gradient-before&quot;&gt;A technique for generating beautiful color gradients	&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The css property is applied to a specific css class I named &lt;code&gt;.gradient&lt;/code&gt; which I use in different places around the website HTML, this way I thought I could easily change the gradient colors and at the same time apply it freely wherever I wanted independently of the container.&lt;/p&gt;
&lt;h3 id=&quot;javascript-and-pseudo-elements&quot;&gt; Javascript and pseudo-elements&lt;/h3&gt;
&lt;p&gt;The first place where adding the colorful dot makes more sense is internal links, if a link is pointing to another post in the blog I want to apply the small piece of &lt;strong&gt;branding&lt;/strong&gt;, fair and simple. I already tackled the first part of this issue in this previous post &lt;a href=&quot;https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/&quot; class=&quot;gradient-before&quot;&gt;How to build a minimalist Markdown blog with Eleventy&lt;/a&gt;, what I had in mind was to add a &lt;code&gt;:before&lt;/code&gt; pseudo-element to the link and style it with the current gradient.&lt;/p&gt;
&lt;p&gt;The first part was easy, I edited the function I already wrote in &lt;code&gt;eleventy.config.js&lt;/code&gt;, changing it from this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;mdLib&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;markdownItLinks&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	processHTML&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// defaults to false for backwards compatibility&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;	replaceLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;htmlToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		if&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;.md&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;			// remove the content after the last slash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; newLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#E06C75&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#E06C75&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; newLink&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to this, where I still change the link but also the &lt;code&gt;class&lt;/code&gt; attribute to add my own custom class &lt;code&gt;.gradient-before&lt;/code&gt; to which I will add a pseudo-element:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;mdLib&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;markdownItLinks&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	processHTML&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// defaults to false for backwards compatibility&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;	replaceLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;htmlToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		if&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;.md&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;			// remove the content after the last slash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; newLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#E06C75&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#E06C75&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;			// add class to the link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; newToken&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; token&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;			newToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;attrs&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;				[&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;href&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;newLink&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;				[&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;class&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;gradient-before&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;			];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; newToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now I just needed to target the &lt;code&gt;.gradient-before::before&lt;/code&gt; pseudo-element in my javascript and it would have been done, but nope, &lt;strong&gt;TIL that pseudo-elements are not part of the DOM&lt;/strong&gt; and therefore can&#39;t be accessed from javascript, so I had to find another way to do it.&lt;/p&gt;
&lt;p&gt;A solution from &lt;strong&gt;Stack Overflow&lt;/strong&gt; was to generate dynamically a &lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; tag with the css property I wanted to apply to &lt;code&gt;.gradient-before::before&lt;/code&gt; and this is what I ended up with:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// style pseudo elements for internal links by adding a new stylesheet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; gradientStyleSheet&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;	document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;#gradientStyleSheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;	document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;appendChild&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;createElement&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;style&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;gradientStyleSheet&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;gradientStyleSheet&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;gradientStyleSheet&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;innerHTML&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; `.gradient-before:before {background: &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;cssGradient&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;;}`&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that worked smoothly! You maybe noticed them in action in this very post, the links to other blog posts have the coloured dot just before them, and if you toggle new colours in the homepage they will change throughout the blog.&lt;/p&gt;
&lt;h3 id=&quot;update-favicons-with-javascript&quot;&gt; Update favicons with javascript&lt;/h3&gt;
&lt;p&gt;The next step is to have the &lt;strong&gt;favicon&lt;/strong&gt; too change dynamically with the picked gradient colours, but I wasn&#39;t even sure if it was possible, after all favicons are static files, right?&lt;/p&gt;
&lt;p&gt;It turns out that it is actually possible, I found a great tutorial on &lt;strong&gt;CSS Tricks&lt;/strong&gt;, &lt;a href=&quot;https://css-tricks.com/how-to-create-a-favicon-that-changes-automatically/&quot;&gt;How to Create a Favicon That Changes Automatically&lt;/a&gt; that explains just how to do it thanks to &lt;strong&gt;SVG favicons.&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;h6&gt;⚠️ Warning:&lt;/h6&gt;
&lt;p&gt;As of today (April 2023), SVG favicons are supported by all modern browsers with the only exception of Safari both on desktop and mobile.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using javascript we can target the favicon &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the &lt;strong&gt;HTML&lt;/strong&gt; and change the &lt;code&gt;href&lt;/code&gt; attribute to instead of pointing to an asset url, we embed the new file directly by changing the attribute to a &lt;strong&gt;data URI&lt;/strong&gt; that contains the favicon svg with the new colours.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// style favicon by creating a svg and converting it to a data url of the favicon&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; faviconHref&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; `data:image/svg+xml,%3Csvg xmlns=&#39;http://www.w3.org/2000/svg&#39; width=&#39;50&#39; height=&#39;50&#39;%3E%3Cdefs%3E%3CradialGradient id=&#39;b&#39; gradientTransform=&#39;matrix(2 0 0 2 -1 -.5)&#39;%3E%3Cstop offset=&#39;19%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3Cstop offset=&#39;39.25%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39; stop-opacity=&#39;0.75&#39;/%3E%3Cstop offset=&#39;59.5%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39; stop-opacity=&#39;0.5&#39;/%3E%3Cstop offset=&#39;100%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39; stop-opacity=&#39;0&#39;/%3E%3C/radialGradient%3E%3ClinearGradient id=&#39;a&#39; x1=&#39;.5&#39; x2=&#39;.5&#39; y1=&#39;0&#39; y2=&#39;1&#39;%3E%3Cstop offset=&#39;0%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3Cstop offset=&#39;22%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3Cstop offset=&#39;45%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3Cstop offset=&#39;57%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3Cstop offset=&#39;76%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3Cstop offset=&#39;94%25&#39; stop-color=&#39;&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;])&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&#39;/%3E%3C/linearGradient%3E%3C/defs%3E%3Ccircle cx=&#39;50%25&#39; cy=&#39;50%25&#39; r=&#39;50%25&#39; fill=&#39;url(%23a)&#39;/%3E%3Ccircle cx=&#39;50%25&#39; cy=&#39;50%25&#39; r=&#39;50%25&#39; fill=&#39;url(%23b)&#39;/%3E%3C/svg%3E`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// Ensure we have access to the document, i.e. we are in the browser.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;if&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#C678DD&quot;&gt;typeof&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; window&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; ===&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;undefined&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; favicon&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;	document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;link[rel*=&#39;icon&#39;]&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt;||&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;	document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;head&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;appendChild&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;createElement&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;link&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;favicon&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;image/svg+xml&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;favicon&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;rel&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;icon&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;favicon&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;href&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; faviconHref&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/how-to-create-a-favicon-that-changes-automatically/&quot;&gt;CSS Tricks - How to Create a Favicon That Changes Automatically&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://yoksel.github.io/url-encoder/&quot;&gt;URL-encoder for SVG&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>A technique for generating beautiful color gradients</title>
		<link href="https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/"/>
		<updated>2023-02-26T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/</id>
		<content type="html">&lt;p&gt;2023-02-26&lt;/p&gt;
&lt;h1 id=&quot;a-technique-for-generating-beautiful-color-gradients&quot;&gt; A technique for generating beautiful color gradients&lt;/h1&gt;
&lt;p&gt;There is only one non-black-and-white piece in the whole UI which is the &lt;strong&gt;color gradient circle&lt;/strong&gt; in the homepage and in the header of the posts. I thought adding a small piece of color would be a fun highlight given the whole website is set in neutral shades.&lt;/p&gt;
&lt;p&gt;But I didn&#39;t want to commit to a specific brand color, also there are many nice color gradients! So I experimented with the idea to generate a new gradient every time the page is loaded. I remember I liked the gradients generated from this nice online &lt;a href=&quot;https://doodad.dev/gradient-generator&quot;&gt;gradient generator&lt;/a&gt;, by reading through the generated css I found out that a technique to generate nice looking gradients is to combine &lt;code&gt;radial-gradient&lt;/code&gt; and &lt;code&gt;linear-gradient&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;background-image&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;: radial-gradient(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		100% 100% at 0% 50%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;		#d53a42&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 19%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		rgba(204&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 58&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 78&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.75&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) 39&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;.25%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		rgba(194&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 57&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 86&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;.5&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) 59&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;.5%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		rgba(177&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 56&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 94&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) 100%&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	), &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;linear-gradient(180deg&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #ffffb5&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 0%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #fef372&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 7.33%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #f6d860&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 22%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #f3bf59&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			27.67%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #ed894b&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 39%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #e47346&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 45%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #d53a42&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 57%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #c93a51&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 63.33%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; #b1385e&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 76%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt; #97385d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			82%&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#ABB2BF&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#FFFFFF&quot;&gt; #6a324f&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; 94%&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/doodad.png&quot; alt=&quot;A nice color gradient made of yellow and reddish colors&quot;&gt;
&lt;em&gt;The result from the css&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;generate-the-colors&quot;&gt; Generate the colors&lt;/h2&gt;
&lt;p&gt;The first step is to generate a pleasing palette of 4/5 colors for the &lt;code&gt;linear-gradient&lt;/code&gt;, to achieve this I learned from the technique used in this repository &lt;a href=&quot;https://github.com/meodai/farbvelo&quot;&gt;meodai/farbvelo&lt;/a&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;it picks a series of &lt;strong&gt;color stops&lt;/strong&gt; &lt;em&gt;ℕ0 hues&lt;/em&gt; at a user defined &lt;strong&gt;minimum angle&lt;/strong&gt; ∠ generated by the &lt;a href=&quot;https://github.com/hsluv/hsluv&quot;&gt;hsluv/hsluv&lt;/a&gt; library, a human-friendly alternative to HSL.&lt;/li&gt;
&lt;li&gt;it &lt;strong&gt;interpolates&lt;/strong&gt; between color stops in &lt;strong&gt;CIE L*a*b*&lt;/strong&gt; by using &lt;a href=&quot;https://github.com/gka/chroma.js&quot;&gt;gka/chroma.js&lt;/a&gt;, a library for color manipulations.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I then pick a middle value in the color palette to generate the &lt;code&gt;radial-gradient&lt;/code&gt; color stops. In &lt;code&gt;gradient.js&lt;/code&gt; I do those steps and then export the result as a css string:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt; setColors&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;	let&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; gradient&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; `radial-gradient(100% 100% at 0% 50%, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; 19%, rgba(0, 0, 0, 0) 100%), linear-gradient(180deg, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;array&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#CA1243;--shiki-dark:#C678DD&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;)`&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;	document&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;.gradient&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;((&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;el&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;		el&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;style&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;background&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; gradient&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;let-the-user-choose&quot;&gt; Let the user choose&lt;/h2&gt;
&lt;p&gt;With the gradient generator working, I really liked the outcomes, but I also wish any reader of this website could find their favorite gradient and have it &lt;strong&gt;persist&lt;/strong&gt; across page loads. So I made the coloured circle in the homepage a &lt;strong&gt;clickable button&lt;/strong&gt; that generates a new gradient and store the result in the browser &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;
&lt;h5&gt;Some nice gradients&lt;/h5&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/gr1.png&quot; alt=&quot;A nice color gradient made of green and bluish colors&quot;&gt;
&lt;em&gt;background: radial-gradient(100% 100% at 0% 50%, rgb(118, 201, 193) 19%, rgba(0, 0, 0, 0) 100%), linear-gradient(rgb(62, 97, 102), rgb(100, 166, 177), rgb(118, 201, 193), rgb(128, 225, 191), rgb(136, 240, 187), rgb(145, 216, 178));&lt;/em&gt;
&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/gr2.png&quot; alt=&quot;A nice color gradient made of bluish and pink colors&quot;&gt;
&lt;em&gt;background: radial-gradient(100% 100% at 0% 50%, rgb(176, 208, 211) 19%, rgba(0, 0, 0, 0) 100%), linear-gradient(rgb(76, 108, 112), rgb(129, 188, 196), rgb(176, 208, 211), rgb(215, 208, 205), rgb(235, 206, 200), rgb(204, 198, 196));&lt;/em&gt;
&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-26-generating-beautiful-color-gradients/gr3.png&quot; alt=&quot;A nice color gradient made of purple and greenish colors&quot;&gt;
&lt;em&gt;background: radial-gradient(100% 100% at 0% 50%, rgb(202, 185, 195) 19%, rgba(0, 0, 0, 0) 100%), linear-gradient(rgb(123, 92, 110), rgb(218, 158, 195), rgb(202, 185, 195), rgb(146, 196, 170), rgb(99, 201, 150), rgb(141, 194, 149));&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://doodad.dev/gradient-generator&quot;&gt;Doodad online gradient generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/gka/chroma.js&quot;&gt;gka/chroma.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hsluv/hsluv&quot;&gt;hsluv/hsluv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/meodai/farbvelo0&quot;&gt;meodai/farbvelo&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Markdown is the paper of the web</title>
		<link href="https://dan-webnotes.com/posts/2023-02-24-markdown-is-paper-for-web/"/>
		<updated>2023-02-24T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-02-24-markdown-is-paper-for-web/</id>
		<content type="html">&lt;p&gt;2023-02-24&lt;/p&gt;
&lt;h1 id=&quot;markdown-is-the-paper-of-the-web&quot;&gt; Markdown is the paper of the web&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://daringfireball.net/projects/markdown/syntax#philosophy&quot;&gt;Markdown philosophy&lt;/a&gt; states that it&#39;s always been a format intended to be easy to write and read, specifically intended for &lt;strong&gt;publishing on the web.&lt;/strong&gt; One of the greatest feature becoming more apparent after seeing the rise and fall of web-publishing services is its &lt;strong&gt;portability.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-24-markdown-is-paper-for-web/800px-AS_Neo.jpeg&quot; alt=&quot;A picture of the AlphaSmart writing machine&quot;&gt;
&lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/AlphaSmart&quot;&gt;The AlphaSmart&lt;/a&gt;, or the way I see proprietary publishing platforms&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If one picks a platform for its conveniences, it is almost as if they were committing to always use a dedicated machine for their writing, and with the many conveniences, might also come limitations. Batteries can run out, or it might just break down.&lt;/p&gt;
&lt;p&gt;Markdown files are like a pile of paper sheets where I can sketch, jot down drafts, but at the end of the day I will be always be able to carry them with me.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://stephango.com/file-over-app&quot;&gt;File over app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://daringfireball.net/projects/markdown/syntax#philosophy&quot;&gt;Markdown philosophy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/AlphaSmart&quot;&gt;The AlphaSmart&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>This blog as a documentation for my projects</title>
		<link href="https://dan-webnotes.com/posts/2023-02-24-blog-as-documentation-for-projects/"/>
		<updated>2023-02-24T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-02-24-blog-as-documentation-for-projects/</id>
		<content type="html">&lt;p&gt;2023-02-24&lt;/p&gt;
&lt;h1 id=&quot;this-blog-as-a-documentation-for-my-projects&quot;&gt; This blog as a documentation for my projects&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;My goal from the beginning is to have this website as a companion for my projects, a place to document their progress.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But also it is a way to keep myself &lt;strong&gt;motivated&lt;/strong&gt; and &lt;strong&gt;accountable&lt;/strong&gt; to keep working at them. I know writing takes time, doing projects takes time and motivation comes and goes, but what bothers me the most are the &lt;strong&gt;folders of unfinished projects&lt;/strong&gt; that I have sitting on my computer. From the moon-shot projects to the basically finished experiments that just need a little tidying to call them done.&lt;/p&gt;
&lt;p&gt;My idea to avoid this is to keep the posts &lt;strong&gt;small and frequent,&lt;/strong&gt; so that I can keep myself motivated even when little progress is being made. To support this way of working I added a &lt;strong&gt;FrontMatter&lt;/strong&gt; property &lt;code&gt;project&lt;/code&gt; to my markdown files.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;project&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;My blog&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, when a post is actually &lt;strong&gt;part of a series&lt;/strong&gt; of posts, a &lt;strong&gt;navigation menu&lt;/strong&gt; is displayed on top of the page to let readers orient and explore the subject.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-24-blog-as-documentation-for-projects/navigation.png&quot; alt=&quot;A screenshot depicting the navigation menu for project posts&quot;&gt;
&lt;em&gt;The navigation menu for project posts&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The layout can still undergo some changes, but so far those are the main features I want to keep:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the list of posts is ordered in &lt;strong&gt;chronological order,&lt;/strong&gt; instead of the typical list where the latest is on top&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;strong&gt;name of the project&lt;/strong&gt; should be central, right now it is displayed next to the &lt;code&gt;/home&lt;/code&gt; link&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the &lt;strong&gt;navigation item&lt;/strong&gt; on the rights side controls the project posts list, not the blog navigation&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not all posts will belong to a specific project, there are going to be single-standing posts, but i really like the idea that each post is the &lt;strong&gt;atomic unit&lt;/strong&gt; for bigger projects, whether the topic of the post is technical, about graphics or just me writing any thought about it.&lt;/p&gt;
&lt;p&gt;I&#39;ve already found useful the fact that each project is not not a folder but a &lt;strong&gt;frontmatter property,&lt;/strong&gt; this way I can move posts around or promote a post from being a sub-unit of a project to a standalone project as it evolves, without having to worry about broken links or redirects.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>How to build a minimalist Markdown blog with  Eleventy</title>
		<link href="https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/"/>
		<updated>2023-02-21T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/</id>
		<content type="html">&lt;p&gt;2023-02-21&lt;/p&gt;
&lt;h1 id=&quot;how-to-build-a-minimalist-markdown-blog-with-eleventy&quot;&gt; How to build a minimalist Markdown blog with Eleventy&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Anybody who ever started a new blog knows the feeling of pursuing a long list of features, only to get overwhelmed by the growing complexity. Knowing this, I tried to build this blog as a stripped-down container for my projects.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;a-simple-container&quot;&gt; A simple container&lt;/h2&gt;
&lt;p&gt;Let&#39;s admit it, &lt;strong&gt;UIs are cool,&lt;/strong&gt; but usually the focus should be only on displaying content. Maybe fueled by some laziness, here are the choices made here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;dark mode is automatic&lt;/strong&gt; depending on the user&#39;s system preferences, no fancy buttons to switch between modes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no reading metrics&lt;/strong&gt; of any kind, no reading progress indicator, no time to read, no read counter statistics&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no comment system and social media buttons.&lt;/strong&gt; Just no. Of course feel free to comment with an email&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no search or tag filtering&lt;/strong&gt;, since there needs to be enough content to justify it&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no cookies&lt;/strong&gt; Nobody likes to see a cookie popup as the first thing they see when visiting a website.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;no about page,&lt;/strong&gt; when a paragraph can do.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/simplicity.png&quot; alt=&quot;A screenshot of the about paragraph of this website reading: &#39;dan dep, designer and developer. I craft graphics, interfaces and ideas&#39;&quot;&gt;
&lt;em&gt;A really simple about paragraph&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;markdown-is-all-you-need&quot;&gt; Markdown is all you need&lt;/h2&gt;
&lt;p&gt;Since the goal of this website is to document ongoing projects, it was important to have a setup that can store in a self-contained way all the content, text and images, in simple and &lt;strong&gt;portable&lt;/strong&gt; formats.&lt;/p&gt;
&lt;h5&gt;Images and folders&lt;/h5&gt;
&lt;p&gt;To achieve this the website directory structure uses a separate folder for each post. In the same folder there is going to be the text stored in a markdown file and all the images referenced in the file content.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    ├── post-title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    │ 	├── post-title.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    │ 	└── image.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    └── another-post&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    		├── another-post.md&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;    		└── image.png&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To ensure &lt;strong&gt;portability&lt;/strong&gt; and &lt;strong&gt;compatibility&lt;/strong&gt; with any future setup, it is important to have a &lt;strong&gt;pure Markdown syntax&lt;/strong&gt;. In this setup we ditch the images &lt;strong&gt;shortcodes&lt;/strong&gt;, that in the Eleventy starter template reference images with Nunjucks syntax, like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;image&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;./possum.png&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;Three possum hanging from a red balloon&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While to use the markdown syntax, images need to be referenced like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;![&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Three possum hanging from a red balloon&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;./possum.png&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To achieve this, it would be possible to just set in &lt;code&gt;eleventy.config.js&lt;/code&gt; the option to output a copy of any images using the same folder structure, along those lines:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;eleventyConfig&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;addPassthroughCopy&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;	&quot;content/posts/**/*.{svg,webp,png,jpeg,jpg,avif}&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that would mean no image optimization, no responsiveness at all, and that&#39;s not great, luckily this cool &lt;code&gt;markdown-it&lt;/code&gt; plugin exists, &lt;a href=&quot;https://github.com/solution-loisir/markdown-it-eleventy-img&quot;&gt;solution-loisir/markdown-it-eleventy-img&lt;/a&gt; that allows to parse the images using the markdown syntax. Mission accomplished.&lt;/p&gt;
&lt;h5&gt;Nunjucks templates&lt;/h5&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/11ty/eleventy-base-blog&quot;&gt;11ty/eleventy-base-blog&lt;/a&gt; is a great starting point to to build a blog, but with some changes to the repository structure it&#39;s possible to make it &lt;strong&gt;future-proof.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, it can be confusing that Nunjucks files can be used as content for templates as they support &lt;strong&gt;FrontMatter&lt;/strong&gt; syntax. But it might be preferable to have a clear separation where Nunjucks files work only as templates and Markdown files for content. To do this let&#39;s convert all Nunjucks files in the &lt;code&gt;/content&lt;/code&gt; folder to &lt;code&gt;.md&lt;/code&gt;. Also all nunjucks syntax is preprocessed in markdown by default, but it can be turned off in &lt;code&gt;eleventy.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;markdownTemplateEngine&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;false&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also the nunjucks templates in &lt;code&gt;/layouts&lt;/code&gt; were using frontmatter to set the layout.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;layout: layouts/base.njk&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it&#39;s possible to convert them to pure Nunjucks syntax by stating which layout they are extending like this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;extends&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;layouts/base.njk&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;block&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; content&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endblock&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Linking markdown files&lt;/h5&gt;
&lt;p&gt;It&#39;s possible to link to other internal posts using markdown syntax, but this usually requires to use the &lt;strong&gt;FrontMatter&lt;/strong&gt; &lt;code&gt;permalink&lt;/code&gt; property, but this too can be too setup-specific. Moreover today &lt;strong&gt;VSCode&lt;/strong&gt; allow you to drag-and-drop the file into the editor, which automatically generates the relative link.&lt;/p&gt;
&lt;p&gt;&lt;video class=&quot;markdown-video&quot; src=&quot;https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/drop-link.mp4&quot; poster=&quot;https://dan-webnotes.com/posts/2023-02-21-build-minimalist-markdown-blog-eleventy/drop-link.poster.jpg&quot; preload=&quot;metadata&quot; aria-label=&quot;Video recording of importing a markdown file as a link in another markdown file&quot; autoplay=&quot;&quot; muted=&quot;&quot; loop=&quot;&quot; playsinline=&quot;&quot;&gt;&lt;/video&gt;
&lt;em&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/languages/markdown/&quot;&gt;Editing Markdown in VSCode&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But this, just like with image assets, won&#39;t work when the content is rendered in HTML because the folder structure will change at build-time and also the linked markdown file will be converted to &lt;code&gt;index.html&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So this won&#39;t work:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Post title&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;../yyyy-mm-dd-post-title/yyyy-mm-dd-post-title.md&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But this one below will, because &lt;code&gt;index.html&lt;/code&gt; is the default file for a folder, so we just need to omit everything that comes after the last slash from the link.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;Post title&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#ABB2BF&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-light-text-decoration:inherit;--shiki-dark:#C678DD;--shiki-dark-text-decoration:underline&quot;&gt;../post-title/&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#E06C75&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To edit the links at build-time there is another &lt;strong&gt;markdown-it&lt;/strong&gt; plugin, &lt;a href=&quot;https://github.com/martinheidegger/markdown-it-replace-link&quot;&gt;martinheidegger/markdown-it-replace-link&lt;/a&gt;, which allow to set some rules inside &lt;code&gt;eleventy.config.js&lt;/code&gt; to replace the relative links with the correct ones.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;mdLib&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;use&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt;markdownItLinks&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	processHTML&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// defaults to false for backwards compatibility&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;	replaceLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;token&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-light-font-style:inherit;--shiki-dark:#E06C75;--shiki-dark-font-style:italic&quot;&gt;htmlToken&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		if&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;includes&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;.md&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;			// remove the content after the last slash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			const&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#E5C07B&quot;&gt; newLink&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;replace&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#E06C75&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;^&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt;/]&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#D19A66&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#E06C75&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;			return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; newLink&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;		}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E06C75&quot;&gt; link&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;});&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;Typography&lt;/h5&gt;
&lt;p&gt;Even a minimalist blog can still have great typography, and since most of the content would be text and code anyways, it&#39;s very easy to have nice looking website with a few steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Extracting the &lt;code&gt;.prose&lt;/code&gt; class styles from the &lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss-typography&quot;&gt;tailwindlabs/tailwindcss-typography&lt;/a&gt; plugin and adding it to the markdown CSS files, provides a great starting point to tweak going forward.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the &lt;a href=&quot;https://github.com/11ty/eleventy-plugin-syntaxhighlight&quot;&gt;11ty/eleventy-plugin-syntaxhighlight&lt;/a&gt; and pick a &lt;a href=&quot;https://prismjs.com&quot;&gt;Prism&lt;/a&gt; theme to add it to the CSS files. This blog is using the &lt;code&gt;prism-one-dark&lt;/code&gt; theme.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy-base-blog&quot;&gt;11ty/eleventy-base-blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy-plugin-syntaxhighlight&quot;&gt;11ty/eleventy-plugin-syntaxhighlight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bnijenhuis.nl/notes/automatically-generate-open-graph-images-in-eleventy/&quot;&gt;Automatically generate open graph images in Eleventy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://code.visualstudio.com/docs/languages/markdown/&quot;&gt;Markdown and Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/martinheidegger/markdown-it-replace-link&quot;&gt;martinheidegger/markdown-it-replace-link&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plausible.io&quot;&gt;Plausible Analytics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://prismjs.com&quot;&gt;PrismJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/solution-loisir/markdown-it-eleventy-img&quot;&gt;solution-loisir/markdown-it-eleventy-img&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tailwindlabs/tailwindcss-typography&quot;&gt;tailwindlabs/tailwindcss-typography&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tinylytics.app/&quot;&gt;Tinylytics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/Provider/Style/URI.html&quot;&gt;W3C - Cool URIs don&#39;t change&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://css-tricks.com/working-with-web-feeds-its-more-than-rss&quot;&gt;Working With Web Feeds: It’s More Than RSS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Setup a blog with Eleventy 2.0, Tailwind and Alpine.js</title>
		<link href="https://dan-webnotes.com/posts/2023-02-19-setup-a-blog-with-eleventy-2-tailwind-alpine/"/>
		<updated>2023-02-19T00:00:00Z</updated>
		<id>https://dan-webnotes.com/posts/2023-02-19-setup-a-blog-with-eleventy-2-tailwind-alpine/</id>
		<content type="html">&lt;p&gt;2023-02-19&lt;/p&gt;
&lt;h1 id=&quot;setup-a-blog-with-eleventy-2-0-tailwind-and-alpine-js&quot;&gt; Setup a blog with Eleventy 2.0, Tailwind and Alpine.js&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Hello world! My current job is front-end developer and I wanted to have a new home for my own ideas and tinkering.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This didn&#39;t took place on a whim of a boring sunday afternoon, but took a few weeks, and it started with looking into very nice &lt;strong&gt;Next.js&lt;/strong&gt; &lt;a href=&quot;https://nextra.site&quot;&gt;starter templates&lt;/a&gt;. They looked amazing but I still decided to trying to develop it with the absolute minimum setup.&lt;/p&gt;
&lt;p&gt;As &lt;a href=&quot;https://www.11ty.dev&quot;&gt;Eleventy&lt;/a&gt; just released the new 2.0 version, it&#39;s the perfect occasion to test this new software. It is a highly-praised &lt;strong&gt;static-site generator&lt;/strong&gt; and this new version comes with even better DX experience. It only takes forking their official starter template from their website, &lt;a href=&quot;https://github.com/11ty/eleventy-base-blog&quot;&gt;11ty/eleventy-base-blog&lt;/a&gt; to get started building.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://dan-webnotes.com/posts/2023-02-19-setup-a-blog-with-eleventy-2-tailwind-alpine/eleventy-base-blog.png&quot; alt=&quot;A screenshot of the Eleventy starter template homepage&quot;&gt;
&lt;em&gt;The starting point&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;installing-tailwind-and-alpine-js&quot;&gt; Installing Tailwind and Alpine.js&lt;/h2&gt;
&lt;p&gt;One great thing of doing front-end dev today is using libraries like &lt;a href=&quot;https://tailwindcss.com&quot;&gt;Tailwind&lt;/a&gt; and &lt;a href=&quot;https://alpinejs.dev&quot;&gt;Alpine.js&lt;/a&gt; because they allow for speedy development and iteration, letting you focus on the blog content.
This is the stack this blog will use, you just need to install them with &lt;strong&gt;npm&lt;/strong&gt; to get started.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;npm&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; tailwindcss&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; alpinejs&lt;/span&gt;&lt;span style=&quot;color:#986801;--shiki-dark:#D19A66&quot;&gt; --save-dev&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I created &lt;code&gt;index.css&lt;/code&gt; and &lt;code&gt;index.js&lt;/code&gt; files in the &lt;code&gt;src&lt;/code&gt; folder and added the following to the &lt;code&gt;index.js&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt; Alpine&lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt; from&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;alpinejs&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#E5C07B&quot;&gt;Alpine&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#4078F2;--shiki-dark:#61AFEF&quot;&gt;start&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And as the usual Tailwind setup, I created a &lt;code&gt;tailwind.config.js&lt;/code&gt; file and a &lt;code&gt;postcss.config.js&lt;/code&gt; file in the root of my project.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// tailwind.config.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	content&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt;&quot;./_includes/**/*.njk&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	theme&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;		extend&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	variants&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;		extend&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	plugins&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; [],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;content&lt;/code&gt; property is used by Tailwind to know which files to scan for tailwind classes, in my case I am using &lt;strong&gt;Nunjucks&lt;/strong&gt; templates, so I added the path to my &lt;code&gt;njk&lt;/code&gt; files.&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A0A1A7;--shiki-light-font-style:italic;--shiki-dark:#7F848E;--shiki-dark-font-style:italic&quot;&gt;// postcss.config.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E5C07B&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#56B6C2&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;	plugins&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;		tailwindcss&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E45649;--shiki-dark:#E06C75&quot;&gt;		autoprefixer&lt;/span&gt;&lt;span style=&quot;color:#0184BC;--shiki-dark:#ABB2BF&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; {},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;	},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then I added to my &lt;code&gt;index.css&lt;/code&gt; file the following:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@tailwind&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; base;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@tailwind&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; components;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;@tailwind&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; utilities;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;eleventy-and-its-new-features&quot;&gt; Eleventy and its new features&lt;/h2&gt;
&lt;p&gt;Eleventy 2.0 comes with a lot of new features, from reading their official &lt;a href=&quot;https://www.11ty.dev/blog/eleventy-v2/&quot;&gt;announcement&lt;/a&gt;, they worked hard to improve performances: dependencies are smaller, build times are faster, and the DX is better.&lt;/p&gt;
&lt;p&gt;One improvement in this new version is that some really useful plugins are included out-of-the-box or are very easy to install. I am using the following plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/rss/&quot;&gt;eleventy-plugin-rss&lt;/a&gt; to generate an RSS feed
&lt;blockquote&gt;
&lt;h6&gt;⚠️ Warning:&lt;/h6&gt;
&lt;p&gt;The Rss plugin only works with the Nunjucks template engine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/syntaxhighlight/&quot;&gt;eleventy-plugin-syntaxhighlight&lt;/a&gt; to add syntax highlighting to code blocks&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/image/&quot;&gt;eleventy-img&lt;/a&gt; to perform build-time image transformations, it can output multiple sizes, in multiple formats, cache remote images locally&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/navigation/&quot;&gt;eleventy-navigation&lt;/a&gt; to easily generate navigation menus&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@11ty/eleventy-plugin-bundle/&quot;&gt;eleventy-plugin-bundle&lt;/a&gt;, it lets you create small bundles where you need them, even on a per-page basis, more on this later&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/server-vite/&quot;&gt;eleventy-plugin-vite&lt;/a&gt; which lets you use &lt;strong&gt;Vite&lt;/strong&gt; to bundle your assets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This sounds like a lot, but once they are installed and configured, they are really easy to use and it&#39;s difficult to bump into any issues.&lt;/p&gt;
&lt;p&gt;It was nice to to use the &lt;code&gt;eleventy-plugin-bundle&lt;/code&gt; plugin to create small bundles only where it made sense.
For example, since only the blog posts rely on markdown, I needed the css that styles the content only in my post template, to do so I added the following to my &lt;code&gt;post.njk&lt;/code&gt; file:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;src/css/markdown.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;src/css/prism-one-dark.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{%- &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endcss&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which will be loaded inline only in the posts pages for better performance. In the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of my &lt;code&gt;base.njk&lt;/code&gt; template file I have this:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{%- &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;css&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;src/css/index.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;src/css/utility.css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endcss&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;style&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;getBundle&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;css&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&amp;#x3C;/style&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also do the same to load javascript files, and use the &lt;code&gt;getBundle&lt;/code&gt; tag to inline the script files, but for this specific use case I noticed that the loading was smoother by using the other plugin feature, which loads the scripts in a single file.&lt;/p&gt;
&lt;p&gt;At the beginning of this project I was trying to set a specific &lt;code&gt;--pathprefix&lt;/code&gt; option but I got some issue with the inlined javascript so I ended up doing this instead:&lt;/p&gt;
&lt;pre class=&quot;shiki shiki-themes one-light one-dark-pro&quot; style=&quot;background-color:#FAFAFA;--shiki-dark-bg:#282c34;color:#383A42;--shiki-dark:#abb2bf&quot; tabindex=&quot;0&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{%- &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;js&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;public/js/index.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;  {% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;include&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;public/js/gradient.js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;endjs&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt;&amp;#x3C;script type=&quot;module&quot; src=&quot;{% &lt;/span&gt;&lt;span style=&quot;color:#A626A4;--shiki-dark:#C678DD&quot;&gt;getBundleFileUrl&lt;/span&gt;&lt;span style=&quot;color:#50A14F;--shiki-dark:#98C379&quot;&gt; &quot;js&quot;&lt;/span&gt;&lt;span style=&quot;color:#383A42;--shiki-dark:#ABB2BF&quot;&gt; %}&quot;&gt;&amp;#x3C;/script&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Anyways those are quite small performance optimizations. I will write next a post about the choices I made to ensure this blog is fast to modify and maintain.&lt;/p&gt;
&lt;h3 id=&quot;resources&quot;&gt; Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/11ty/eleventy-base-blog&quot;&gt;11ty/eleventy-base-blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://alpinejs.dev&quot;&gt;Alpine.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev&quot;&gt;Eleventy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/image/&quot;&gt;eleventy-img&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/navigation/&quot;&gt;eleventy-navigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/@11ty/eleventy-plugin-bundle/&quot;&gt;eleventy-plugin-bundle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/rss/&quot;&gt;eleventy-plugin-rss&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/plugins/syntaxhighlight/&quot;&gt;eleventy-plugin-syntaxhighlight&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.11ty.dev/docs/server-vite/&quot;&gt;eleventy-plugin-vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://tailwindcss.com&quot;&gt;Tailwind&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
</feed>
