<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:a="http://www.w3.org/2005/Atom"><channel><a:link href="https://mefody.dev/feed/rss.xml" rel="self" type="application/rss+xml"/><title>Dev Tips by Nikita Dubko</title><link>https://mefody.dev</link><language>en</language><description>Hello, my name is Nikita and I am a front-end developer. Here are life hacks and tips related to my daily work.</description><pubDate>Sat, 10 Feb 2024 00:00:00 GMT</pubDate><lastBuildDate>Sat, 10 Feb 2024 00:00:00 GMT</lastBuildDate><item><title>Weekly Links: 10 February 2024</title><link>https://mefody.dev/chunks/weekly-2024-02-10/</link><pubDate>Sat, 10 Feb 2024 00:00:00 GMT</pubDate><description><![CDATA[<ul>
<li><a href="https://groups.google.com/a/chromium.org/g/blink-dev/c/CWP5rb--Gyk/m/cpRngx-BAAAJ">Intent to Prototype: CSS line-clamp property</a> — CSS Overflow Module Level 4 proposal without <code>-webkit</code> prefixes.</li>
<li><a href="https://cloudfour.com/thinks/how-to-embed-3d-models-on-the-web/">How to Embed 3D Models on the Web</a> — Jason Grigsby shares a cross-browser way.</li>
<li><a href="https://heydonworks.com/article/offloading-javascript-with-custom-properties/">Offloading JavaScript With Custom Properties</a> — Heydon Pickering made an IntersectionObserver solution as a module for his clients to start playing with scroll-based visual effects.</li>
<li><a href="https://risingstars.js.org/2023/en">2023 JavaScript Rising Stars</a> — A comparison of the number of stars added on GitHub over the last 12 months.</li>
<li><a href="https://www.youtube.com/watch?v=lN3ntsSJXyI">Discover the Side Panel API for PWAs</a> — Microsoft Edge team is experimenting with a new API for a side-by-side multitasking experience.</li>
<li><a href="https://blog.chromium.org/2024/02/chromium-issue-tracker-migration-is.html">Chromium Issue Tracker migration is complete</a> — Issue tracking moved from Monorail.</li>
<li><a href="https://frontendmasters.com/blog/mask-your-icons/">Making your SVG icons CSS masks instead of inline HTML or backgrounds has some benefits</a> — Chris Coyier shares the way to style monochrome icons.</li>
</ul>
]]></description><guid>https://mefody.dev/chunks/weekly-2024-02-10/</guid></item><item><title>A CSS editor written in CSS</title><link>https://mefody.dev/chunks/css-editor-in-css/</link><pubDate>Thu, 08 Feb 2024 00:00:00 GMT</pubDate><description><![CDATA[<p>I found an <a href="https://front-end.social/@mia/111889170998301977">interesting tooth</a> by Miriam Suzanne. She suggests combining <code>@scope</code>, CSS Container Queries, and a bit of <code>contenteditable</code> magic to make a CSS editor in CSS. No JavaScript, no libraries. Let’s try it out!</p>
<h2>HTML</h2>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>css-demo</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>panels<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span> <span class="token attr-name">spellcheck</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>false<span class="token punctuation">"</span></span> <span class="token attr-name">contenteditable</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
<span class="token atrule"><span class="token rule">@scope</span></span> <span class="token punctuation">{</span>
    <span class="token comment">/* Demo CSS */</span>
<span class="token punctuation">}</span>
        </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>demo<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
            <span class="token comment">&lt;!-- Demo HTML --></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>css-demo</span><span class="token punctuation">></span></span></code></pre>
