<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Mehdi M.</title>
    <description>The latest articles on Forem by Mehdi M. (@meduzen).</description>
    <link>https://forem.com/meduzen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F47671%2Fb261f75e-04b9-4402-ab27-40b3552b9379.jpeg</url>
      <title>Forem: Mehdi M.</title>
      <link>https://forem.com/meduzen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/meduzen"/>
    <language>en</language>
    <item>
      <title>When Vite ignores your Browserslist configuration</title>
      <dc:creator>Mehdi M.</dc:creator>
      <pubDate>Mon, 26 Dec 2022 11:18:48 +0000</pubDate>
      <link>https://forem.com/meduzen/when-vite-ignores-your-browserslist-configuration-3hoe</link>
      <guid>https://forem.com/meduzen/when-vite-ignores-your-browserslist-configuration-3hoe</guid>
      <description>&lt;p&gt;I’m a long time user of &lt;a href="https://browsersl.ist/"&gt;Browserslist&lt;/a&gt; and &lt;a href="https://vitejs.dev/"&gt;Vite&lt;/a&gt; and I was pretty convinced they paired very-well. It seems to be the case for both CSS and JavaScript output, but it actually is not for JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The issue
&lt;/h2&gt;

&lt;p&gt;Weirdly, it took me ages to notice the JavaScript transformations done by Vite (using &lt;a href="https://esbuild.github.io/"&gt;ESBuild&lt;/a&gt; under the hood) always produce the same result, no matter your Browserslist configuration. Whoops!&lt;/p&gt;

&lt;p&gt;In reality, the &lt;a href="https://github.com/evanw/esbuild/issues/121"&gt;issue&lt;/a&gt; is that ESBuild doesn’t support Browserslist and uses its own &lt;a href="https://esbuild.github.io/api/#target"&gt;fine-grained &lt;code&gt;target&lt;/code&gt; system&lt;/a&gt; with a different syntax.&lt;/p&gt;

&lt;p&gt;Knowing this, we are left with two options to honor our browsers target: maintaining a second list with a compliant ESBuild syntax (passed through Vite &lt;a href="https://vitejs.dev/config/build-options.html#build-target"&gt;&lt;code&gt;build.target&lt;/code&gt;&lt;/a&gt;), or use the following fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fix in two steps
&lt;/h2&gt;

&lt;p&gt;Fortunately, there’s the &lt;a href="https://github.com/marcofugaro/browserslist-to-esbuild"&gt;&lt;code&gt;browserslist-to-esbuild&lt;/code&gt;&lt;/a&gt; package (by &lt;a href="https://marcofuga.ro/"&gt;Marco Fugaro&lt;/a&gt;) that is able to properly pass the content of a &lt;code&gt;browserslist&lt;/code&gt; file to ESBuild.&lt;/p&gt;

&lt;p&gt;The steps described here can also be visualized &lt;a href="https://github.com/Sunappu-Dojo/burokku/pull/47/commits/b2ff0fe3e23313120644bce57cec4240af4828b6"&gt;in a commit of mine&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, add &lt;code&gt;browserslist-to-esbuild&lt;/code&gt; to your project (tested version: 1.2.0):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i &lt;span class="nt"&gt;-D&lt;/span&gt; browserslist-to-esbuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Then, in your &lt;code&gt;vite.config.js&lt;/code&gt; file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;browserslistToEsbuild&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;browserslist-to-esbuild&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;browserslistToEsbuild&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it! But wait, there’s more…&lt;/p&gt;

&lt;p&gt;(Note: &lt;a href="https://github.com/nihalgonsalves/esbuild-plugin-browserslist"&gt;another package&lt;/a&gt; can do this, but I have not tested it.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Unsupported JavaScript features
&lt;/h2&gt;

&lt;p&gt;Now that ESBuild properly receives a &lt;code&gt;browserslist&lt;/code&gt; config, maybe it will throw an error on compilation if you are trying to use a JavaScript feature unsupported by some of the browsers you target. In my case, I was trying to use top-level &lt;code&gt;await&lt;/code&gt;, which is &lt;a href="https://caniuse.com/mdn-javascript_operators_await_top_level"&gt;available starting Safari 15&lt;/a&gt; while I want to support Safari starting 12.2 (iOS) or 13.1 (macOS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; ERROR  &lt;span class="o"&gt;[&lt;/span&gt;vite:esbuild-transpile] Transform failed with 1 error:                                                                          18:07:46
js/helpers/TopLevelAwait.js:1:0: ERROR: Top-level await is not available &lt;span class="k"&gt;in &lt;/span&gt;the configured target environment &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"chrome100"&lt;/span&gt;, &lt;span class="s2"&gt;"edge102"&lt;/span&gt;, &lt;span class="s2"&gt;"firefox91"&lt;/span&gt;, &lt;span class="s2"&gt;"ios12.2"&lt;/span&gt;, &lt;span class="s2"&gt;"safari13.1"&lt;/span&gt; + 2 overrides&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was well aware that some of my target browsers don’t support this feature: I’m actually using top-level &lt;code&gt;await&lt;/code&gt; to detect another browser feature, so what I want is top-level &lt;code&gt;await&lt;/code&gt; to remain in my code and crash in some browsers. This way, my app knows which workaround to use when the feature is not detected.&lt;/p&gt;

&lt;p&gt;Well, we are lucky again, because ESBuild allows to receive a &lt;a href="https://esbuild.github.io/api/#supported"&gt;list of “supported” features&lt;/a&gt; that will be prioritized over the compilation target coming from &lt;code&gt;browserslist&lt;/code&gt;. All we have to do in our Vite configuration is to use the &lt;a href="https://vitejs.dev/config/shared-options.html#esbuild"&gt;&lt;code&gt;esbuild&lt;/code&gt;&lt;/a&gt; config entry to set &lt;code&gt;supported['top-level-await']&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;esbuild&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Prevents ESBuild to throw when using a feature not supported by the
     * list of supported browsers coming from the `browserslist` file.
     */&lt;/span&gt;
    &lt;span class="na"&gt;supported&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;top-level-await&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wit this, we can compile without error, and the JavaScript now preserves &lt;code&gt;await&lt;/code&gt; at top-level.&lt;/p&gt;

&lt;p&gt;With this knowledge in mind, I think it’s safe to say that Vite is only one step away to claim full Browserslist support, and that step is probably that Vite could use &lt;code&gt;browserslist-to-esbuild&lt;/code&gt; to make everyone’s life easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  More on Vite and Browserslist
&lt;/h2&gt;

&lt;p&gt;Actually, Vite doesn’t support Browserslist at all: the only reason it “seems” to work well with CSS is because Vite uses &lt;a href="https://postcss.org/"&gt;PostCSS&lt;/a&gt;, which itself natively uses Browserslist. We could say that Vite supports Browserslist by proxy, for CSS. I’m not the only one &lt;a href="https://github.com/vitejs/vite/discussions/6849"&gt;who have been confused&lt;/a&gt; by this situation.&lt;/p&gt;

&lt;p&gt;On the other hand, if your project uses the &lt;a href="https://github.com/vitejs/vite/tree/main/packages/plugin-legacy"&gt;&lt;code&gt;@vitejs/plugin-legacy&lt;/code&gt;&lt;/a&gt;, an official Vite plugin helping you supporting browsers outside of &lt;a href="https://vitejs.dev/guide/build.html#browser-compatibility"&gt;Vite browser compatibility list&lt;/a&gt;, then Vite will make use of your Browserslist configuration because this plugin uses Babel &lt;a href="https://babeljs.io/docs/en/babel-preset-env"&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt;&lt;/a&gt; instead of ESBuild, and this Babel plugin uses your Browserslist configuration out of the box in order to define the list of JavaScript transformations that Babel will apply.&lt;/p&gt;

&lt;p&gt;As &lt;code&gt;@vitejs/plugin-legacy&lt;/code&gt; has explicit &lt;a href="https://github.com/vitejs/vite/tree/main/packages/plugin-legacy#targets"&gt;browser target documentation&lt;/a&gt; and even a &lt;a href="https://github.com/vitejs/vite/tree/main/packages/plugin-legacy#ignorebrowserslistconfig"&gt;&lt;code&gt;ignorebrowserslistconfig&lt;/code&gt; option&lt;/a&gt;, I’m gonna end by quoting myself with a sentence from the previous section:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Vite is only one step away to claim full Browserslist support, and that step is probably that Vite could use of &lt;code&gt;browserslist-to-esbuild&lt;/code&gt; to make everyone’s life easier.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;del&gt;Or, for now, two steps away: &lt;a href="https://dev.to/kingyue/comment/23l3g"&gt;as mentioned&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/kingyue"&gt;@kingyue&lt;/a&gt;, there’s currently a &lt;a href="https://github.com/vitejs/vite/issues/2476"&gt;bug in &lt;code&gt;@vitejs/plugin-legacy&lt;/code&gt;&lt;/a&gt; (and a &lt;a href="https://github.com/vitejs/vite/pull/11318"&gt;fix in review&lt;/a&gt; !), causing the Browserslist configuration to be ignored.&lt;/del&gt; (Fixed in &lt;code&gt;@vitejs/plugin-legacy&lt;/code&gt; 4.0.1.)&lt;/p&gt;

</description>
      <category>vite</category>
      <category>esbuild</category>
      <category>browserslist</category>
      <category>await</category>
    </item>
    <item>
      <title>watchOS, the wrist and the web for smaller screens</title>
      <dc:creator>Mehdi M.</dc:creator>
      <pubDate>Sun, 27 Oct 2019 02:14:49 +0000</pubDate>
      <link>https://forem.com/meduzen/watchos-the-wrist-and-the-web-bbj</link>
      <guid>https://forem.com/meduzen/watchos-the-wrist-and-the-web-bbj</guid>
      <description>&lt;p&gt;I was recently wondering what the web capabilities of Apple watchOS are. Here are my observations while using a Watch Series 5 with &lt;a href="https://www.apple.com/watchos/watchos-6/" rel="noopener noreferrer"&gt;watchOS 6&lt;/a&gt;, both released in 2019:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There’s no browser app. The only ways to consume web content are by hitting a link from Mail or Messages, or by asking Siri to go to a URL. These actions open the WebKit view (Safari 13). Like on other Apple devices, Messages uses the &lt;a href="https://ogp.me" rel="noopener noreferrer"&gt;Open Graph&lt;/a&gt; spec to replace URL’s by more readable links.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff7ffch2ajwxhcszy67ec.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ff7ffch2ajwxhcszy67ec.jpg" alt="Open Graph in action in Messages on watchOS."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Page loading duration ranges from a few seconds to more than a minute. It’s hard to predict why as it doesn’t seem linked to the JavaScript weight or to the amount of pictures.&lt;/li&gt;
&lt;li&gt;Once loaded, it’s okay-ish to browse a document. It just works and supports a wide range of browsers features (including Grid Layout).&lt;/li&gt;
&lt;li&gt;Voice control really helps to input text data, otherwise you’re left drawing letters one by one, which is the last resort fallback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft0qtha25inppg94gz0bs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ft0qtha25inppg94gz0bs.jpg" alt="Drawing letters to write on watchOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Holding an arm in front of the eyes and using the other one to browse the web prevents the overall experience to be enjoyable, reminding that watches are good for passive features, short actions and notifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that’s exactly why the Apple Watch is a great device: most apps narrow their scope, putting emphasis on small interactions, and they do it well. Keeping these principles with the web, Apple is just redirecting users to devices where the experience is better (and where the battery lasts longer).&lt;/p&gt;

&lt;p&gt;I think keeping the same focus is the way to go while supporting very small viewports on the web. Taking a developer personal website as example, you could limit what’s displayed on such a small screen to the minimal contact informations, a bit like a business card: the name, a small picture or logo and a few contact links (&lt;code&gt;&amp;lt;a href="mailto:…"&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;a href="tel:…"&amp;gt;&lt;/code&gt;). If these informations are already part of your website footer, you’re probably only a few media queries away from a decent result.&lt;/p&gt;

&lt;p&gt;When it comes to web development, watchOS requires you to be aware of some specificities, across these four topics: missing features, viewport size, forms and reader mode.&lt;/p&gt;

&lt;p&gt;The only official piece of information about web content on watchOS, well hidden in the middle of nowhere, is a &lt;a href="https://developer.apple.com/videos/play/wwdc2018/239" rel="noopener noreferrer"&gt;WWDC2018 video about preparing web content for watchOS 5&lt;/a&gt; by Apple’s developer &lt;a href="https://twitter.com/wensonhsieh" rel="noopener noreferrer"&gt;Wenson Hsieh&lt;/a&gt;. Luckily it’s a great one!&lt;/p&gt;

&lt;p&gt;We’ll go through the specific things and then see what it could mean to support smaller viewports in general. Spoiler alert: as often, betting on the fundamentals (semantic HTML, progressive enhancement) wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Disabled features
&lt;/h2&gt;

&lt;p&gt;On watchOS, there’s no support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;video playback on the web, but &lt;a href="https://developer.apple.com/design/human-interface-guidelines/watchos/user-interaction/audio-and-video/" rel="noopener noreferrer"&gt;native apps can have it&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;Service Workers;&lt;/li&gt;
&lt;li&gt;web fonts: watchOS uses &lt;a href="https://developer.apple.com/design/human-interface-guidelines/watchos/visual-design/typography" rel="noopener noreferrer"&gt;San Fransisco Compact&lt;/a&gt;, which is optimized for legibility on small sizes. A great decision.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A great use case for Service Workers on a watch could be Push Notifications (they require a Service Worker), but they are currently only available in Chrome, so it’s no big deal for now to not have Service Workers on watchOS. &lt;/p&gt;

&lt;h2&gt;
  
  
  2. The &lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;meta name="viewport"&amp;gt;&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Apple is helping CSS authors by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setting on all Watch models the same viewport, 320*357, matching the width of the iPhone SE;&lt;/li&gt;
&lt;li&gt;overriding &lt;code&gt;initial-scale&lt;/code&gt; to &lt;code&gt;0.49&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;forcing &lt;a href="https://www.scottohara.me/blog/2018/12/11/shrink-to-fit.html" rel="noopener noreferrer"&gt;&lt;code&gt;shrink-to-fit&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;yes&lt;/code&gt; (&lt;code&gt;shrink-to-fit=yes&lt;/code&gt;) in order to avoid horizontal scrolling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words: the layout of your website stays the same as on the smallest phones and fits the Watch screen without the need to unzoom.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6c70jnnu4tcbv5bsvx8m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6c70jnnu4tcbv5bsvx8m.jpg" alt="shrink-to-fit applied to the viewport on watchOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flexibility is also given as these viewport adaptations can be disabled with (non-standard) &lt;code&gt;&amp;lt;meta name="disabled-adaptations" content="watch"&amp;gt;&lt;/code&gt;: the viewport then ranges from 272*340 (38 mm Watch) to 368*448 (44 mm) and isn’t automatically shrunk to the viewport anymore, opening the road to custom styles for viewports smaller than &lt;code&gt;320px&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1yt4ikyruremlnngfuul.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1yt4ikyruremlnngfuul.jpg" alt="&amp;lt;meta name="&gt;&lt;/a&gt; combined with &lt;a class="mentioned-user" href="https://dev.to/media"&gt;@media&lt;/a&gt; (min-width) on watchOS"/&amp;gt;&lt;/p&gt;

&lt;p&gt;This &lt;em&gt;meta&lt;/em&gt; is also important to fine-tune websites using responsive images: &lt;a href="https://ericportis.com/posts/2018/respimg-apple-watch" rel="noopener noreferrer"&gt;Eric Portis recommends to disable watchOS viewport adaptations&lt;/a&gt; because of the returned &lt;em&gt;DPR&lt;/em&gt; (device pixel ratio) being too high, resulting in wasted bandwidth (and thus battery consumption).&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Forms
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Accessibility
&lt;/h3&gt;

&lt;p&gt;Filling a form opens a full screen panel, so &lt;code&gt;arial-label&lt;/code&gt; is needed to provide label hints while filling a field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fk2mssi88km94f9fishxd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fk2mssi88km94f9fishxd.jpg" alt="Accessible form field on watchOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, don’t forget the &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"billing-email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    The email address where invoices will be sent
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"billing-email"&lt;/span&gt; &lt;span class="na"&gt;aria-label=&lt;/span&gt;&lt;span class="s"&gt;"Billing email"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fields
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;select&amp;gt;&lt;/code&gt; and the following &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#&amp;lt;input&amp;gt;_types" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; types&lt;/a&gt; all comes with a dedicated keyboard layout: &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;numeric&lt;/code&gt;, &lt;code&gt;tel&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, &lt;code&gt;time&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7g5kc4d1zom3av2326ho.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F7g5kc4d1zom3av2326ho.jpg" alt="Tel, date and select fields on watchOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Reading articles
&lt;/h2&gt;

&lt;p&gt;Heavy text pages automatically enable the reader mode. Like every reader mode, it relies on proper HTML markup: &lt;code&gt;article&lt;/code&gt;, &lt;code&gt;figure&lt;/code&gt;, &lt;code&gt;figcaption&lt;/code&gt;, &lt;code&gt;blockquote&lt;/code&gt;…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fstmnlom5zwbayd9wx7z3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fstmnlom5zwbayd9wx7z3.jpg" alt="&amp;lt;figure&amp;gt;&amp;lt;img src="&gt;&lt;/a&gt;Picture description shown below the picture&lt;/p&gt;

&lt;p&gt;Unexpectedly, &lt;a href="https://schema.org" rel="noopener noreferrer"&gt;microdata&lt;/a&gt; are used to introduce the article metadata in the reader mode. This is awesome!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fdrlufq75orkvlvfmbn87.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fdrlufq75orkvlvfmbn87.jpg" alt="Microdata used to introduce an article in the watchOS reader mode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Dealing with small viewports in general
&lt;/h2&gt;

&lt;p&gt;A few months ago, I started to shape what supporting smaller viewports could be like. Aside from an Apple Watch, there are at least &lt;del&gt;two&lt;/del&gt; three other use cases for ~150 px wide viewports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;desktop installed PWA;&lt;/li&gt;
&lt;li&gt;smartphones split views;&lt;/li&gt;
&lt;li&gt;Firefox macOS allowing to resize the window &lt;a href="https://m.nintendojo.fr/@meduz/109641994342740113" rel="noopener noreferrer"&gt;as low as 450 px by 63 px&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Usually I move a lot of CSS inside &lt;code&gt;@media (min-width: 20em)&lt;/code&gt; (&lt;code&gt;20em&lt;/code&gt; is generally &lt;code&gt;320px&lt;/code&gt;). Some rules of thumb for smaller viewports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every CSS rule changing an element position, size, flow or horizontal spacing should be in this &lt;code&gt;min-width&lt;/code&gt; media query;&lt;/li&gt;
&lt;li&gt;same for decorative assets like &lt;code&gt;background-image&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;make sure &lt;code&gt;font-size&lt;/code&gt; stays small;&lt;/li&gt;
&lt;li&gt;avoid running JavaScript if your app can work without it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’re left with a &lt;em&gt;usable&lt;/em&gt; HTML document with a basic sense of identity powered by some decoration rules (colours, opacity…).&lt;/p&gt;

&lt;p&gt;Here’s a basic example where two elements in the header stack in one column when the viewport is too small, along with &lt;code&gt;background-image&lt;/code&gt; removal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbnazvycvrbo0x8x3qjm3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fbnazvycvrbo0x8x3qjm3.jpg" alt="Putting everything on a single column for viewports smaller than 320px wide"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The only CSS changes consist of moving some CSS declarations into a &lt;code&gt;@media&lt;/code&gt; rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;62&lt;/span&gt;&lt;span class="mi"&gt;.5%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="mi"&gt;.2rem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20em&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url('bg.png')&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Did you know a desktop installed web app can be resized down to 207×117 on macOS? Here’s &lt;a href="https://canistop.net" rel="noopener noreferrer"&gt;Can I Stop&lt;/a&gt; installed on macOS, with a viewport width below 320 px:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6jsqdom7iemh7bhd23xj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F6jsqdom7iemh7bhd23xj.jpg" alt="Can I Stop as an installed desktop app on macOS"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is &lt;a href="https://block.sunappu.net" rel="noopener noreferrer"&gt;Burokku&lt;/a&gt; width a viewport of 371×1 (well, actually 0.77px according to Edge developer tools) on Windows 10 (&lt;a href="https://m.nintendojo.fr/@meduz/110000122113450691" rel="noopener noreferrer"&gt;video&lt;/a&gt;):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0cryhnqwoam6ukbo1a4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0cryhnqwoam6ukbo1a4.jpg" alt="Burokku as an installed desktop app on Windows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, big shoutout to &lt;a href="https://developer.apple.com/videos/play/wwdc2018/239/?time=62" rel="noopener noreferrer"&gt;Apple’s developers videos website&lt;/a&gt;, which contains downloadable videos, high-definition slides (the pictures of this article are mostly from the slides), and a super cool transcription system with links to navigate the video. Worth trying and browsing!&lt;/p&gt;

</description>
      <category>watchos</category>
      <category>html</category>
      <category>css</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Write CSS variables faster in SCSS</title>
      <dc:creator>Mehdi M.</dc:creator>
      <pubDate>Wed, 07 Nov 2018 00:33:08 +0000</pubDate>
      <link>https://forem.com/meduzen/write-css-variables-faster-in-scss-1mon</link>
      <guid>https://forem.com/meduzen/write-css-variables-faster-in-scss-1mon</guid>
      <description>&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt; (October 20th, 2022): while this helper remains cool, I have decided to not use it outside of personal projects. Compared to IDE auto-completion, its benefits might not be worth the cognitive load linked to any additional abstraction.&lt;/p&gt;




&lt;p&gt;I love &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/var" rel="noopener noreferrer"&gt;CSS variables&lt;/a&gt; (&lt;a href="https://dev.to/meduzen/comment/6k2d"&gt;here’s why&lt;/a&gt;) but the syntax isn’t very readable to me:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;there’s this double hyphen thing in the name: &lt;code&gt;--varName&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;var&lt;/code&gt; function is required to access it: &lt;code&gt;color: var(--myColor);&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crazy. Let’s simplify this with…&lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;v()&lt;/code&gt; function!
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codepen.io/meduzen/pen/YRyEPe?editors=1100" rel="noopener noreferrer"&gt;Demo on Codepen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/meduzen/v-helper" rel="noopener noreferrer"&gt;NPM package&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;First, define your CSS variables normally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#fff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, use it with &lt;code&gt;v(varName)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It generates this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--bg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--primary&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s only a 4 characters win, but it’s a cool one for readability and you’ll use it often.&lt;/p&gt;

&lt;p&gt;That’s it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional second parameter as fallback
&lt;/h2&gt;

&lt;p&gt;As it was &lt;a href="https://dev.to/equinusocio/comment/6kda"&gt;pleasely mentioned&lt;/a&gt; in the comments, the CSS &lt;code&gt;var()&lt;/code&gt; function can take a fallback as second parameter: if the wanted CSS variable isn’t defined or has an understandable value for the browser, this default value will be used.&lt;/p&gt;

&lt;p&gt;So, let’s update &lt;code&gt;v()&lt;/code&gt; accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="k"&gt;@function&lt;/span&gt; &lt;span class="nf"&gt;v&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$fallback&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;@if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$fallback&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;@else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;@return&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nv"&gt;$var&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let’s write something that benefits from the optional fallback, like a “pin the video in a corner” feature:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  One small bit of fun
&lt;/h2&gt;

&lt;p&gt;Do you know that &lt;code&gt;--&lt;/code&gt; is a valid name for a CSS custom property? Unfortunately, it’s hard to declare and use it in SCSS. But the &lt;code&gt;v()&lt;/code&gt; helper &lt;a href="https://github.com/meduzen/v-helper#---is-a-valid-custom-property-name" rel="noopener noreferrer"&gt;makes your life a bit easier&lt;/a&gt;. ✌️&lt;/p&gt;

&lt;h2&gt;
  
  
  Other attempts that could have been cool, but…
&lt;/h2&gt;

&lt;p&gt;If you’re wondering how to improve my package, I compiled &lt;a href="https://gist.github.com/meduzen/7ada5fc3d7296767c9e7f677229d60d4" rel="noopener noreferrer"&gt;three unsuccessful attempts in a Gist&lt;/a&gt;. Feel free to propose CSS variable tips!&lt;/p&gt;

</description>
      <category>css</category>
      <category>sass</category>
      <category>scss</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Recover a lost Git stash in two steps</title>
      <dc:creator>Mehdi M.</dc:creator>
      <pubDate>Fri, 27 Apr 2018 21:38:58 +0000</pubDate>
      <link>https://forem.com/meduzen/recover-a-lost-git-stash-in-two-steps-569</link>
      <guid>https://forem.com/meduzen/recover-a-lost-git-stash-in-two-steps-569</guid>
      <description>&lt;p&gt;Sometimes you end up &lt;a href="https://css-irl.info/how-git-stash-can-help-you-juggle-multiple-branches" rel="noopener noreferrer"&gt;stashing&lt;/a&gt; &lt;a href="https://www.git-scm.com/docs/git-stash" rel="noopener noreferrer"&gt;code&lt;/a&gt;, then at some point those stashes get cleaned. And one day, you may encounter the situation I faced this week:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fine, this code is merged, so let’s delete the related stashes. Done! And… hey… wasn’t this part of the feature supposed to be in the codebase? Is the stash I just deleted lost forever?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Fortunately, I managed to recover lost stashes. I’m not a Git expert, but here’s what worked for me after going through various readings (including &lt;a href="https://stackoverflow.com/questions/89332/how-to-recover-a-dropped-stash-in-git" rel="noopener noreferrer"&gt;some&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/32517870/how-to-undo-git-stash-clear" rel="noopener noreferrer"&gt;Stack Overflow&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/20537223/when-should-i-use-git-stash" rel="noopener noreferrer"&gt;answers&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Here’s the two-steps recovery procedure.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. List lost stashes
&lt;/h2&gt;

&lt;p&gt;Let’s run this command for a project where all stashes were trashed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fsck &lt;span class="nt"&gt;--unreachable&lt;/span&gt; | &lt;span class="nb"&gt;grep &lt;/span&gt;commit | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;' '&lt;/span&gt; &lt;span class="nt"&gt;-f3&lt;/span&gt; | xargs git log &lt;span class="nt"&gt;--merges&lt;/span&gt; &lt;span class="nt"&gt;--no-walk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns a list of lost stashes, ordered by date.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmdijr6l202ux4yi31cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvmdijr6l202ux4yi31cy.png" alt="Ho, 3 lost stashes!" width="530" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;To quit the list of stashes, press the &lt;a href="https://unsplash.com/search/photos/cookies" rel="noopener noreferrer"&gt;Q key&lt;/a&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;To navigate in a long stashes list, use &lt;code&gt;up&lt;/code&gt; and &lt;code&gt;down&lt;/code&gt; arrows.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;For Windows user, maybe johnwait’s comment will help you during the battle.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  2. Send a lost stash back where it comes from
&lt;/h2&gt;

&lt;p&gt;Let’s use the commit hash of the second stash:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git update-ref refs/stash 4b3fc45c94caadcc87d783064624585c194f4be8 &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"My recovered stash"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it! You’ll find your stash as usual, using &lt;code&gt;git stash list&lt;/code&gt; or by having a look in your &lt;a href="http://gitup.co/" rel="noopener noreferrer"&gt;favorite Git client&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gotchas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. I still can’t see my recovered stash
&lt;/h3&gt;

&lt;p&gt;Retry using the &lt;code&gt;--create-reflog&lt;/code&gt; parameter (thanks &lt;a href="https://dev.to/studoggithub/comment/d54a"&gt;studoggithub&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git update-ref refs/stash 4b3fc45c94caadcc87d783064624585c194f4be8 &lt;span class="nt"&gt;--create-reflog&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"My recovered stash"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. My Git isn’t in English
&lt;/h3&gt;

&lt;p&gt;If your Git isn’t in English, you’ll have to run &lt;code&gt;alias git='LANG=en_GB git'&lt;/code&gt; each time you want to recover a set of stashes (thanks &lt;a href="https://dev.to/mathieuschopfer/comment/egd0"&gt;mathieuschopfer&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Some advices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Commit messages are healthy
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Always use a commit message&lt;/strong&gt; using &lt;code&gt;git stash save -m "My commit message"&lt;/code&gt;: without message, the only informations helping to identify a stash are its timestamp and the branch it was saved from, which may not be enough compared to a strong explicit name.&lt;/p&gt;

&lt;p&gt;Commit messages also help Git clients:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitUp, the Git client I use, completely fails at showing unnamed stashes. That’s probably why you can’t create a stash in GitUp without giving it a name, which is great!&lt;/li&gt;
&lt;li&gt;The well-known &lt;a href="https://www.sourcetreeapp.com/" rel="noopener noreferrer"&gt;SourceTree&lt;/a&gt; succeeds at showing unnamed stashes, but as you can guess, the list isn’t friendly to browse:
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw084clpajw2ul0sfzy0d.png" alt="Unnamed stashes in SourceTree" width="143" height="193"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Yes, &lt;code&gt;git stash apply&lt;/code&gt; &amp;gt; &lt;code&gt;git stash pop&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Unlike &lt;code&gt;git stash pop&lt;/code&gt;, &lt;strong&gt;&lt;code&gt;git stash apply&lt;/code&gt;&lt;/strong&gt; does not remove the stash from the list of stashes, which can avoid some loss.&lt;/p&gt;

&lt;h3&gt;
  
  
  Branches &amp;gt; stashes
&lt;/h3&gt;

&lt;p&gt;Finally, I’d recommend to avoid &lt;code&gt;git stash&lt;/code&gt;. Instead, try to &lt;a href="https://git-scm.com/docs/git-checkout" rel="noopener noreferrer"&gt;use a branch&lt;/a&gt;. This seems obvious but it only comes to me as I was finding a way to recover a stash: maybe I should use temporary branches instead of stashes. Using the &lt;a href="http://nvie.com/posts/a-successful-git-branching-model/" rel="noopener noreferrer"&gt;Git Flow&lt;/a&gt; method at work, this could have come to my mind before encountering a painful experience.&lt;/p&gt;

&lt;p&gt;If you have any &lt;em&gt;stash&lt;/em&gt; hint or experience that you want to share, comments are welcome.&lt;/p&gt;

</description>
      <category>git</category>
    </item>
  </channel>
</rss>