<p>Our custom tag <code>&lt;css-demo&gt;</code> has <code>display: inline</code> by default, just like a <code>span</code>. We need to change it in CSS later.</p>
<p>With <code>contenteditable</code> attribute on a tag you can edit the text of the tag. We’ve already used it <a href="https://mefody.dev/chunks/css-editor-in-css/chunks/design-mode/">here</a>.</p>
<p>Add <code>spellcheck=&quot;false&quot;</code> to disable automatic spell checking. Yeah, browser, I see that my CSS is not really English.</p>
<h2>CSS</h2>
<p>All the magic happens here.</p>
<p>Let’s make a grid with two columns of the same width.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">*</span> <span class="token punctuation">{</span>
    <span class="token property">box-sizing</span><span class="token punctuation">:</span> border-box<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token selector">css-demo</span> <span class="token punctuation">{</span>
    <span class="token property">--height</span><span class="token punctuation">:</span> 100vh<span class="token punctuation">;</span> <span class="token comment">/* let's make it fullscreen */</span>

    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--height<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token comment">/* fix default `inline` behaviour */</span>

    <span class="token selector">.panels</span> <span class="token punctuation">{</span>
        <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
        <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr<span class="token punctuation">;</span>
        <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--height<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">border</span><span class="token punctuation">:</span> 3px solid #777<span class="token punctuation">;</span>

        <span class="token selector">> style</span> <span class="token punctuation">{</span>
            <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token selector">> .demo</span> <span class="token punctuation">{</span>
            <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
            <span class="token property">place-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
            <span class="token property">border-left</span><span class="token punctuation">:</span> 3px solid #777<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Yeah, I use CSS Nesting, why not? It looks suitable here. And there is a pretty border to separate the code and the demo.</p>
<p>I added a <code>.panels</code> wrapper to Miriam’s example to have more freedom to style the container.</p>
<p>Then we need to make our <code>&lt;style&gt;</code> content visible and readable.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">style</span> <span class="token punctuation">{</span>
    <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span> <span class="token comment">/* magic! */</span>
    <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">"Fira Code"</span><span class="token punctuation">,</span> monospace<span class="token punctuation">;</span>
    <span class="token property">white-space</span><span class="token punctuation">:</span> pre<span class="token punctuation">;</span>
    <span class="token property">overflow</span><span class="token punctuation">:</span> scroll<span class="token punctuation">;</span>
    <span class="token property">padding</span><span class="token punctuation">:</span> 1em 1.5em<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can use any monospaced font to display the code.</p>
<p>Make sure you use <code>white-space: pre</code> to display the CSS code as it was written in your demo source code.</p>
<p>Let’s make it adaptive and embeddable. CSS Container Queries — that’s your time!</p>
<pre class="language-css"><code class="language-css"><span class="token selector">css-demo</span> <span class="token punctuation">{</span>
    <span class="token property">container</span><span class="token punctuation">:</span> css-demo / size<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@container</span> css-demo <span class="token punctuation">(</span>width &lt; 800px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector">.panels</span> <span class="token punctuation">{</span>
        <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr<span class="token punctuation">;</span>
        <span class="token property">grid-template-rows</span><span class="token punctuation">:</span> 1fr 1fr<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>And let’s make our demo better for dark theme users.</p>
<pre class="language-css"><code class="language-css"><span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector">html</span> <span class="token punctuation">{</span>
        <span class="token property">color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Combine it all.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">*</span> <span class="token punctuation">{</span>
    <span class="token property">box-sizing</span><span class="token punctuation">:</span> border-box<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector">html</span> <span class="token punctuation">{</span>
        <span class="token property">color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token selector">css-demo</span> <span class="token punctuation">{</span>
    <span class="token property">--height</span><span class="token punctuation">:</span> 100vh<span class="token punctuation">;</span>
    <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--height<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
    <span class="token property">container</span><span class="token punctuation">:</span> css-demo / size<span class="token punctuation">;</span>

    <span class="token selector">.panels</span> <span class="token punctuation">{</span>
        <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
        <span class="token property">height</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--height<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr 1fr<span class="token punctuation">;</span>
        <span class="token property">border</span><span class="token punctuation">:</span> 3px solid #777<span class="token punctuation">;</span>

        <span class="token selector">> style</span> <span class="token punctuation">{</span>
            <span class="token property">display</span><span class="token punctuation">:</span> block<span class="token punctuation">;</span>
            <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">"Fira Code"</span><span class="token punctuation">,</span> monospace<span class="token punctuation">;</span>
            <span class="token property">white-space</span><span class="token punctuation">:</span> pre<span class="token punctuation">;</span>
            <span class="token property">overflow</span><span class="token punctuation">:</span> scroll<span class="token punctuation">;</span>
            <span class="token property">height</span><span class="token punctuation">:</span> 100%<span class="token punctuation">;</span>
            <span class="token property">padding</span><span class="token punctuation">:</span> 1em 1.5em<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token selector">> .demo</span> <span class="token punctuation">{</span>
            <span class="token property">display</span><span class="token punctuation">:</span> grid<span class="token punctuation">;</span>
            <span class="token property">place-items</span><span class="token punctuation">:</span> center<span class="token punctuation">;</span>
            <span class="token property">border-left</span><span class="token punctuation">:</span> 3px solid #777<span class="token punctuation">;</span>
        <span class="token punctuation">}</span>

        <span class="token atrule"><span class="token rule">@container</span> css-demo <span class="token punctuation">(</span>width &lt; 800px<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
            <span class="token selector">&amp;</span> <span class="token punctuation">{</span>
                <span class="token property">grid-template-columns</span><span class="token punctuation">:</span> 1fr<span class="token punctuation">;</span>
                <span class="token property">grid-template-rows</span><span class="token punctuation">:</span> 1fr 1fr<span class="token punctuation">;</span>

                <span class="token selector">> .demo</span> <span class="token punctuation">{</span>
                    <span class="token property">border-top</span><span class="token punctuation">:</span> 3px solid #777<span class="token punctuation">;</span>
                    <span class="token property">border-left</span><span class="token punctuation">:</span> none<span class="token punctuation">;</span>
                <span class="token punctuation">}</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
</details>
<p>You can play with the component <a href="https://codepen.io/dark_mefody/full/PoLdPoY">here</a>.</p>
<p>Unfortunately, right now, this CSS editor <a href="https://caniuse.com/css-cascade-scope">only works</a> in stable Chrome and Safari Technology Preview. But I believe it will work in Firefox <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=%40scope">soon</a>.</p>
]]></description><guid>https://mefody.dev/chunks/css-editor-in-css/</guid></item><item><title>Weekly Links: 03 February 2024</title><link>https://mefody.dev/chunks/weekly-2024-02-03/</link><pubDate>Sat, 03 Feb 2024 00:00:00 GMT</pubDate><description><![CDATA[<ul>
<li><a href="https://blog.shalvah.me/posts/learn-svg-by-drawing-an-arrow">Learn SVG by drawing an arrow</a> — Demonstration of SVG by constructing an arrow in HTML/JavaScript. Step by step, with Math and pictures.</li>
<li><a href="https://developer.apple.com/documentation/safari-release-notes/safari-17_4-release-notes">Safari 17.4 Beta Release Notes</a> — A lot of new features in CSS, forms, JavaScript, Web Components, etc. <code>@scope</code> is my favorite.</li>
<li><a href="https://www.figma.com/blog/dev-mode-ga/">What’s next for Dev Mode: Annotations, Compare Changes, Plugins, and More</a> — Figma moves Dev Mode out of free beta.</li>
<li><a href="https://pawelgrzybek.com/stop-resolving-the-same-merge-conflict-multiple-times-during-merge-or-rebase-using-git-rerere/">Stop resolving the same merge conflict multiple times during merge or rebase using git rerere</a> — REuse REcorded REsolution.</li>
<li><a href="https://piccalil.li/blog/a-highly-configurable-switch-component-using-modern-css/">A highly configurable switch component using modern CSS techniques</a> — Andy Bell builds a switch component step by step.</li>
<li><a href="https://ryanmulligan.dev/blog/scroll-triggered-animations-style-queries/">CSS Scroll-triggered Animations with Style Queries</a> — Ryan Mulligan is experimenting with scroll-driven animation to create an interesting text appearance effect.</li>
<li><a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-4-beta/">Announcing TypeScript 5.4 Beta</a> — <code>NoInfer</code> utility type, <code>groupBy</code> declarations, new quick fix to add new parameters to functions in VSCode.</li>
<li><a href="https://www.caniemail.com/news/2024-01-29-new-outlook-macos/">The new Outllok on macOS</a> — In Email Client Support Scoreboard, the new Outlook on macOS falls from the 3rd position to the 23rd position.</li>
<li><a href="https://www.zachleat.com/web/carouscroll/">carouscroll Web Component</a> — A zero-dependency web component to add next and previous buttons to a scrollable container by Zach Leatherman.</li>
<li><a href="https://codepen.io/monochromer/pen/abMqObP">Images with backdrop blur. Double picture image feature</a> — Interesting usage of <code>picture</code> with two <code>img</code>s without <code>src</code>.</li>
<li><a href="https://webkit.org/blog/14955/the-web-just-gets-better-with-interop/">The web just gets better with Interop 2024</a> — The 2024 focus areas.</li>
<li><a href="https://web.dev/blog/interop-2023-wrapup">Celebrate a more interoperable web with Interop 2023</a> — The final scores of really great job.</li>
</ul>
]]></description><guid>https://mefody.dev/chunks/weekly-2024-02-03/</guid></item><item><title>Different favicon for development build</title><link>https://mefody.dev/chunks/favicon-dev/</link><pubDate>Tue, 30 Jan 2024 00:00:00 GMT</pubDate><description><![CDATA[<p>It’s really annoying when you spend a lot of time trying to catch a bug in the local build when, in fact, you’ve been looking at the production version the whole time.</p>
<p>When coding, I usually have several versions of the website open: the production version, the local version, and the version on the testing stage. When they all have the same title and the same favicons, it can be confusing.</p>
<figure >
    <img src="https://mefody.dev/chunks/favicon-dev/images/same-tabs.jpg" alt="Three tabs in browser look the same." loading="lazy" decoding="async">
    <figcaption>
        Ok, where are you?
    </figcaption>
</figure>
<p>It will be handy if the tab in the browser looks different for different builds. And I can change the favicon, can’t I?</p>
<figure >
    <img src="https://mefody.dev/chunks/favicon-dev/images/different-tabs.jpg" alt="Three tabs in browser. The second tab has different favicon." loading="lazy" decoding="async">
    <figcaption>
        Here you are!
    </figcaption>
</figure>
<h2>The simplest favicon</h2>
<p>Lea Verou <a href="https://twitter.com/LeaVerou/status/1241619866475474946">twitted</a> a modern way to make a minimalistic emoji favicon.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>svg</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://w3.org/2000/svg<span class="token punctuation">"</span></span> <span class="token attr-name">viewBox</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>0 0 100 100<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>text</span> <span class="token attr-name">y</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>.9em<span class="token punctuation">"</span></span> <span class="token attr-name">font-size</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>90<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>🍉<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>text</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>svg</span><span class="token punctuation">></span></span></code></pre>
<p>That’s it. Simple, three lines of code, working.</p>
<p>This is handy for three reasons:</p>
<ol>
<li>It’s easy to update.</li>
<li>You can make numerous different favicons.</li>
<li>They look equally good in light and dark themes.</li>
</ol>
<p>Ok, now just save your favorite emoji to <code>favicon_dev.svg</code>.</p>
<h2>Add the favicon to the project</h2>
<p>There are several options here.</p>
<h3>Build</h3>
<p>Most likely, you have a website build script. So, at build time, you can throw an environment variable to the builder.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"eleventy &amp;&amp; gulp build"</span><span class="token punctuation">,</span>
        <span class="token property">"build:prod"</span><span class="token operator">:</span> <span class="token string">"ELEVENTY_ENV=production npm run build"</span><span class="token punctuation">,</span>
        <span class="token property">"build:dev"</span><span class="token operator">:</span> <span class="token string">"ELEVENTY_ENV=development npm run build"</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>My blog is built using Gulp (yeah, yeah, and what are you going to do to me, I’m in another city). I would make this kind of replacement at build time.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">var</span> gulp <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> replace <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'gulp-replace'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

gulp<span class="token punctuation">.</span><span class="token function">task</span><span class="token punctuation">(</span><span class="token string">'favicon'</span><span class="token punctuation">,</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">ELEVENTY_ENV</span> <span class="token operator">===</span> <span class="token string">'production'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Promise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">resolve</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">resolve</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> gulp
        <span class="token punctuation">.</span><span class="token function">src</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token constant">PUBLIC_PATH</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">/**/index.html</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span><span class="token function">replace</span><span class="token punctuation">(</span>
            <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">&lt;link rel="icon" href="https://mefody.dev/chunks/favicon-dev/\/favicon\.ico"></span><span class="token regex-delimiter">/</span><span class="token regex-flags">g</span></span><span class="token punctuation">,</span>
            <span class="token string">'&lt;link rel="icon" href="https://mefody.dev/chunks/favicon-dev/favicon_dev.svg" type="image/svg+xml">'</span>
        <span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">pipe</span><span class="token punctuation">(</span>gulp<span class="token punctuation">.</span><span class="token function">dest</span><span class="token punctuation">(</span><span class="token constant">PUBLIC_PATH</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h4>Templating language</h4>
<p>My blog is a static site. There is Eleventy under the hood. The page templates are written using the <a href="https://mozilla.github.io/nunjucks/">Nunjucks</a>. Here’s how to teach Eleventy to swap out the favicon.</p>
<ol>
<li>Place environment variables into the <a href="https://www.11ty.dev/docs/data-cascade/">data cascade</a>.</li>
</ol>
<pre class="language-js"><code class="language-js"><span class="token comment">// file: src/data/isdevelopment.js</span>

<span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'dotenv'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">config</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

module<span class="token punctuation">.</span><span class="token function-variable function">exports</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">ELEVENTY_ENV</span> <span class="token operator">===</span> <span class="token string">'development'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
<ol start="2">
<li>Use the variable in your header template.</li>
</ol>
<pre class="language-html"><code class="language-html">{% if isdevelopment %}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/favicon_dev.svg<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>image/svg+xml<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
{% else %}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/favicon.ico<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>link</span> <span class="token attr-name">rel</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>apple-touch-icon<span class="token punctuation">"</span></span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>/images/favicon/favicon-180.png<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
{% endif %}</code></pre>
<h3>Client</h3>
<p>You can move the logic of changing the favicon to the client.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">if</span> <span class="token punctuation">(</span>location<span class="token punctuation">.</span>hostname <span class="token operator">===</span> <span class="token string">"localhost"</span> <span class="token operator">||</span>
    location<span class="token punctuation">.</span>hostname <span class="token operator">===</span> <span class="token string">"127.0.0.1"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> faviconEl <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">'link[rel=icon]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    faviconEl<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"href"</span><span class="token punctuation">,</span> <span class="token string">"/favicon_dev.svg"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    faviconEl<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">"type"</span><span class="token punctuation">,</span> <span class="token string">"image/svg+xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<h2>Sources</h2>
<ul>
<li><a href="https://strawberrycode.com/blog/favicon-dev-prod/">Different Favicon for Dev and Prod</a></li>
<li><a href="https://evilmartians.com/chronicles/how-to-favicon-in-2021-six-files-that-fit-most-needs">How to Favicon in 2024: Six files that fit most needs</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/favicon-dev/</guid></item><item><title>Weekly Links: 27 January 2024</title><link>https://mefody.dev/chunks/weekly-2024-01-27/</link><pubDate>Sat, 27 Jan 2024 00:00:00 GMT</pubDate><description><![CDATA[<ul>
<li><a href="https://frontendmasters.com/blog/highlight-text-when-a-user-scrolls-down-to-that-piece-of-text/">Highlight Text When a User Scrolls Down to That Piece of Text</a> — Great usage of CSS Scroll-Driven Animation. By Chris Coyier.</li>
<li><a href="https://moderncss.dev/12-modern-css-one-line-upgrades/">12 Modern CSS One-Line Upgrades</a> — Tiny useful code snippets by Stephanie Eckles.</li>
<li><a href="https://localghost.dev/blog/automated-weekly-links-posts-with-raindrop-io-and-eleventy/">Automated weekly links posts with raindrop.io and Eleventy</a> — That’s why this page exists.</li>
<li><a href="https://nerdy.dev/hacky-css-noise-with-repeating-gradients">Make some hacky noise with CSS gradients</a> — Adam Argyle creates an interesting text effect.</li>
<li><a href="https://lamplightdev.com/blog/2024/01/10/streaming-html-out-of-order-without-javascript/">Streaming HTML out of order without JavaScript</a> — Interesting usage of Declarative Shadow DOM for progressive rendering of a webpage.</li>
<li><a href="https://developer.chrome.com/blog/new-in-chrome-121?hl=en">New in Chrome 121</a> — Speculation Rules API updates, <code>scrollbar-color</code> and <code>scrollbar-width</code>, <code>font-palette</code>, <code>::spelling-error</code> and <code>::grammar-error</code>.</li>
<li><a href="https://www.devever.net/~hl/pics">Memoirs from the old web: IE’s crazy content rating system</a> — By Hugo Landau.</li>
<li><a href="https://spur-i-t.com/blog/key-updates-in-wcag-2-2-experts-overview/amp/">Key updates in WCAG 2.2: Expert’s overview</a> — Accessibility expert Glafira Zhur overviews the new criteria of WCAG 2.2 and finds out how it affects the accessibility landscape.</li>
</ul>
]]></description><guid>https://mefody.dev/chunks/weekly-2024-01-27/</guid></item><item><title>Styles of text selection</title><link>https://mefody.dev/chunks/selection/</link><pubDate>Sun, 26 Dec 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Some of you may notice that text selections in this blog are not default. I mean if you select some text its background is not blue. I believe that it is OK to change some defaults to make the design of your website more consistent. CSS can help you with that.</p>
<p><strong>Disclaimer:</strong> People expect some defaults by… default. And the selection is one of such things. Don’t change the default behavior just because you can. The selection should be obvious.</p>
<h2>Selection</h2>
<p>If the default blue background for the selection on your website is not compatible with the design of your website, you can use <code>::selection</code> pseudo-element to change it.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">::selection</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-text<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>For ancient Firefox versions (61 and below) don’t forget about <code>::-moz-selection</code>.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">::-moz-selection</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
    <span class="token property">background</span><span class="token punctuation">:</span> red<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The <code>::selection</code> pseudo can change not all the CSS properties inside of it. The list is really short:</p>
<ul>
<li><code>color</code>;</li>
<li><code>background-color</code>;</li>
<li><code>text-decoration</code>;</li>
<li><code>text-shadow</code>.</li>
</ul>
<p>If you use SVG, you can also change <code>stroke-color</code>, <code>fill-color</code>, and <code>stroke-width</code>.</p>
<p>This restriction can be simply explained. When the user selects the text, they expect to have an immediate response. And, of course, there should not be any layout shifts. Any background images can cause an image loading, and any margins will cause layout shifts. So, you can change only fast for rendering properties. And when you use <code>background: blue</code>, the browser will change it to <code>background-color: blue</code>.</p>
<p>It’s important to remember accessibility. The contrast ratio between the background color and text color must be at least <code>4.5:1</code>. Don’t forget about the contrast between selection background and element background. If they have almost the same color, your users will be confused.</p>
<p>By default, browsers try to use system settings for selection. For example, macOS users can change the selection color via “OS Settings → General” and Chrome <a href="https://github.com/chromium/chromium/blob/c4d3c31083a2e1481253ff2d24298a1dfe19c754/third_party/blink/renderer/core/layout/layout_theme_mac.mm#L59">respects this color</a>. There is no way to get this color from JS or CSS (it will be a big privacy issue if they can).</p>
<h2>Target selection</h2>
<p>There is another selection that Blink browsers have by default. Try to visit <a href="https://mefody.dev/chunks/selection/#:~:text=It%E2%80%99s%20important%20to%C2%A0remember%20accessibility">this link</a>. If you use Chromium-based browser you will see the selection on a text fragment passed to the URL. And you can style this selection too.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">::target-text</span> <span class="token punctuation">{</span>
    <span class="token property">color</span><span class="token punctuation">:</span> white<span class="token punctuation">;</span>
    <span class="token property">background-color</span><span class="token punctuation">:</span> tomato<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>The <code>::target-text</code> has the same restrictions as <code>::selection</code>. MDN proposes to change <code>font-weight</code> in their example, but I hope <a href="https://github.com/mdn/content/pull/11497">this PR</a> will be merged soon.</p>
<h2>Sources</h2>
<ul>
<li><a href="https://drafts.csswg.org/css-pseudo-4/#highlight-selectors">CSS Pseudo-Elements Module Level 4</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/selection/</guid></item><item><title>Inspect the ninja element available on hover or focus</title><link>https://mefody.dev/chunks/hover-debug/</link><pubDate>Thu, 09 Dec 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Sometimes you have a task to debug some element that is displayed on hover or focus. But it hides when clicked outside the viewport. For example, when you click somewhere in DevTools.</p>
<p>So, how to debug such ninja elements? Let’s use Chrome DevTools possibilities for that.</p>
<h2>Toggle element state</h2>
<p>The most general solution is to choose <code>:hover</code> state in the Toggle Element State panel.</p>
<figure >
    <img src="https://mefody.dev/chunks/hover-debug/images/toggle-state.png" alt="Toggle Element State panel in DevTools." loading="lazy" decoding="async">
    <figcaption>
        It is hidden under the `:hov` button in a Styles drawer.
    </figcaption>
</figure>
<p>Let’s see it in action.</p>
<figure >
    <video width="1440" height="900" controls muted  playsinline preload="metadata">
    <source src="https://mefody.dev/chunks/hover-debug/images/netlify@1440.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
    <source src="https://mefody.dev/chunks/hover-debug/images/netlify@1440.h264.mp4" type="video/mp4">
</video>
    <figcaption>
        Just use `:hover` toggler.
    </figcaption>
</figure>
<p>Unfortunately, in many cases, enabling pseudo-classes is not enough.</p>
<h2>Emulate a focused page</h2>
<p>For pages that use JavaScript to toggle a focused state you can try to emulate focus on a page. Did you know that you can call a Command Menu with <kbd>Ctrl Shift P</kbd> (<kbd>⌘ ⇧ P</kbd> for macOS)? It has a command <code>Emulate a focused page</code> that can help us with our issue.</p>
<figure >
    <img src="https://mefody.dev/chunks/hover-debug/images/emulate-focus.png" alt="Command Menu in DevTools with `focu` typed." loading="lazy" decoding="async">
    <figcaption>
        It is also available with “Run command” command :)
    </figcaption>
</figure>
<p>Let’s see it in action.</p>
<figure >
    <video width="1440" height="900" controls muted  playsinline preload="metadata">
    <source src="https://mefody.dev/chunks/hover-debug/images/yandex@1440.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
    <source src="https://mefody.dev/chunks/hover-debug/images/yandex@1440.h264.mp4" type="video/mp4">
</video>
    <figcaption>
        Perfect case!
    </figcaption>
</figure>
<h2>Break on attribute modifications</h2>
<p>In some very strange cases, the hover state is set with JavaScript. And it is difficult to debug such cases because JS doesn’t handle a focus state. But we have a “hammer” for that.</p>
<figure >
    <img src="https://mefody.dev/chunks/hover-debug/images/break-on.png" alt="&quot;Break on...&quot; menu in DevTools." loading="lazy" decoding="async">
    <figcaption>
        Right Click on a DOM-element, Break on..., attribute modifications.
    </figcaption>
</figure>
<p>When the class attribute of the element is changed, we’ll have a JavaScript breakpoint triggered.</p>
<p>Let’s see it in action.</p>
<figure >
    <video width="1440" height="900" controls muted  playsinline preload="metadata">
    <source src="https://mefody.dev/chunks/hover-debug/images/amazon@1440.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
    <source src="https://mefody.dev/chunks/hover-debug/images/amazon@1440.h264.mp4" type="video/mp4">
</video>
    <figcaption>
        The debugger freezes the page, so you can easily inspect all the elements.
    </figcaption>
</figure>
<h2>Materials</h2>
<ul>
<li><a href="https://getfrontend.tips/inspect-an-element-shown-on-hover/">Inspect an element shown on hover</a></li>
<li><a href="https://developer.chrome.com/docs/devtools/command-menu/">Run commands in the Command Menu</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/hover-debug/</guid></item><item><title>Accessible components from scratch</title><link>https://mefody.dev/chunks/a11y-from-scratch/</link><pubDate>Mon, 15 Nov 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Recently, my colleagues asked me to create a small checklist for making an accessible component from scratch. Here it is.</p>
<h2>Why do I need to make something accessible?</h2>
<p>Do you have a perfect vision? Will it be perfect forever?</p>
<p>Have you had your hand broken sometime? Arm dislocation, maybe? Cut your finger? How was it to use websites?</p>
<p>Did you have a broken mouse sometime? Broken touchpad? Imagine that your touchpad is broken, and you need to find some repair service to fix it, but your phone is discharged, and the search page is made the way you can’t follow the link using the keyboard. Good luck!</p>
<p>We (developers) still do not know how to calculate the lost profit. Anatoly Popko (my blinded colleague from Yandex) said that he wants to spend his money using some services but the services don’t want to get his money just because their functionality is inaccessible.</p>
<p>When we make our websites comfortable for people with disabilities, we make these sites very comfortable for us.</p>
<h2>How can people use your site?</h2>
<ul>
<li><em>With a screenreader.</em> The website is voiced by a screenreader. It’s useful for blinded people.</li>
<li><em>With keyboard.</em> There is a possibility to use website without mouse, using <kbd>Tab</kbd>, <kbd>Enter</kbd>, <kbd>Space</kbd> and arrows. It’s useful for people with locomotor system disabilities or somebody who just want to use a keyboard.</li>
<li><em>With a mouse.</em> It’s useful for people who can’t use a keyboard.</li>
<li><em>With zoom.</em> Just because I have poor eyesight.</li>
<li><em>With contrast.</em> For people with color blindness.</li>
<li><em>Without animations.</em> For people with epilepsy.</li>
<li><em>With left hand.</em> For left-handed persons.</li>
</ul>
<h2>How to make the component accessible?</h2>
<h3>1. Use ready-made solutions</h3>
<p>You are not the first person who wants to make an accessible component. Smashing Magazine has an <a href="https://www.smashingmagazine.com/2021/03/complete-guide-accessible-front-end-components/">awesome article</a> with many links about the a11y.</p>
<h3>2. Use semantic tags</h3>
<p>Screenreader will do all the job if you have <code>nav</code>, <code>ul</code>, <code>button</code>, <code>a</code>, <code>dialog</code>, etc. It can’t do the same if you use <code>div</code> and <code>span</code> only.</p>
<h3>3. Use ARIA</h3>
<p>If you can’t solve your task with semantic tags only. But please, try point 2 first.</p>
<h3>4. Do not use tiny interactive elements</h3>
<p>Try to touch some tiny <code>5×5</code> button to close some adv popup. It enrages! Use <code>44px</code> as a minimum dimension for any interactive element, it’s enough for fingers.</p>
<h3>5. Link <code>&lt;a&gt;</code> should have some text inside it</h3>
<p>Screenreader reads the URL if it hasn’t. Let me guess, you don’t have readable URLs for all your links, have you? If your links don’t have texts by design, add <code>&lt;span class=&quot;visibility-hidden&quot;&gt;Text&lt;/span&gt;</code> for that. But try to talk to your designer first.</p>
<h3>6. Links vs Buttons</h3>
<p>Do you have the web-app state recoverable by URL? It’s an <code>&lt;a&gt;</code> link. Haven’t you? It’s a <code>&lt;button&gt;</code>.</p>
<h3>7. Don’t use only icons for buttons or links</h3>
<p>Add some hidden <code>span</code> or <code>aria-label</code> to give that element a text. Talk to your designer to make the element better. Not every person understands your icons, but almost everybody understands the text.</p>
<h3>8. Add <code>alt</code> to your images</h3>
<p>Blind people want to read them too. Can’t you do that? Use <code>alt=&quot;&quot;</code> to hide the image from screenreader. It will announce the URL if you haven’t an <code>alt</code> attribute. Let me guess, you don’t have readable URLs for all your images, have you?</p>
<h3>9. Don’t hide visual focus</h3>
<p>If you don’t like the default style of a focus, make your own custom styles. Explain to your designer, that you can’t hide the focus. If they argue with you, add the <code>cursor: none</code> to their Firgma workspace to explain it more clearly.</p>
<h3>10. Trap the focus inside the modal.</h3>
<p>The focus shouldn’t move outside.</p>
<h3>11. Move the focus inside the modal on its opening</h3>
<h3>12. Return the focus back when the modal is closed</h3>
<h3>13. Don’t use only the colors to create some difference</h3>
<p>If you use red to mark errors and green to mark success messages, somebody sees <em>some</em> color to mark <em>something</em>… Add icons, text, underlines instead. Why in general we use red color to mark something dangerous, huh?</p>
<h3>14. Use captions for videos</h3>
<p>Don’t use videos with forced subtitles, they can’t be translated.</p>
<h3>15. Use <code>prefers-*</code> media features</h3>
<p>For example, <code>prefers-reduced-motion</code> or <code>prefers-contrast</code>. If I’ve set such an option for my OS, I have some reasons for that.</p>
<h3>16. Don’t use tiny font size</h3>
<p>It’s annoying. I can’t see tiny texts. If your designer decided to use <code>10px</code> as a font-size, make his Figma workspace <em>better</em> with <code>font-size: 5px !important</code> everywhere. But try to talk with them first.</p>
<h3>17. Don’t try too hard</h3>
<p>Make your general scenarios work first. If your ’BUY’ button doesn’t work, it makes no sense to add perfect captions to all the images on a page. Fix the main scenario first.</p>
<h3>18. Use correct texts for interactive elements</h3>
<p>Don’t use <code>Button</code> text inside the <code>&lt;button&gt;</code>. All the roles are read by the screenreader by default.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://www.smashingmagazine.com/2021/03/complete-guide-accessible-front-end-components/">A Complete Guide To Accessible Front-End Components</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/a11y-from-scratch/</guid></item><item><title>Prevent text glyphs from turning into emojis</title><link>https://mefody.dev/chunks/emoji-to-text/</link><pubDate>Sun, 19 Sep 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Last year I had an interesting task to make a heart symbol a part of a page title. We were organizing ’Ya Love Frontend’ conference (Ya is for Yandex, but it sounds the same as ’I’ in Russian), and we used the UTF-8 heart symbol to make the title more emotional.</p>
<p>So, what’s the problem?</p>
<p>If you have the title ’I ❤ Frontend’, it is rendered differently in different browsers on different operating systems. For example, on Android and iOS it looks like emoji. And that’s a huge problem if you have to style the title.</p>
<h2>Unicode</h2>
<p>It’s all about rendering. Nikita Prokopov described it in <a href="https://tonsky.me/blog/emoji/">his detailed article about emojis</a>.</p>
<p>Every symbol you use has its UTF-8 sequence. For example, letter A is <code>U+0041</code>, letter Z is <code>U+005A</code>, $ is <code>U+0024</code>, etc. The same is for emoji, ❤ is <code>U+2764</code>.</p>
<p>You can even paste it into your HTML as a Unicode sequence, not a symbol.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>I ❤ Frontend<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span>
or
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>I <span class="token entity" title="&#x2764;">&amp;#x2764;</span> Frontend<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code></pre>
<p><code>&amp;#x</code> is for Unicode prefixing.</p>
<p>But what if the current font hasn’t any glyph that can render your UTF-8 symbol? OS tries to find any font that has that glyph. So, iOS will find the Apple Color Emoji font, Android will find the Noto Color Emoji font, etc. And it looks like we have some possibilities to control it.</p>
<h3>Fonts</h3>
<p>The first decision is to have a font that has all your necessary glyphs. For example, Arial. Or some custom font. You need to add that font to font fallbacks in your CSS.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">body</span> <span class="token punctuation">{</span>
    <span class="token property">font-family</span><span class="token punctuation">:</span> <span class="token string">'Text Font'</span><span class="token punctuation">,</span> <span class="token string">'Custom Glyphs Font'</span><span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>I don’t like such solutions because I can’t control all the glyphs in the text. Especially if I have some kind of content management system. And it’s a pain to rebuild the font every time I need a new glyph.</p>
<h3>Variation selectors</h3>
<p>Luckily, we have another option. UTF has special characters to control the rendering. <code>U+FE0E</code> asks OS and browser to render the previous glyph as text, <code>U+FE0F</code> asks to render the previous glyph as emoji.</p>
<p>So, let’s try to use it.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>ul</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token entity" title="&#x2600;">&amp;#x2600;</span> can be rendered differently.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token entity" title="&#x2600;">&amp;#x2600;</span><span class="token entity" title="&#xFE0F;">&amp;#xFE0F;</span> should look like a sun emoji.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>li</span><span class="token punctuation">></span></span><span class="token entity" title="&#x2600;">&amp;#x2600;</span><span class="token entity" title="&#xFE0E;">&amp;#xFE0E;</span> should look like a sun text symbol.<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>li</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>ul</span><span class="token punctuation">></span></span></code></pre>
<ul>
    <li>&#x2600; can be rendered differently.</li>
    <li>&#x2600;&#xFE0F; should look like a sun emoji.</li>
    <li>&#x2600;&#xFE0E; should look like a sun text symbol.</li>
</ul>
<p>So, if you need to disable emoji in your text, convert the symbol to UTF-8 or UTF-16 sequence (<code>symbol.codePointAt(0).toString(16)</code>), than add <code>&amp;#xFE0E</code> to it.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span><span class="token punctuation">></span></span>I <span class="token entity" title="&#x2764;">&amp;#x2764;</span><span class="token entity" title="&#xFE0E;">&amp;#xFE0E;</span> Frontend<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code></pre>
<p>But it won’t work for the heart emoji on Android. I don’t know why. When we tested it last year, it was ok, but… You can play around with different emojis <a href="https://codepen.io/dark_mefody/pen/NWgMxrd">in this sandbox</a>. As for me, something is better than nothing.</p>
<h2>Accessibility</h2>
<p>Remember that all emojis have text representations. For example, ⭐︎ is <code>white medium star</code>, ► is <code>black right-pointing pointer</code>, etc. And screen readers will use these texts.</p>
<p>So, our <code>I ❤ Frontend</code> becomes <code>I Red Heart Frontend</code>. I suppose we didn’t mean that.</p>
<p>To fix it, use the glyph <a href="https://tink.uk/accessible-emoji/">the right way</a>.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>img<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Love<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token entity" title="&#x2764;">&amp;#x2764;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span></code></pre>
<p>And the final result we used on the conference website is below.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h1</span><span class="token punctuation">></span></span>
    I <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>span</span> <span class="token attr-name">role</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>img<span class="token punctuation">"</span></span> <span class="token attr-name">aria-label</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Love<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token entity" title="&#x2764;">&amp;#x2764;</span><span class="token entity" title="&#xFE0E;">&amp;#xFE0E;</span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>span</span><span class="token punctuation">></span></span> Frontend!
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h1</span><span class="token punctuation">></span></span></code></pre>
<h2>Resources</h2>
<ul>
<li><a href="https://tonsky.me/blog/emoji/">Emoji under the hood</a></li>
<li><a href="https://mts.io/2015/04/21/unicode-symbol-render-text-emoji/">Unicode symbol as text or emoji</a></li>
<li><a href="https://codepoints.net/U+FE0E">U+FE0E VARIATION SELECTOR-15</a></li>
<li><a href="https://tink.uk/accessible-emoji/">Accessible emoji</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/emoji-to-text/</guid></item><item><title>Tell about the website creators using humans.txt</title><link>https://mefody.dev/chunks/humans-txt/</link><pubDate>Sat, 21 Aug 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>I check the analytics of this blog every week, especially the ‘Top resources not found’ section. Just to be sure that I have no broken links. This week, I found strange requests to the <code>/humans.txt</code> file. I’ve added <code>/robots.txt</code> before, but why somebody tries to open <code>/humans.txt</code>?</p>
<h2>We are people, not machines</h2>
<p>I found the answer on <a href="https://humanstxt.org/">humanstxt.org</a>. It’s a really cool initiative to add info about all the creators of the website.</p>
<blockquote>
<p>We are always saying that, but the only file we generate is one full of additional information for the searchbots: robots.txt. Then why not doing one for ourselves?</p>
</blockquote>
<p>And that’s true. So I’ve added <a href="https://mefody.dev/chunks/humans-txt/humans.txt">such file</a> to my blog.</p>
<p>Also, I found a lot of websites that already use the file in different ways.</p>
<ul>
<li>Google added <code>humans.txt</code> to their domain <a href="http://googlesystem.blogspot.com/2011/05/googles-humanstxt-file.html">almost ten years ago</a>.</li>
<li>GitHub redirects requests to this file to their ‘About’ page.</li>
<li>Evil Martians made redirect from <code>humans.txt</code> to <code>martians.txt</code> with the same format.</li>
</ul>
<h2>How to?</h2>
<ol>
<li>Add the file <code>humans.txt</code> to the root of your site.</li>
<li>Add info about all the site creators to this file.</li>
<li>Add <code>&lt;link rel=&quot;author&quot; href=&quot;/humans.txt&quot;&gt;</code> to the <code>&lt;head&gt;</code>.</li>
</ol>
<p><strong>Read more:</strong> <a href="https://humanstxt.org/Standard.html">humans.txt: Quick start</a></p>
<h2>Automation</h2>
<p>I want to keep the section <code>/* THANKS */</code> with the list of all contributors actual. So I’ve added some automation to update the list on every local build:</p>
<ol>
<li>Get data from <code>git shortlog -sne</code>. <code>s</code> is for summary only, <code>e</code> is for contributors emails, <code>n</code> is for the number of commits.</li>
<li>Remove contributors with my emails from the list.</li>
<li>Save the list to data file.</li>
<li>Put the list to <code>humans.txt</code> on every build.</li>
</ol>
<p><a href="https://github.com/MeFoDy/mefody.dev/blob/main/gulpfile.js">Source code</a>.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://humanstxt.org/">Humans TXT: We Are People, Not Machines.</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/humans-txt/</guid></item><item><title>Git Hooks: share with your team</title><link>https://mefody.dev/chunks/git-hooks-share/</link><pubDate>Sun, 15 Aug 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>In my previous <a href="https://mefody.dev/chunks/git-hooks-share/chunks/git-hooks/">chunk</a> I showed the way to make development in your repo more productive. But there was a good question unsolved: “How to share git hooks with your team?” By default, all your <code>.git</code> files are local — they are not for being pushed. So how can I make my automation from <code>.git/hooks</code> public?</p>
<h2>README.md</h2>
<p>You can add a chapter to the <code>README.md</code> file with instructions on setting up git hooks locally. With links to gists or something like that. But this way is not the true way.</p>
<h2>npm prepare</h2>
<p>There is a way to add some automation to your package after <code>npm install</code> run. Npm has useful <a href="https://docs.npmjs.com/cli/v7/using-npm/scripts">lifecycle scripts</a> that can help you. The <code>prepare</code> script looks really suitable for our task to install git hooks on a local machine.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"prepare"</span><span class="token operator">:</span> <span class="token string">"bash ./copy-hooks.sh"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>But you still need to write your <code>copy-hooks.sh</code> script. Not a good way for frontend beginners.</p>
<h2>Separate folder</h2>
<p>To make git hooks a part of a repository, you can just move them to a separate folder. For example, to <code>.githooks</code> or <code>.config/githooks</code>. But you still need to have some steps that will make these hooks executable.</p>
<p>Git can help you with it. Command <code>git config core.hooksPath .config/githooks</code> tells your local git to use <code>.config/githooks</code> as a folder with hooks. Pretty simple.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"prepare"</span><span class="token operator">:</span> <span class="token string">"git config core.hooksPath .config/githooks"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span></code></pre>
<p>Konstantinos Leimonis <a href="https://www.smashingmagazine.com/2019/12/git-hooks-team-development-workflow/">proposes</a> another trick with symlinks.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">find</span> .git/hooks <span class="token parameter variable">-type</span> l <span class="token parameter variable">-exec</span> <span class="token function">rm</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">\</span><span class="token punctuation">\</span><span class="token punctuation">;</span>
<span class="token function">find</span> .githooks <span class="token parameter variable">-type</span> f <span class="token parameter variable">-exec</span> <span class="token function">ln</span> <span class="token parameter variable">-sf</span> <span class="token punctuation">..</span>/<span class="token punctuation">..</span>/<span class="token punctuation">{</span><span class="token punctuation">}</span> .git/hooks/ <span class="token punctuation">\</span><span class="token punctuation">\</span><span class="token punctuation">;</span></code></pre>
<p>This code links scripts from <code>.githooks</code> folder to <code>.git/hooks/</code>. So when git tries to call some hook from its default directory it will execute the hook from your separate directory.</p>
<h2>Git hooks managers</h2>
<p>There is a lot of projects that can help you to avoid bash learning if you just want to use web technologies for development. My favorite tools are:</p>
<ul>
<li><a href="https://github.com/typicode/husky">husky</a> — hooks manager on steroids with a big community. It is lightweight and MIT licensed in the stable version. I use it in my work projects.</li>
<li><a href="https://github.com/toplenboren/simple-git-hooks">simple-git-hooks</a> — hooks manager for small-sized projects. I use it in my blog repo.</li>
</ul>
<p>With these managers, you don’t need to write any bash scripts, but you can. And their auto-installation is still simple. My <code>package.json</code> looks like this:</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"prepare"</span><span class="token operator">:</span> <span class="token string">"npx simple-git-hooks"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"simple-git-hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"pre-push"</span><span class="token operator">:</span> <span class="token string">"npm run lint"</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Honestly, you don’t need all this <code>prepare</code> stuff for <code>simple-git-hooks</code> because it uses its own <code>postinstall</code> script and makes all the automation by itself. Husky had such automation before, but they <a href="https://blog.typicode.com/husky-git-hooks-autoinstall/">decided</a> to change the behavior.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://docs.npmjs.com/cli/v7/using-npm/scripts">npm scripts</a></li>
<li><a href="https://www.smashingmagazine.com/2019/12/git-hooks-team-development-workflow/">How To Ease Your Team’s Development Workflow With Git Hooks</a></li>
<li><a href="https://typicode.github.io/husky/">Husky docs</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/git-hooks-share/</guid></item><item><title>Git Hooks: let the machine do all the routine</title><link>https://mefody.dev/chunks/git-hooks/</link><pubDate>Tue, 27 Jul 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>I wanna live in a world where every commit is a project state in which everything is fine: linters are green, dependencies are up-to-date, git history is clear, etc. Fortunately, I can configure my projects to use git hooks to help contributors to avoid mistakes.</p>
<h2>Git hooks basics</h2>
<p>Git hook is a snippet triggered when the git executes something. For example, if you have a strict rule <em>“No tabs for indentation”</em>, you can create a hook that checks all the changed files to satisfy the rule. Git will run this check and stop the action (push, commit), if the rule has been ignored by some impudent contributor.</p>
<p>There are many git actions you can interfere with:</p>
<ul>
<li><strong>pre-commit</strong></li>
<li>pre-merge-commit</li>
<li><strong>prepare-commit-msg</strong></li>
<li>commit-msg</li>
<li>post-commit</li>
<li>pre-rebase</li>
<li><strong>post-checkout</strong></li>
<li>post-merge</li>
<li><strong>pre-push</strong></li>
<li>etc.</li>
</ul>
<p>You can find more information about all existing git hooks <a href="https://git-scm.com/docs/githooks">here</a>.</p>
<p>To set up a hook, you should create an executable file in the <code>.git/hooks</code> directory named according to the spec.</p>
<p>Let’s create a simple hook that runs linters on every <code>git push</code>. It will help to keep the repo clean.</p>
<pre class="language-bash"><code class="language-bash"><span class="token builtin class-name">cd</span> .git/hooks <span class="token comment"># go to the hooks directory</span>
<span class="token function">vi</span> pre-push <span class="token comment"># create or edit the hook</span></code></pre>
<p>Paste the following code to the file.</p>
<pre class="language-bash"><code class="language-bash"><span class="token shebang important">#!/bin/sh</span>
<span class="token function">npm</span> run lint</code></pre>
<p>Pretty simple, right? This hook just runs a custom npm script from your <code>package.json</code>. You can use <a href="https://github.com/MeFoDy/mefody.dev/blob/main/package.json">my config</a> as an example.</p>
<p>Save, exit, commit, profit!</p>
<p><strong>Note:</strong> it’s important to make the hook file executable. The magic will not happen without it.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">chmod</span> +x pre-push <span class="token comment"># make the file executable</span></code></pre>
<h2>Useful git hooks</h2>
<p>If you know bash language a little, you can add many useful git hooks to your project.</p>
<p>Of course, you can use not only bash for your git hooks. It can be everything executable, like Python or even JS. But remember that bash is preinstalled and can be run on most environments, whereas other languages should be installed and configured before their usage. So I prefer bash.</p>
<p>Check these projects to have inspiration:</p>
<ul>
<li><a href="https://github.com/aitemr/awesome-git-hooks">aitemr / awesome-git-hooks</a></li>
<li><a href="https://github.com/compscilauren/awesome-git-hooks">compscilauren / awesome-git-hooks</a></li>
</ul>
<h3>Put the Task ID to commit messages</h3>
<p>If your team decided to use task ids from the task tracker (JIRA, Wrike, whatever else) in commit messages, create a <code>prepare-commit-msg</code> file in the <code>.git/hooks</code> directory and paste the following code there.</p>
<pre class="language-shell"><code class="language-shell"><span class="token shebang important">#!/bin/sh</span>

<span class="token comment"># .git/hooks/prepare-commit-msg</span>

<span class="token assign-left variable">COMMIT_MSG</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">cat</span> $1<span class="token variable">)</span></span>
<span class="token assign-left variable">CURRENT_BRANCH</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">git</span> rev-parse --abbrev-ref HEAD<span class="token variable">)</span></span>
<span class="token assign-left variable">TASK_ID_REGEX</span><span class="token operator">=</span><span class="token string">"[A-Z]+-[0-9]+"</span> <span class="token comment"># corresponds to JIRA-123 or SERP-666</span>
<span class="token assign-left variable">TASK_ID_FROM_CURRENT_BRANCH</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$CURRENT_BRANCH</span>"</span> <span class="token operator">|</span> <span class="token function">grep</span> <span class="token parameter variable">-Eo</span> <span class="token string">"<span class="token variable">$TASK_ID_REGEX</span>"</span><span class="token variable">)</span></span>

<span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token operator">!</span> <span class="token parameter variable">-z</span> <span class="token string">"<span class="token variable">$TASK_ID_FROM_CURRENT_BRANCH</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$TASK_ID_FROM_CURRENT_BRANCH</span>: <span class="token variable">$COMMIT_MSG</span>"</span> <span class="token operator">></span> <span class="token variable">$1</span>
<span class="token keyword">fi</span></code></pre>
<p>It parses your branch name, and if the name contains something looking like the task ID, the hook prepends this ID to the commit message. For example, if you have the branch named <code>AREA-51</code> and your commit message is <code>Find UFO</code>, the final commit message will be <code>AREA-51: Find UFO</code>.</p>
<p>You can make this hook much smarter like <a href="https://github.com/aitemr/awesome-git-hooks/blob/master/prepare-commit-msg/prepare-commit-msg-jira">here</a>.</p>
<h3>Get notified about new dependencies after checkout</h3>
<p>Paste the following code to the <code>.git/hooks/post-checkout</code>.</p>
<pre class="language-shell"><code class="language-shell"><span class="token shebang important">#!/bin/sh</span>

<span class="token comment"># .git/hooks/post-checkout</span>

<span class="token assign-left variable">PREV_COMMIT</span><span class="token operator">=</span><span class="token variable">$1</span>
<span class="token assign-left variable">POST_COMMIT</span><span class="token operator">=</span><span class="token variable">$2</span>

<span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token parameter variable">-f</span> package-lock.json <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    <span class="token keyword">if</span> <span class="token operator">!</span> <span class="token function">git</span> <span class="token function">diff</span> <span class="token parameter variable">--quiet</span> <span class="token variable">$PREV_COMMIT</span><span class="token punctuation">..</span><span class="token variable">$POST_COMMIT</span> -- package-lock.json<span class="token punctuation">;</span> <span class="token keyword">then</span>
        <span class="token builtin class-name">echo</span> <span class="token string">"'package-lock.json' has been changed. Please, run 'npm ci' to update dependencies."</span>
    <span class="token keyword">fi</span>
<span class="token keyword">fi</span></code></pre>
<p>You can make it more colourful and even let it running <code>npm ci</code> automatically like <a href="https://gist.github.com/lyrixx/5867424">here</a>. But I don’t like when my tools install something without my permission.</p>
<h3>Disable direct commits to the <code>main</code> branch</h3>
<p>It’s a common pattern to have no direct commits to the <code>main</code> branch. Let your CI do all the thing. Of course, you must configure your repository to avoid such situation, but it’s ok to add more confidence with an extra check on a git level.</p>
<p>Paste the following code to the <code>.git/hooks/pre-push</code>.</p>
<pre class="language-shell"><code class="language-shell"><span class="token shebang important">#!/bin/sh</span>

<span class="token comment"># .git/hooks/pre-push</span>

<span class="token assign-left variable">CURRENT_BRANCH</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">git</span> rev-parse --abbrev-ref HEAD<span class="token variable">)</span></span>

<span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token string">"<span class="token variable">$CURRENT_BRANCH</span>"</span> <span class="token operator">=</span> <span class="token string">"main"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span>
    <span class="token builtin class-name">echo</span> <span class="token string">"YOU SHALL NOT PASS!<span class="token entity" title="\n">\n</span>Dear <span class="token environment constant">$USER</span>, you don't want to commit directly to the 'main' branch ;)"</span>
    <span class="token builtin class-name">exit</span> <span class="token number">1</span>
<span class="token keyword">fi</span></code></pre>
<p><strong>Note:</strong> it’s important to keep <code>exit 1</code> in the code to stop the push.</p>
<p>I found a cool example of public alerting about the accident <a href="https://www.notion.so/e7682478b8927700c714f12e37f0837e">here</a>. But you should be sure all your teammates are ok with such sort of blaming.</p>
<h2><code>simple-git-hooks</code> with <code>lint-staged</code></h2>
<p>If your project is small and you don’t need complicated hooks with dozens of checks, try to use a lightweight library <a href="https://github.com/toplenboren/simple-git-hooks">simple-git-hooks</a>. It has some limitations but its possibilities are enough for my opensource projects.</p>
<p>I use the next flow:</p>
<ol>
<li>Run linters on staged files before commit and fix the files automatically if it’s possible.</li>
<li>Run linters on all files before push.</li>
</ol>
<p>To work with staged changes only I use another useful library <a href="https://github.com/okonet/lint-staged">lint-staged</a>.</p>
<p>Let’s configure the project to implement the flow. Firstly, install the packages.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> --save-dev simple-git-hooks lint-staged</code></pre>
<p>Then add a configuration to your <code>package.json</code>.</p>
<pre class="language-json"><code class="language-json"><span class="token punctuation">{</span>
    <span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"lint"</span><span class="token operator">:</span> <span class="token string">"npm run lint:editorconfig &amp;&amp; npm run lint:css &amp;&amp; npm run lint:js"</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"lint-staged"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"*"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token string">"editorconfig-checker"</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"*.js"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token string">"eslint --fix"</span>
        <span class="token punctuation">]</span><span class="token punctuation">,</span>
        <span class="token property">"*.css"</span><span class="token operator">:</span> <span class="token punctuation">[</span>
            <span class="token string">"stylelint --fix"</span>
        <span class="token punctuation">]</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span>
    <span class="token property">"simple-git-hooks"</span><span class="token operator">:</span> <span class="token punctuation">{</span>
        <span class="token property">"pre-commit"</span><span class="token operator">:</span> <span class="token string">"npx lint-staged"</span><span class="token punctuation">,</span>
        <span class="token property">"pre-push"</span><span class="token operator">:</span> <span class="token string">"npm run lint"</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>As you can see, I use editorconfig to check all the files and separate linters for JS and CSS files. So when I commit, <code>simple-git-hooks</code> calls the <code>lint-staged</code>, and <code>lint-staged</code> does all the magic connected to fixing the staged files.</p>
<p>When I try to push my local changes to the remote repo, <code>simple-git-hooks</code> starts linters with <code>npm run lint</code>, and if the linters fail, the push will be stopped until I fix all the errors.</p>
<p>To apply the config, run the following command.</p>
<pre class="language-bash"><code class="language-bash">npx simple-git-hooks</code></pre>
<p><strong>More:</strong> <a href="https://mefody.dev/chunks/git-hooks/chunks/git-hooks-share/">Git Hooks: share with your team</a></p>
<h2>Conclusion</h2>
<p>It’s easier to have clean code in your repo when you have git hooks configured. Add clear warning messages with helpful tips, links, and instructions to help other people contribute to your project. And don’t waste your time fixing the accidents instead of preventing them.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://git-scm.com/docs/githooks">Git Hooks documentation</a></li>
<li><a href="https://www.atlassian.com/git/tutorials/git-hooks">Bitbucket: Git Hooks tutorial</a></li>
<li><a href="https://githooks.com/">Git Hooks</a></li>
<li><a href="https://codeinthehole.com/tips/tips-for-using-a-git-pre-commit-hook/">Tips for using a git pre-commit hook</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/git-hooks/</guid></item><item><title>Change the form control color with accent-color property</title><link>https://mefody.dev/chunks/accent-color/</link><pubDate>Fri, 02 Jul 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Do you like default colors used by form controls such as radio buttons, checkboxes, or sliders? I mean, they are the same on every website. These colors have become more modern after <a href="https://blogs.windows.com/msedgedev/2019/10/15/form-controls-microsoft-edge-chromium/">Microsoft commitment</a> to redesign form controls in Chromium, but they are still the same on every website.</p>
<p>
    <input type="checkbox" checked>
    <input type="radio" checked>
    <input type="range">
</p>
<p>When we want to change these default colors, we have to use some of 1001 ways to create custom-styled form controls with all their bugs coming.</p>
<p>Imagine if you could change the color of checkboxes to match the theme color of your site…</p>
<p>If your heart is beating faster after the words above, what do you think about the <code>accent-color</code> CSS property?</p>
<h2><code>accent-color</code></h2>
<p>Last year, I found an interesting issue in the CSSWG drafts titled <a href="https://github.com/w3c/csswg-drafts/issues/5187">‘Allow specifying the “accent color” of a form control element’</a>.</p>
<p>Adam Argyle made me dream about this feature again this February after <a href="https://twitter.com/argyleink/status/1360022120810483715">his tweet</a>:</p>
<blockquote>
<p><code>accent-color: hotpink;</code> 🎉
Chromium is prototyping the style feature for forms! I couldn’t wait, so I went and tried it out in a custom build. Here it is!
hotpink checkboxes with 1 line of CSS 😎</p>
</blockquote>
<p><em>Disclaimer: it still doesn’t work, don’t try to use it at home. Or maybe you can use it as a progressive enhancement?</em></p>
<p>So what does the spec say? Let’s visit the <a href="https://drafts.csswg.org/css-ui-4/#widget-accent">CSS Basic User Interface Module Level 4</a>.</p>
<blockquote>
<p>The accent-color CSS property allows the author to specify the accent color for user-interface controls generated by the element.</p>
</blockquote>
<blockquote>
<p>The UA should use the specified accent-color to draw whichever parts of the element’s control(s) would have otherwise been styled with an accent color.</p>
</blockquote>
<p>Sounds interesting. If my website has some theme colors, can I use them to make all the form controls more… design integrated? Without hacks and bugs.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">:root</span> <span class="token punctuation">{</span>
    <span class="token property">--color-accent</span><span class="token punctuation">:</span> #ffcc00<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@media</span> <span class="token punctuation">(</span><span class="token property">prefers-color-scheme</span><span class="token punctuation">:</span> dark<span class="token punctuation">)</span></span> <span class="token punctuation">{</span>
    <span class="token selector">:root</span> <span class="token punctuation">{</span>
        <span class="token property">--color-accent</span><span class="token punctuation">:</span> #880088<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token selector">body</span> <span class="token punctuation">{</span>
    <span class="token property">accent-color</span><span class="token punctuation">:</span> <span class="token function">var</span><span class="token punctuation">(</span>--color-accent<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Just one line of CSS!</p>
<p>If you see not defaultish form controls below, then the future has arrived, and your browser supports <code>accent-color</code> right now.</p>
<p style="accent-color: var(--color-accent);">
    <input type="checkbox" checked>
    <input type="radio" checked>
    <input type="range">
</p>
<figure >
    <img src="https://mefody.dev/chunks/accent-color/images/caniuse-accent-color.png" alt="Status of accent-color property on Caniuse." loading="lazy" decoding="async">
    <figcaption>
        In my century, Caniuse knows nothing about `accent-color`.
    </figcaption>
</figure>
<h2>Early demos</h2>
<p>During the last GDE meeting <a href="https://twitter.com/JosephArhar">Joey Arhar</a> showed us a really curious demo of his implementation of the <code>accent-color</code> property in Chrome: <a href="https://accent-color.glitch.me/">https://accent-color.glitch.me/</a>.</p>
<p>If you see all of the form controls on the page blue, it’s ok. To see the rainbow, you need a Canary version of Chrome with “Experimental Web Platform features” enabled:</p>
<ol>
<li>Go to <code>chrome://flags/</code>.</li>
<li>Enable “Experimental Web Platform features”.</li>
<li>Restart the browser.</li>
<li>Ta-da!</li>
</ol>
<p>With Firefox Nightly, you can do the same:</p>
<ol>
<li>Go to <code>about:config</code>.</li>
<li>Enable “browser.preferences.experimental”.</li>
<li>Restart the browser.</li>
<li>Ta-da!</li>
</ol>
<p>If you did everything right, you might see something like this.</p>
<figure >
    <img src="https://mefody.dev/chunks/accent-color/images/the-rainbow.jpg" alt="Colored checkboxes." loading="lazy" decoding="async">
    <figcaption>
        Cool, isn't it?
    </figcaption>
</figure>
<h2>PWA</h2>
<p>If you’ve already made your web application installable (PWA), you can set the theme color of its standalone version.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>theme-color<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#ffcc00<span class="token punctuation">"</span></span><span class="token punctuation">></span></span></code></pre>
<p>In the new <a href="https://developer.apple.com/documentation/safari-release-notes/safari-15-beta-release-notes#HTML">Safari 15</a> this tiny snippet will make your website look trendy on macOS too.</p>
<p>But the next step will be full coloring of your PWA.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>theme-color<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>#ffcc00<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">></span></span><span class="token style"><span class="token language-css">
    <span class="token selector">body</span> <span class="token punctuation">{</span> <span class="token property">accent-color</span><span class="token punctuation">:</span> #ffcc00<span class="token punctuation">;</span> <span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">></span></span></code></pre>
<h2>Browser support</h2>
<p>The <code>accent-color</code> is now supported under experimental flags in Firefox and Chrome. You can watch the statuses in bug trackers:</p>
<ul>
<li><a href="https://chromestatus.com/feature/4752739957473280">Chrome Platform Status</a></li>
<li><a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1705605">Firefox Bugzilla</a></li>
<li><a href="https://bugs.webkit.org/show_bug.cgi?id=227587">WebKit Bugzilla</a></li>
</ul>
<p>It still has some bugs and difficulties that need to be solved. You can set the color you want, but the user agent must keep the form control accessible. So it’s still in beta. But you can help browsers test the early implementations of the feature and share your feedback in bug trackers.</p>
]]></description><guid>https://mefody.dev/chunks/accent-color/</guid></item><item><title>Link to download</title><link>https://mefody.dev/chunks/download-link/</link><pubDate>Thu, 17 Jun 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Sometimes I need to create a link that should show a system dialog to save the file. Browsers are pretty smart to open that dialog for some binaries, e.g. for archives or <code>*.exe</code>. But what if I want to download an image or some video?</p>
<h2><code>Content-Disposition</code> header</h2>
<p>The most valid way is to add a <code>Content-Disposition</code> header on the server.</p>
<pre class="language-html"><code class="language-html">Content-Disposition: attachment; filename=kitten.jpg</code></pre>
<p>When your browser finds the <code>attachment</code> value, it starts to download the file, not to show it.</p>
<p>But sometimes you can’t change any server configs, so we need a more browserish way to solve the problem.</p>
<h2><code>download</code> attribute</h2>
<p>The easiest way to do this is to add the <code>download</code> attribute to your link.</p>
<p>If you just add it without any value, your browser will try to get the name of the file from its <code>Content-Disposition</code> header (yeah, it has high priority) or its path.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images/kitten.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">download</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>img</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images/kitten-preview.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">alt</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Kitten photo preview<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Try it: <a href="https://mefody.dev/chunks/download-link/demo/kitten-pixel.jpg" download>demo link</a>.</p>
<p>You can set some value to <code>download</code> if you want to change the default name. It can help when you have some strange auto-generated URL like <code>https://cdn/images/a1H5-st42-Av1f-rUles</code>.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>images/1h24v9lj.jpg<span class="token punctuation">"</span></span> <span class="token attr-name">download</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>kitten<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    Download
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Try it: <a href="https://mefody.dev/chunks/download-link/demo/kitten-pixel.jpg" download="i-am-tiny">demo link</a>.</p>
<p><strong>Important!</strong> All this attribute magic <a href="https://www.chromestatus.com/feature/4969697975992320">is not for cross-origin links</a>. You can’t control the stuff from cross-origin sources due to security issues.</p>
<p>And remember that IE and old Safari are unaware of <code>download</code>. <a href="https://caniuse.com/download">Check it</a>.</p>
<h2><code>blob:</code> and <code>data:</code></h2>
<p>Another lifehack to help your users save pictures of kittens in a format convenient for them. If you use AVIF or WebP images on your site, it is a huge chance that no one will be able to save them on their computer or phone to view them later. More precisely, they can save the image, but they can’t view it. Very sad.</p>
<p>To help them, use <code>data:</code> or <code>blob:</code> URLs inside the <code>href</code> attribute.</p>
<p><strong>Step 1.</strong> Draw the image on a canvas.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> canvas <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'canvas'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> ctx <span class="token operator">=</span> canvas<span class="token punctuation">.</span><span class="token function">getContext</span><span class="token punctuation">(</span><span class="token string">'2d'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> image <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Image</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
image<span class="token punctuation">.</span><span class="token function-variable function">onload</span> <span class="token operator">=</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    ctx<span class="token punctuation">.</span><span class="token function">drawImage</span><span class="token punctuation">(</span>image<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// TODO: put the magic here</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
image<span class="token punctuation">.</span>src <span class="token operator">=</span> <span class="token string">'kitten-170.avif'</span><span class="token punctuation">;</span></code></pre>
<p><strong>Step 2a.</strong> Save the image as a blob to the link <code>href</code>.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> blobLink <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'blob-link'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

canvas<span class="token punctuation">.</span><span class="token function">toBlob</span><span class="token punctuation">(</span><span class="token parameter">blob</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> blobUrl <span class="token operator">=</span> <span class="token constant">URL</span><span class="token punctuation">.</span><span class="token function">createObjectURL</span><span class="token punctuation">(</span>blob<span class="token punctuation">)</span><span class="token punctuation">;</span>
    blobLink<span class="token punctuation">.</span>href <span class="token operator">=</span> blobUrl<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'image/jpeg'</span><span class="token punctuation">,</span> <span class="token number">0.9</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Yes, I can save AVIF as JPEG. Cool, right? The user downloaded just 4 KB AVIF from a server and got his 13 KB JPEG on a client!</p>
<p><strong>Step 2b.</strong> Save the image as a data to the link <code>href</code>.</p>
<p>Some browsers can’t use blobs, so you can help them with data-urls.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> dataLink <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'data-link'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

dataLink<span class="token punctuation">.</span>href <span class="token operator">=</span> canvas<span class="token punctuation">.</span><span class="token function">toDataURL</span><span class="token punctuation">(</span><span class="token string">'image/jpeg'</span><span class="token punctuation">,</span> <span class="token number">0.9</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>It’s even easier, but not so performant.</p>
<p>You can play with the full demo here:</p>
<ul>
<li><a href="https://mefody.dev/chunks/download-link/demo/index.html">Demo</a></li>
<li><a href="https://github.com/MeFoDy/mefody.dev/blob/main/src/chunks/download-link/demo/index.html">Source code</a></li>
</ul>
<h2>Sources</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/MIME#Content-Disposition">Wiki: Content-Disposition</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/A">MDN: A</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL">MDN: canvas.toDataURL</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob">MDN: canvas.toBlob</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/download-link/</guid></item><item><title>Set the width of the tab character</title><link>https://mefody.dev/chunks/tab-size/</link><pubDate>Wed, 26 May 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>In our <a href="https://web-standards.ru/podcast/">Web Standards</a> podcast, we often discuss new features and changes from the latest browsers’ release notes. Imagine my impressions when I found the next text in <a href="https://webkit.org/blog/11672/release-notes-for-safari-technology-preview-124/">Release Notes for Safari Technology Preview 124</a>.</p>
<blockquote>
<p>Supported animation of the <code>tab-size</code> CSS property (<a href="https://trac.webkit.org/changeset/274939/webkit/">r274939</a>)</p>
</blockquote>
<p>The first one: <em>“WAT? We had <code>tab-size</code> property all this time?”</em></p>
<p>The second one: <em>“WAAAAAT? It can even be animated?”</em></p>
<h2><kbd>tab</kbd> vs <kbd>space</kbd></h2>
<p>At the beginning of time, an endless war began. What should I use to indent my code? One character that costs 1 byte to store, or 4 characters that cost 4 bytes? If you have 1KB of memory on your storage device, it’s pretty critical.</p>
<p>Today we have a <a href="https://almanac.httparchive.org/en/2020/page-weight#page-weight">2MB median page</a> on the web, so who cares? Code minification, gzip, and IDE settings are your best friends to avoid the holy war. For example, I use <a href="https://editorconfig.org/">EditorConfig</a> for all my projects. Just to be sure I and my collegues use the same code style.</p>
<p>But what if I prefer tabs and want to show some code snippet to somebody who prefers spaces? How can I help him or her to save the peace of mind?</p>
<h2>tab-size</h2>
<p>Let’s make a demo. I want to share the snippet that shows how to use a <code>tab-size</code> property.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">pre</span> <span class="token punctuation">{</span>
	<span class="token property">tab-size</span><span class="token punctuation">:</span> 4<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>You can’t see it by default but I use a <code>\t</code> character to make an indentation. And because of the default styles of <a href="https://prismjs.com/">Prism</a> code highlighter attached to my blog, it looks the same as the next snippet with 4 spaces to indent.</p>
<pre class="language-css"><code class="language-css"><span class="token selector">pre</span> <span class="token punctuation">{</span>
    <span class="token property">tab-size</span><span class="token punctuation">:</span> 4<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Let’s change the value.</p>
<style id="demo-0">
    #demo-0 + pre[class*='language-'] > code[class*='language-'] { -moz-tab-size: 8; tab-size: 8; }
</style>
<pre class="language-css"><code class="language-css"><span class="token selector">pre</span> <span class="token punctuation">{</span>
    <span class="token property">tab-size</span><span class="token punctuation">:</span> 8<span class="token punctuation">;</span>
	<span class="token property">color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>Now you can see the difference when your colleague has made a commit with <code>--no-verify</code>, oh, little villain.</p>
<p>So, the <code>tab-size: 4</code> in CSS says <em>“I want to make a tab character width equal to 4 space characters width”</em>. And it works!</p>
<p>But I can make this width not relative but absolute.</p>
<style id="demo-1">
    #demo-1 + pre[class*='language-'] > code[class*='language-'] { -moz-tab-size: 1em; tab-size: 1em; }
</style>
<pre class="language-css"><code class="language-css"><span class="token selector">pre</span> <span class="token punctuation">{</span>
	<span class="token property">tab-size</span><span class="token punctuation">:</span> 1em<span class="token punctuation">;</span>
<span class="token punctuation">}</span></code></pre>
<p>If you read this article in Safari 13-, sorry — you won’t see the difference. But for other browsers, you can set the width of <code>\t</code> to absolute units like <code>px</code>, <code>em</code>, etc.</p>
<p>And yeah, it can be animated.</p>
<style id="demo-2">
    #demo-2 + pre[class*='language-'] > code[class*='language-'] {
        -moz-tab-size: 4;
        tab-size: 4;
        animation: tab 3s ease-in-out infinite alternate;
    }

    @keyframes tab {
        from { -moz-tab-size: 1; tab-size: 1; }
        to { -moz-tab-size: 8; tab-size: 8; }
    }
</style>
<pre class="language-css"><code class="language-css"><span class="token selector">pre</span> <span class="token punctuation">{</span>
	<span class="token property">tab-size</span><span class="token punctuation">:</span> 4<span class="token punctuation">;</span>
	<span class="token property">animation</span><span class="token punctuation">:</span> tab 3s ease-in-out infinite alternate<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token atrule"><span class="token rule">@keyframes</span> tab</span> <span class="token punctuation">{</span>
	<span class="token selector">from</span> <span class="token punctuation">{</span> <span class="token property">tab-size</span><span class="token punctuation">:</span> 1<span class="token punctuation">;</span> <span class="token punctuation">}</span>
	<span class="token selector">to</span> <span class="token punctuation">{</span> <span class="token property">tab-size</span><span class="token punctuation">:</span> 8<span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>Pretty useless, but fun!</p>
<p>Don’t forget about vendor prefixes, <code>tab-size</code> still requires a <code>-moz-</code> prefix in Firefox. Add your vote <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=737785">here</a> to increase the bug weight.</p>
<p>IE? No.</p>
<h2>Sources</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/tab-size">MDN: tab-size</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/tab-size/</guid></item><item><title>Work with cookies the modern way</title><link>https://mefody.dev/chunks/cookie-store-api/</link><pubDate>Sat, 01 May 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Have you ever worked with cookies? Did you find working with them obvious? I think it has a lot of nuances for newbies.</p>
<h2>document.cookie</h2>
<p>Let’s take a look at the classic way to work with cookies. We’ve had cookies in the specification since 1994, <a href="https://curl.se/rfc/cookie_spec.html">thanks to Netscape</a>. Netscape implemented <code>document.cookie</code> <a href="https://www.erikoest.dk/cookies.htm">in 1996</a> in their Netscape Navigator. Look at this definition of a cookie from those days.</p>
<blockquote>
<p>A cookie is a small piece of information stored on the client machine in the <code>cookies.txt</code> file.</p>
</blockquote>
<p>You can even find the chapter about <code>document.cookie</code> in the <a href="https://www.cs.ait.ac.th/~on/O/oreilly/web/jscript/refp_79.htm">“Javascript. The Definitive Guide. Second Edition, January 1997”</a>. 24 years ago. And we are still using that old way to work with cookies because of backward compatibility.</p>
<p>So, what’s the way?</p>
<h3>Get cookies</h3>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> cookies <span class="token operator">=</span> document<span class="token punctuation">.</span>cookie<span class="token punctuation">;</span>
<span class="token comment">// returns "_octo=GH1.1.123.456; tz=Europe%2FMinsk" on GitHub</span></code></pre>
<p>Yeah, that’s it. It returns a string with all cookies separated by <code>;</code>.</p>
<p>How to get a single cookie value? Right, split the string manually.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">function</span> <span class="token function">getCookieValue</span><span class="token punctuation">(</span><span class="token parameter">name</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> cookies <span class="token operator">=</span> document<span class="token punctuation">.</span>cookie<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">';'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">const</span> res <span class="token operator">=</span> cookies<span class="token punctuation">.</span><span class="token function">find</span><span class="token punctuation">(</span><span class="token parameter">c</span> <span class="token operator">=></span> c<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span>name <span class="token operator">+</span> <span class="token string">'='</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span><span class="token function">indexOf</span><span class="token punctuation">(</span><span class="token string">'='</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span></code></pre>
<p>How to get some cookie expiration date? No way.</p>
<p>How to get some cookie domain? No way.</p>
<p>You can parse the HTTP <code>Cookie</code> header if you want.</p>
<h3>Set cookies</h3>
<pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> <span class="token string">'theme=dark'</span><span class="token punctuation">;</span></code></pre>
<p>It creates the cookie named <code>theme</code> with the value equals <code>dark</code>. Ok, does it mean that <code>document.cookie</code> is a string? Nope. It’s a setter.</p>
<pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> <span class="token string">'mozilla=netscape'</span><span class="token punctuation">;</span></code></pre>
<p>It doesn’t rewrite the old cookie named <code>theme</code>, it creates the new one named <code>mozilla</code>. Now you have two cookies.</p>
<p>By default, a created cookie expires when the browser is closed. You can set the expiration date.</p>
<pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> <span class="token string">'browser=ie11; expires=Tue, 17 Aug 2021 00:00:00 GMT'</span><span class="token punctuation">;</span></code></pre>
<p>Yeah, right, that’s what I want, calculate the expiration date in GMT format every time I want to set a cookie. Ok, let’s write some more JavaScript.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> date <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
date<span class="token punctuation">.</span><span class="token function">setTime</span><span class="token punctuation">(</span>date<span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span><span class="token number">30</span> <span class="token operator">*</span> <span class="token number">24</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// love it</span>
document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">login=mefody; expires=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>date<span class="token punctuation">.</span><span class="token function">toUTCString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">; path=/</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span></code></pre>
<p>Fortunately, we have another option to set the cookie expiration.</p>
<pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> <span class="token string">'element=caesium; max-age=952001689'</span><span class="token punctuation">;</span></code></pre>
<p>The <code>max-age</code> part is a lifetime of a cookie in seconds and it has more priority than the <code>expires</code> part.</p>
<p>Don’t forget about <code>path</code> and <code>domain</code>. By default, the cookie is set for the current location and the current host. If you need to set the cookie for the entire domain, add <code>; path=/; domain=example.com</code>.</p>
<h3>Delete cookies</h3>
<pre class="language-js"><code class="language-js">document<span class="token punctuation">.</span>cookie <span class="token operator">=</span> <span class="token string">'login=; expires=Thu, 01 Jan 1970 00:00:00 GMT'</span><span class="token punctuation">;</span></code></pre>
<p>To delete the cookie you should set its expiration date to some past date. To be sure that it will be deleted, use the Unix epoch start.</p>
<h3>Service Workers</h3>
<p>No. Just no. Working with <code>document.cookie</code> is a synchronous operation, so you can’t use it in service workers.</p>
<h2>Cookie Store API</h2>
<p>There is a draft of an awesome API that can help us to avoid a lot of pain in the future. It’s <a href="https://wicg.github.io/cookie-store/">Cookie Store API</a>.</p>
<p>Firstly, it’s an async API. It means you can use it without blocking the main thread. And service workers can use them too.</p>
<p>Secondly, it’s more clear for understanding.</p>
<h3>Get cookies</h3>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> cookies <span class="token operator">=</span> <span class="token keyword">await</span> cookieStore<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> sessionCookies <span class="token operator">=</span> <span class="token keyword">await</span> cookieStore<span class="token punctuation">.</span><span class="token function">getAll</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'session_'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">matchType</span><span class="token operator">:</span> <span class="token string">'starts-with'</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>The method <code>getAll</code> returns an array, not a string. That’s what I expect when I try to get a list of something.</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> ga <span class="token operator">=</span> <span class="token keyword">await</span> cookieStore<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'_ga'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">/**
{
    "domain": "mozilla.org",
    "expires": 1682945254000,
    "name": "_ga",
    "path": "/",
    "sameSite": "lax",
    "secure": false,
    "value": "GA1.2.891784426.1616320570"
}
*/</span></code></pre>
<p>Whoa! I can get the expiration date, domain and path info without hacks!</p>
<h3>Set cookies</h3>
<pre class="language-js"><code class="language-js"><span class="token keyword">await</span> cookieStore<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">'name'</span><span class="token punctuation">,</span> <span class="token string">'value'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>or</p>
<pre class="language-js"><code class="language-js"><span class="token keyword">await</span> cookieStore<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'name'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">value</span><span class="token operator">:</span> <span class="token string">'value'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">expires</span><span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">86400</span><span class="token punctuation">,</span>
    <span class="token literal-property property">domain</span><span class="token operator">:</span> self<span class="token punctuation">.</span>location<span class="token punctuation">.</span>host<span class="token punctuation">,</span>
    <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">'/'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">secure</span><span class="token operator">:</span> self<span class="token punctuation">.</span>location<span class="token punctuation">.</span>protocol <span class="token operator">===</span> <span class="token string">'https:'</span><span class="token punctuation">,</span>
    <span class="token literal-property property">httpOnly</span><span class="token operator">:</span> <span class="token boolean">false</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Love this syntax!</p>
<h3>Delete cookies</h3>
<pre class="language-js"><code class="language-js"><span class="token keyword">await</span> cookieStore<span class="token punctuation">.</span><span class="token function">delete</span><span class="token punctuation">(</span><span class="token string">'ie6'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Or you can set the expiration date to the past date if you want, but what for?</p>
<h3>Cookie events</h3>
<pre class="language-js"><code class="language-js">cookieStore<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'change'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">const</span> cookie <span class="token keyword">in</span> event<span class="token punctuation">.</span>changed<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">Cookie </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cookie<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> changed to </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>cookie<span class="token punctuation">.</span>value<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<p>Yeah, you will have a possibility to subscribe to cookies changes without thread blocking polling. Fantastic!</p>
<h3>Service Workers</h3>
<pre class="language-js"><code class="language-js"><span class="token comment">// service-worker.js</span>

<span class="token keyword">await</span> self<span class="token punctuation">.</span>registration<span class="token punctuation">.</span>cookies<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">[</span>
    <span class="token punctuation">{</span>
        <span class="token literal-property property">name</span><span class="token operator">:</span> <span class="token string">'cookie-name'</span><span class="token punctuation">,</span>
        <span class="token literal-property property">url</span><span class="token operator">:</span> <span class="token string">'/path-to-track'</span><span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

self<span class="token punctuation">.</span><span class="token function">addEventListener</span><span class="token punctuation">(</span><span class="token string">'cookiechange'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    <span class="token comment">// process the changes</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
<h2>Can I use it right now?</h2>
<p>Be careful, but <a href="https://caniuse.com/cookie-store-api">you can</a>. The Cookie Store API works in Chrome 87+ (Edge 87+, Opera 73+). For other browsers, you can use <a href="https://www.npmjs.com/package/cookie-store">the polyfill</a> that doesn’t return the full cookie info as an original API. Progressive enhancement is the thing.</p>
<p>Keep in mind that this API specification is still in “Draft Community Group Report” status. But if your DX is an important thing for the project, try the modern way.</p>
<h2>Sources</h2>
<ul>
<li><a href="https://www.erikoest.dk/cookies.htm">Netscape cookies</a></li>
<li><a href="https://wicg.github.io/cookie-store/">Cookie Store API Spec</a></li>
<li><a href="https://wicg.github.io/cookie-store/explainer.html">Cookie Store API Explainer</a></li>
<li><a href="https://www.chromestatus.com/feature/5658847691669504">Chrome Status: Cookie Store API</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Cookie_Store_API">MDN: Cookie Store API</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/cookie-store-api/</guid></item><item><title>How to copy part of a long link text</title><link>https://mefody.dev/chunks/copy-part-of-link/</link><pubDate>Thu, 08 Apr 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>Have you ever wanted to select and copy some part of a long link text? Not the full text, just a specific part in the middle.</p>
<figure >
    <video width="1000" height="640" controls muted loop playsinline preload="metadata">
    <source src="https://mefody.dev/chunks/copy-part-of-link/images/select-fail@1000.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
    <source src="https://mefody.dev/chunks/copy-part-of-link/images/select-fail@1000.h264.mp4" type="video/mp4">
</video>
    <figcaption>
        It’s a real pain.
    </figcaption>
</figure>
<p>Did you know that you can hold an <kbd>Alt</kbd> (<kbd>⌥</kbd> for macOS) to make you happy with it?</p>
<figure >
    <video width="1000" height="640" controls muted loop playsinline preload="metadata">
    <source src="https://mefody.dev/chunks/copy-part-of-link/images/select-success@1000.av1.mp4" type="video/mp4; codecs=av01.0.05M.08">
    <source src="https://mefody.dev/chunks/copy-part-of-link/images/select-success@1000.h264.mp4" type="video/mp4">
</video>
    <figcaption>
        Just hold an <kbd>Alt / ⌥</kbd> and select the needed part of a link text.
    </figcaption>
</figure>
<p>Works in Chrome (Edge, Opera, Yandex Browser) and Firefox.</p>
]]></description><guid>https://mefody.dev/chunks/copy-part-of-link/</guid></item><item><title>Social media buttons without JavaScript</title><link>https://mefody.dev/chunks/social-sharing-html-only/</link><pubDate>Mon, 05 Apr 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>You don’t need JavaScript to add social media buttons to your website. But I see JavaScript-based social buttons on websites every day. And these buttons are not about privacy. Let’s see how to create such buttons using <code>&lt;a href=&quot;...&quot;&gt;</code>.</p>
<h2>Twitter</h2>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://twitter.com/intent/tweet?text=Awesome+article&amp;url=https%3A%2F%2Fmefody.dev&amp;hashtags=html,css&amp;via=dev_tip<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    Share on Twitter
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Parameters:</p>
<ul>
<li><code>text</code> — tweet text. It should be URL-encoded. I prefer to use <code>+</code> for spaces.</li>
<li><code>url</code> — the page URL. Should be URL-encoded too.</li>
<li><code>hashtags</code> — obviously. Separated by comma.</li>
<li><code>via</code> — your twitter username without <code>@</code>.</li>
</ul>
<p>The complete text of the tweet will be <code>Awesome article https://mefody.dev #html #css via @dev_tip</code>.</p>
<p><a href="https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/guides/web-intent">Documentation: Tweet button</a></p>
<h2>Facebook</h2>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.facebook.com/sharer.php?u=https://mefody.dev<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    Share on Facebook
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Parameters:</p>
<ul>
<li><code>u</code> — the page URL.</li>
</ul>
<p>Unfortunately, the Facebook sharer no longer supports any customization. If you need custom text, try to use Dialog for that:</p>
<pre class="language-html"><code class="language-html">https://www.facebook.com/dialog/share?app_id=42&amp;display=popup&amp;href=https%3A%2F%2Fmefody.dev</code></pre>
<p>But this way requires <code>app_id</code>, so you have to register your Facebook app. Not very friendly.</p>
<p><a href="https://developers.facebook.com/docs/sharing/reference/share-dialog">Documentation: Facebook Share</a></p>
<h2>VK</h2>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://vk.com/share.php?url=https://mefody.dev<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    Share in VK
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Parameters:</p>
<ul>
<li><code>url</code> — the page URL.</li>
</ul>
<p><a href="https://vk.com/dev/widget_share">Documentation: VK Link Posting</a></p>
<h2>LinkedIn</h2>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmefody.dev<span class="token punctuation">"</span></span> <span class="token attr-name">target</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>_blank<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    Share in LinkedIn
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>a</span><span class="token punctuation">></span></span></code></pre>
<p>Parameters:</p>
<ul>
<li><code>url</code> — the page URL.</li>
</ul>
<p><a href="https://docs.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/plugins/share-plugin">Documentation: Share Plugin</a></p>
<h2>Attributes</h2>
<p>I also add these attributes to my share links:</p>
<ul>
<li><code>target=&quot;_blank&quot;</code> to open the link in a new window.</li>
<li><code>rel=&quot;noopener&quot;</code> to reset <code>window.opener</code>.</li>
</ul>
]]></description><guid>https://mefody.dev/chunks/social-sharing-html-only/</guid></item><item><title>GitHub from CLI</title><link>https://mefody.dev/chunks/github-cli/</link><pubDate>Wed, 31 Mar 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>I love open source. GitHub has a really great UI for managing open source projects in a browser. But what if I want to manage a project right in my terminal?</p>
<p>I have been using the GitHub CLI for half a year and it has boosted my productivity a lot. Let’s talk about typical cases.</p>
<p>To get started with the GitHub CLI, you need the <code>gh</code> package to be installed. Use <code>brew install gh</code> or check <a href="https://github.com/cli/cli#installation">the official installation guide</a>.</p>
<h2>Issues</h2>
<p>Imagine a situation when you forked some project to make it better. Suddenly, you encounter a bug that is not related to the changes you made. What should you do to fix it? Open a browser, find a repo, open issues, create a new one, fill it with details…</p>
<p>Or you can enter a simple command into the terminal.</p>
<pre class="language-bash"><code class="language-bash">gh issue create <span class="token comment"># will ask you for the title and body</span></code></pre>
<p>If you prefer Web UI, add <code>--web</code> as an option.</p>
<pre class="language-bash"><code class="language-bash">gh issue create <span class="token parameter variable">--web</span> <span class="token comment"># will open the issue creation page</span></code></pre>
<h2>Pull Requests</h2>
<p>What do you do when you need to check a pull request made by another developer? Find the fork url, add a new upstream, fetch the branch with changes, checkout…</p>
<p>Or you can get the id of a pull request (it’s <code>42</code> for the url <code>github.com/owner/repo/pull/42</code>) and use it as an option for <code>gh pr</code>.</p>
<pre class="language-bash"><code class="language-bash">gh <span class="token function">pr</span> checkout <span class="token number">42</span></code></pre>
<p>Ok, we have the necessary changes. What’s next? Code review!</p>
<p>Yeah, <code>gh</code> still doesn’t allow you to leave a comment on certain lines of code. But if you just need to approve the PR or request any changes, do it from the terminal.</p>
<pre class="language-bash"><code class="language-bash">gh <span class="token function">pr</span> review <span class="token parameter variable">--approve</span> <span class="token parameter variable">--body</span> <span class="token string">"LGFM"</span>
<span class="token comment"># or</span>
gh <span class="token function">pr</span> review --request-changes <span class="token parameter variable">--body</span> <span class="token string">"Wanna more emojis"</span></code></pre>
<p>Let’s merge the PR if it’s OK.</p>
<pre class="language-bash"><code class="language-bash">gh <span class="token function">pr</span> review <span class="token parameter variable">--approve</span> <span class="token parameter variable">--body</span> <span class="token string">"Looks great, thank you!"</span>
gh <span class="token function">pr</span> merge <span class="token parameter variable">--squash</span> --delete-branch</code></pre>
<p>Of course, you can also open the pull request page via terminal.</p>
<pre class="language-bash"><code class="language-bash">gh <span class="token function">pr</span> view <span class="token parameter variable">--web</span></code></pre>
<p>What if I want to propose my changes to the project? I can do it through the web interface, but it takes too many clicks. I can use the link that git prints for me when I push the branch, it’s faster. But the fastest way is to create PR with <code>gh</code>.</p>
<pre class="language-bash"><code class="language-bash">gh <span class="token function">pr</span> create <span class="token comment"># will ask you for the title and body</span>
<span class="token comment"># or</span>
gh <span class="token function">pr</span> create <span class="token parameter variable">--web</span> <span class="token comment"># will open the PR creation page</span></code></pre>
<h2>Gists</h2>
<p>Sometimes I need to share some code snippets with my colleagues. <a href="https://gist.github.com/">Gist</a> makes it simple. And you can create gists with <code>gh</code>.</p>
<pre class="language-bash"><code class="language-bash"><span class="token function">cat</span> awesome.js <span class="token operator">|</span> gh gist create <span class="token comment"># private by default</span></code></pre>
<h2>Sources</h2>
<ul>
<li><a href="https://cli.github.com/manual/">GitHub CLI: Manual</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/github-cli/</guid></item><item><title>Easy video converting for the web</title><link>https://mefody.dev/chunks/ffmpeg-alias/</link><pubDate>Sun, 28 Mar 2021 00:00:00 GMT</pubDate><description><![CDATA[<p>I want to keep my blog performant. So when there are some videos in an article, I need to convert videos to modern formats to make them smaller.</p>
<h2>HTML</h2>
<p>Andrey Sitnik wrote a <a href="https://evilmartians.com/chronicles/better-web-video-with-av1-codec">great article</a> about video codecs for the web. I customized the snippet from the article for my needs.</p>
<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>video</span> <span class="token attr-name">width</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>600<span class="token punctuation">"</span></span> <span class="token attr-name">height</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>400<span class="token punctuation">"</span></span> <span class="token attr-name">controls</span> <span class="token attr-name">muted</span> <span class="token attr-name">playsinline</span> <span class="token attr-name">preload</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>metadata<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video.av1.mp4<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/mp4; codecs=av01.0.05M.08<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>source</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video.h264.mp4<span class="token punctuation">"</span></span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>video/mp4<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>video</span><span class="token punctuation">></span></span></code></pre>
<p>This snippet works great in modern Chrome and Firefox <a href="https://caniuse.com/av1">with AV1-codec supported</a>, falling back to the bulletproof H264-codec for other browsers.</p>
<h2>ffmpeg</h2>
<p>To convert source videos for the web you can use <code>ffmpeg</code>. For macOS, it’s just <code>brew install ffmpeg</code>. This is a really great tool to work with videos. But its synopsis is not so easy to remember. And it’s not copypastable because of the strict order of arguments. For example, here is a snippet for converting to H264.</p>
<pre class="language-bash"><code class="language-bash">ffmpeg <span class="token parameter variable">-i</span> input.mov <span class="token parameter variable">-map_metadata</span> <span class="token parameter variable">-1</span> <span class="token parameter variable">-an</span> <span class="token parameter variable">-c:v</span> libx264 <span class="token punctuation">\</span>
<span class="token parameter variable">-crf</span> <span class="token number">24</span> <span class="token parameter variable">-preset</span> veryslow <span class="token parameter variable">-profile:v</span> main <span class="token parameter variable">-pix_fmt</span> yuv420p <span class="token punctuation">\</span>
<span class="token parameter variable">-movflags</span> +faststart <span class="token parameter variable">-vf</span> <span class="token string">"scale=trunc(iw/2)*2:trunc(ih/2)*2"</span> <span class="token punctuation">\</span>
output.h264.mp4</code></pre>
<p>I don’t want to remember it!</p>
<h2>Bash aliases</h2>
<p>Let’s make aliases for Bash. Open your <code>~/.bashrc</code> (or <code>~/.zshrc</code> if you use ZSH instead of Bash). Add the next code to the end of the file.</p>
<pre class="language-bash"><code class="language-bash"><span class="token keyword">function</span> <span class="token function-name function">convert-to-h264</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token variable">$2</span> <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">then</span> <span class="token assign-left variable">output</span><span class="token operator">=</span><span class="token variable">$2</span>
        <span class="token keyword">else</span> <span class="token assign-left variable">output</span><span class="token operator">=</span><span class="token variable">${1<span class="token operator">%</span>.*}</span>.h264.mp4
    <span class="token keyword">fi</span>

    ffmpeg <span class="token parameter variable">-i</span> <span class="token variable">$1</span> <span class="token parameter variable">-map_metadata</span> <span class="token parameter variable">-1</span> <span class="token parameter variable">-an</span> <span class="token parameter variable">-c:v</span> libx264 <span class="token punctuation">\</span>
    <span class="token parameter variable">-crf</span> <span class="token number">24</span> <span class="token parameter variable">-preset</span> veryslow <span class="token parameter variable">-profile:v</span> main <span class="token parameter variable">-pix_fmt</span> yuv420p <span class="token punctuation">\</span>
    <span class="token parameter variable">-movflags</span> +faststart <span class="token parameter variable">-vf</span> <span class="token string">"scale=trunc(iw/2)*2:trunc(ih/2)*2"</span> <span class="token punctuation">\</span>
    <span class="token variable">$output</span>
<span class="token punctuation">}</span></code></pre>
<p>Save the file, then apply it with <code>source ~/.bashrc</code> (or <code>source ~/.zshrc</code> for ZSH). Voila, you can use new alias to easily convert your videos.</p>
<pre class="language-bash"><code class="language-bash">convert-to-h264 input.mov <span class="token comment"># converts to input.h264.mp4 by default</span>
<span class="token comment"># or</span>
convert-to-h264 input.mov output.mp4</code></pre>
<p>I also have other aliases for my blog videos.</p>
<pre class="language-bash"><code class="language-bash"><span class="token keyword">function</span> <span class="token function-name function">convert-to-av1</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token variable">$2</span> <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">then</span> <span class="token assign-left variable">output</span><span class="token operator">=</span><span class="token variable">$2</span>
        <span class="token keyword">else</span> <span class="token assign-left variable">output</span><span class="token operator">=</span><span class="token variable">${1<span class="token operator">%</span>.*}</span>.av1.mp4
    <span class="token keyword">fi</span>

    ffmpeg <span class="token parameter variable">-i</span> <span class="token variable">$1</span> <span class="token parameter variable">-map_metadata</span> <span class="token parameter variable">-1</span> <span class="token parameter variable">-an</span> <span class="token parameter variable">-c:v</span> libaom-av1 <span class="token parameter variable">-crf</span> <span class="token number">50</span> <span class="token parameter variable">-b:v</span> <span class="token number">0</span> <span class="token punctuation">\</span>
    <span class="token parameter variable">-pix_fmt</span> yuv420p <span class="token parameter variable">-movflags</span> +faststart <span class="token parameter variable">-vf</span> <span class="token string">"scale=trunc(iw/2)*2:trunc(ih/2)*2"</span> <span class="token punctuation">\</span>
    <span class="token parameter variable">-strict</span> experimental -cpu-used <span class="token number">1</span> <span class="token punctuation">\</span>
    <span class="token variable">$output</span>
<span class="token punctuation">}</span>

<span class="token keyword">function</span> <span class="token function-name function">resize-to-width</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">[</span><span class="token punctuation">[</span> <span class="token variable">$3</span> <span class="token punctuation">]</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
        <span class="token keyword">then</span> <span class="token assign-left variable">output</span><span class="token operator">=</span><span class="token variable">$3</span>
        <span class="token keyword">else</span> <span class="token assign-left variable">output</span><span class="token operator">=</span><span class="token variable">${1<span class="token operator">%</span>.*}</span>@<span class="token variable">$2</span><span class="token builtin class-name">.</span><span class="token variable">${1<span class="token operator">##</span>*.}</span>
    <span class="token keyword">fi</span>

    ffmpeg <span class="token parameter variable">-i</span> <span class="token variable">$1</span> <span class="token parameter variable">-vf</span> <span class="token string">"scale="</span><span class="token variable">$2</span><span class="token string">":trunc(ow/a/2)*2"</span> <span class="token variable">$output</span>
<span class="token punctuation">}</span></code></pre>
<p>So my workflow with videos usually consists of three commands.</p>
<pre class="language-bash"><code class="language-bash">resize-to-width source.mov <span class="token number">1200</span> video.mov
convert-to-h264 video.mov
convert-to-av1 video.mov</code></pre>
<h2>Sources</h2>
<ul>
<li><a href="https://evilmartians.com/chronicles/better-web-video-with-av1-codec">Better web video with AV1 codec</a></li>
<li><a href="https://ffmpeg.org/documentation.html">FFmpeg Documentation</a></li>
<li><a href="https://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-8.html">HOWTO: Bash functions</a></li>
</ul>
]]></description><guid>https://mefody.dev/chunks/ffmpeg-alias/</guid></item></channel></rss>