<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Code Stranger]]></title><description><![CDATA[I am a full stack developer with experience in PHP, Javascript, HTML & CSS, with passion for the Symfony framework. I continue to learn because there is always ]]></description><link>https://blog.tomaskorec.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 11:49:46 GMT</lastBuildDate><atom:link href="https://blog.tomaskorec.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Replace your modals with <dialog> (or don't)]]></title><description><![CDATA[The dialog element has been around for a while, and the key question is: Can it effectively replace all modal elements of various types and designs? The short answer is yes. However, there are several reasons why you should not rush to prepare for th...]]></description><link>https://blog.tomaskorec.com/replace-your-modals-with-dialog-or-dont</link><guid isPermaLink="true">https://blog.tomaskorec.com/replace-your-modals-with-dialog-or-dont</guid><category><![CDATA[HTML]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[coding]]></category><category><![CDATA[Dialog]]></category><category><![CDATA[DOM]]></category><dc:creator><![CDATA[Tomáš Korec]]></dc:creator><pubDate>Thu, 02 Nov 2023 22:08:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698962346382/34c02e98-8f82-4853-a1b9-bea5e92d3489.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <code>dialog</code> element has been around for a while, and the key question is: Can it effectively replace all modal elements of various types and designs? The short answer is yes. However, there are several reasons why you should not rush to prepare for the introduction of this feature.</p>
<h2 id="heading-what-is-ltdialoggt-element-for">What is &lt;dialog&gt; element for?</h2>
<p>In short, the <code>dialog</code> aims to alleviate the eternal problem of modal complexity (anyone who has been through it knows what I am talking about) and introduces a minimal API for opening and closing it while keeping everything simple and reliable. There is not much magic going on: by default, the modal is not visible, but this is caused by the default CSS (<code>display: none</code>), so you are free to override it if needed. Adding the <code>open</code> attribute (not a recommended way, but possible) does nothing special either, it just changes the display to block.</p>
<p>The real magic comes with the javascript methods that can be called on the <code>HTMLDialogElement</code> instance. There are two for opening the modal and one for closing it. The <code>show()</code> method just adds the <code>open</code> attribute, but the <code>showModal()</code> method is about something else.</p>
<h2 id="heading-showmodal">showModal()</h2>
<p>It renders the modal outside the HTML into a "top layer" while keeping the original HTML intact (the top layer element references the <code>dialog</code> element). The <code>dialog</code> element is also provided with a pseudo-element <code>::backdrop</code>, which is given a basic styling. The <code>dialog</code> itself is centered and can be adjusted to the needs of the design. Also, the backdrop can be styled like any other element, and you could say that the backdrop-filter CSS property finally serves its purpose.</p>
<p>The modal can be closed using the javascript <code>close()</code> method on the element, or more clumsily, using the form inside the modal with <code>action="dialog"</code>.</p>
<h2 id="heading-pitfalls">Pitfalls</h2>
<p>However, there are some caveats to consider before you start replacing all your existing modals with dialogs. The good news is that it may satisfy all your needs. The problem is that for certain behaviors you may have to accept some workarounds and even give up some of the benefits that dialogs offer.</p>
<h3 id="heading-top-layer-positioning">Top layer positioning</h3>
<p>When displayed in modal mode (using the <code>showModal()</code> method), the <code>dialog</code> is displayed in a separate layer on top of any HTML elements. This prevents you from showing anything on top of the <code>dialog</code>. Do you have flash messages you want to show while the modal is open? They won't be visible. Do you have a custom cursor (typically created by positioning an element on the mouse position when moving)? You won't see it. Do you have an overlay effect or something that should cover the whole document? Or even a CSS filter applied to <code>body</code> or <code>html</code>? It won't apply to the <code>dialog</code>.</p>
<p>If you need one of these, the only way is to abandon the modal mode and implement it yourself with the non-modal <code>dialog</code>. This means creating your solution for background and positioning. The only advantage you are left with is the simple show/close API, but let's be honest, is it that much of an advantage over toggling a <code>visible</code> class? If you use some fading effects, you will probably have to deal with custom classes anyway.</p>
<h3 id="heading-backdrop-clicks">Backdrop clicks</h3>
<p>The second issue concerns the <strong>backdrop</strong>. Any reasonable modal that allows the user to close it should be able to be closed by clicking on the backdrop (among other possibilities, like clicking a close button or the <em>Esc key</em>). Although the <code>dialog</code> already implements closing with the <em>Esc</em> <em>key</em>, clicking on the backdrop is not easily achievable: There is no way to listen for events on pseudoelements. Of course, we can listen to the <code>dialog</code> itself and distinguish the <code>dialog</code> from its content.</p>
<pre><code class="lang-javascript">modal.addEventListener(<span class="hljs-string">'click'</span>, <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (e.target !== modal) <span class="hljs-keyword">return</span>;

    modal.close();
});
</code></pre>
<p>However, this already forces us to have some element inside the dialog and also to remove a padding from the dialog element, because then clicking on the padded area would still open it. This may be a small problem, but considering how often this feature is used, it would be better to have it natively available.</p>
<h2 id="heading-on-the-other-hand">On the other hand...</h2>
<p>Rather than just mentioning problems, I would like to emphasize perhaps the biggest advantage of using <code>dialog</code> elements: It preserves the DOM structure as it is. So there can be an element with its modal placed inside, and this can do a great job of keeping the relationships between elements straightforward. With an ordinary modal, you either negotiate a good display from inside a deep element structure using some CSS hacking, or you place the modal at the top level in the HTML, torn away from its scope. <code>Dialog</code> is especially great for encapsulated or scoped components like in some javascript frameworks (Angular, React or Stimulus).</p>
<p>I would recommend going with the <code>dialog</code> element if you think all the possible drawbacks are unimportant. Even then, keep them in mind, because the result might be different from what you expected, and you don't want to refactor all your modals just to find out that some things don't work for you.</p>
]]></content:encoded></item><item><title><![CDATA[Navigating Github Copilot: Part 1]]></title><description><![CDATA[Copilot is an AI-powered virtual code assistant created by GitHub. It helps us as programmers write professional quality code faster and easier.
Becoming a Copilot Convert
I've been using Github Copilot for over a year now - since March 2022, to be e...]]></description><link>https://blog.tomaskorec.com/navigating-github-copilot-part-1</link><guid isPermaLink="true">https://blog.tomaskorec.com/navigating-github-copilot-part-1</guid><category><![CDATA[github copilot]]></category><dc:creator><![CDATA[Tomáš Korec]]></dc:creator><pubDate>Tue, 23 May 2023 15:12:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684954762357/a92f790c-3b11-40b8-ba2e-e7e5f7dcbae6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Copilot is an AI-powered virtual code assistant created by GitHub. It helps us as programmers write professional quality code faster and easier.</p>
<h1 id="heading-becoming-a-copilot-convert">Becoming a Copilot Convert</h1>
<p>I've been using Github Copilot for over a year now - since March 2022, to be exact. At first, I was wary of it and didn't use it very effectively, but over time it has become an integral part of my workflow. In that time, I've found that, when used correctly, Copilot can be an incredible time saver and unleash creative thinking. I can still code without Copilot, but I find it an immense waste of time. It's like driving through an unfamiliar city without navigation. Sure, you can rely on the signs and street names. But you may have to stop now and then and look up the route on your paper map before you can continue your journey. And there is (most likely) no way back for me. I got used to Copilot the same way I got used to Waze.</p>
<h1 id="heading-the-first-tragic-date">The First 'Tragic' Date</h1>
<p>A programmer friend of mine has yet to use Copilot, despite my persistent recommendations. He recently wrote me to say that he had finally installed it on a trial basis, but described the result as "tragic". I was not that surprised: Copilot doesn't have to be love at first sight (it took me about a month to learn how to use it so that we didn't get on each other's nerves).</p>
<p>For many people, getting started with Copilot can be difficult. Some may be bothered by the frequent suggestions, others by the error-prone nature of the resulting code, or by a certain unpredictability. It is also important not to expect miracles from Copilot right away, as these will appear after a while of use. Copilot is a tool like any other, and as such it is good to know exactly what it can and cannot be used for.</p>
<p>For this purpose, I have written down some of the most common use cases that I encounter daily and that make the most of Copilot's power.</p>
<p>For the sake of simplicity, I will write most of the following snippets in Javascript.</p>
<h1 id="heading-imitation">Imitation</h1>
<p>A natural feature of AI models is the ability to <strong>mimic</strong> faithfully, and therein lies the power of Copilot. If we provide it with an understandable blueprint, we can get it to mimic it any way we want.</p>
<p>Let's imagine that we have an array of animals and one of the animals selected (<code>currentAnimal</code> - it can be different each time).</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> animals = [<span class="hljs-string">'badger'</span>, <span class="hljs-string">'otter'</span>, <span class="hljs-string">'bear'</span>, <span class="hljs-string">'racoon'</span>];

<span class="hljs-keyword">let</span> currentAnimal = <span class="hljs-string">'bear'</span>;
</code></pre>
<p>Now we will write a <code>moveRight()</code> function that will be called every time the right arrow is clicked. If there is no element left, we will start with the first one:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveRight</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = animals.indexOf(currentAnimal) + <span class="hljs-number">1</span>;

    <span class="hljs-keyword">if</span> (index &gt; animals.length - <span class="hljs-number">1</span>) {
        index = <span class="hljs-number">0</span>;
    }

    currentAnimal = animals[index];
}
</code></pre>
<p>It probably won't even be necessary to write the function declaration for Copilot to understand what's going on: I just added two newlines after the closing brace of the <code>moveRight()</code> function, and Copilot already suggests the following:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveLeft</span>(<span class="hljs-params"></span>) </span>{
</code></pre>
<p>This is probably not a big surprise. But if I accept, Copilot will propose the whole function body:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveLeft</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = animals.indexOf(currentAnimal) - <span class="hljs-number">1</span>;

    <span class="hljs-keyword">if</span> (index &lt; <span class="hljs-number">0</span>) {
        index = animals.length - <span class="hljs-number">1</span>;
    }

    currentAnimal = animals[index];
}
</code></pre>
<p>Ok, so what is the big deal here? Let's break down what has Copilot done.</p>
<ol>
<li><p><strong>Pair completion</strong>: Copilot tends toward completeness. If I have something that describes one half of the problem, it likes to suggest the other half. This can be annoying in the rare case that it wasn't my goal, but very useful when I simply forget to finish it and am about to start writing some other code. In that case, this serves as a friendly reminder that I might be about to accidentally leave out an important part of the desired result.</p>
</li>
<li><p><strong>Maintaining code consistency</strong>: This function can be written in many ways, many of which are probably even better than our solution. Copilot doesn't try to outsmart us and respects our code style.</p>
</li>
<li><p><strong>Identification of the divergence</strong>: These two functions are similar, but there are some key differences. Copilot is very good at deciding what is similar and what is different about these functions. It correctly reverses the endless circle logic for the opposite direction.</p>
</li>
</ol>
<p>On the other hand, you should <strong>not</strong> expect Copilot to fix your bad code if not asked to. For example, if I had written the first function like this:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveRight</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = animals.indexOf(currentAnimal);

    <span class="hljs-keyword">if</span> (index &gt;= animals.length - <span class="hljs-number">1</span>) {
        index = <span class="hljs-number">0</span>;
    }

    currentAnimal = animals[index + <span class="hljs-number">1</span>];
}
</code></pre>
<p>it would have given me the following <code>moveLeft()</code> without hesitation:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveLeft</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = animals.indexOf(currentAnimal);

    <span class="hljs-keyword">if</span> (index &lt;= <span class="hljs-number">0</span>) {
        index = animals.length - <span class="hljs-number">1</span>;
    }

    currentAnimal = animals[index - <span class="hljs-number">1</span>];
}
</code></pre>
<p>What is the problem here? It may not be clear at first, but if you go right from the last one back to the first one, the first one is skipped. Likewise, if you go back to the last one from the first one to the left, it will also skip it.</p>
<p>Don't blame Copilot for your own mistakes. If you are not sure about your code, you can always ask Copilot to refactor it.</p>
<h1 id="heading-refactoring">Refactoring</h1>
<p>I don't use Copilot to refactor my code very often, relying instead on my intuition and experience. However, in some cases, you might find it very useful. Nevertheless, you should always be suspicious of any code that Copilot generates, and double-check that it meets your expectations. Be critical and optionally ask it to improve until you are satisfied with the result.</p>
<blockquote>
<p>You shouldn't just accept Copilot's output as is; always explore its essence to empower your future coding</p>
</blockquote>
<p>Let's rewrite the <code>moveRight()</code> function first. Start by writing a comment with the request.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better</span>
</code></pre>
<p>It offers us this simple solution</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveRight</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = animals.indexOf(currentAnimal);

    index = (index + <span class="hljs-number">1</span>) % animals.length;

    currentAnimal = animals[index];
}
</code></pre>
<p>However, we might want to have the function as a one-liner. So we will specify it:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better as a one-liner</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveRight</span>(<span class="hljs-params"></span>) </span>{
    currentAnimal = animals[(animals.indexOf(currentAnimal) + <span class="hljs-number">1</span>) % animals.length];
}
</code></pre>
<p>This seems fine, but it is starting to look pretty unreadable. It is our job to keep things simple, so we should decide which solution to choose.</p>
<p>A good example of why we shouldn't always rely on Copilot uncritically is this:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better, but without using indexOf</span>
</code></pre>
<p>Let's not be mistaken, this is completely possible. But the result does not reflect that:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better, but without using indexOf</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveRight</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = animals.indexOf(currentAnimal);

    <span class="hljs-keyword">if</span> (index &gt;= animals.length - <span class="hljs-number">1</span>) {
        index = <span class="hljs-number">0</span>;
    }

    currentAnimal = animals[index + <span class="hljs-number">1</span>];
}
</code></pre>
<p>This proves that you need to know, at least approximately, what you are doing when you use Copilot. Let's fix the "prompt":</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better, but without using indexOf and using a loop</span>
</code></pre>
<p>The funny thing is (and this happens to me quite often) that when Copilot has to enter unknown territory, it tries to show some resistance, similar to a person who is forced to jump into unknown water. When I wrote the first comment and pressed Enter, it did not give me a function but added a similar comment for <code>moveLeft</code> and then started repeating it indefinitely.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better, but without using indexOf but using a loop</span>
<span class="hljs-comment">// rewrite moveLeft better, but without using indexOf but using a loop</span>
<span class="hljs-comment">// rewrite moveRight better, but without using indexOf but using a loop</span>
<span class="hljs-comment">// rewrite moveLeft better, but without using indexOf but using a loop</span>
<span class="hljs-comment">// rewrite moveRight better, but without using indexOf but using a loop</span>
<span class="hljs-comment">// rewrite moveLeft better, but without using indexOf but using a loop</span>
</code></pre>
<p>So I had to force the desired result by writing <code>function</code> just below my initial comment. Here it had no turning point, so it finally committed itself to this task.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// rewrite moveRight better, but without using indexOf but using a loop</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">moveRight</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> index = <span class="hljs-number">0</span>;

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; animals.length; i++) {
        <span class="hljs-keyword">if</span> (animals[i] === currentAnimal) {
            index = i;
        }
    }

    <span class="hljs-keyword">if</span> (index &gt;= animals.length - <span class="hljs-number">1</span>) {
        index = <span class="hljs-number">0</span>;
    }

    currentAnimal = animals[index + <span class="hljs-number">1</span>];
}
</code></pre>
<p>Is this solution the best? If you don't know, don't rely on Copilot to know any better.</p>
]]></content:encoded></item><item><title><![CDATA[Moving from Stylus to Sass]]></title><description><![CDATA[I started my web development journey around the year 2012 as HTML & CSS developer. My first projects were more of an introduction to web development and discovering its possibilities, rather than preparing me to become a full-fledged developer.
I was...]]></description><link>https://blog.tomaskorec.com/moving-from-stylus-to-sass</link><guid isPermaLink="true">https://blog.tomaskorec.com/moving-from-stylus-to-sass</guid><category><![CDATA[Sass]]></category><category><![CDATA[Stylus]]></category><category><![CDATA[CSS]]></category><category><![CDATA[coding]]></category><category><![CDATA[learning]]></category><dc:creator><![CDATA[Tomáš Korec]]></dc:creator><pubDate>Fri, 27 Jan 2023 12:49:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1674738880472/c2568fb5-080c-4207-8606-bfa0130fc824.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I started my web development journey around the year 2012 as HTML &amp; CSS developer. My first projects were more of an introduction to web development and discovering its possibilities, rather than preparing me to become a full-fledged developer.</p>
<p>I was more interested in the graphic design of web pages, which was booming at the time, and felt that knowledge of programming was more of a necessity if I wanted to apply my graphic designs.</p>
<p>Strange as it may seem today, at that time a significant proportion of websites were still laid out using HTML tables, the absolute minimum of websites had a responsive display and it was not uncommon to use inline styles.</p>
<p>At least that's how it seemed to me.</p>
<p>The thing is, it's not hard to learn the basics of any language these days. There are plenty of online courses, boot camps, YouTube tutorials and Q&amp;A sites. The roads are trodden and paved.</p>
<p>Back then, it was much harder for a complete beginner like me to learn all the "best practices" and adapt to new trends as they emerged.</p>
<p>At the time, I was unfamiliar with module bundlers and javascript frameworks and usually worked with a single CSS file whose structure was determined only by clumsily written comments.</p>
<p>So it was almost a revelation when I discovered CSS preprocessors. I dabbled with Less for a while but quickly settled on the best of the holy trinity: Stylus.</p>
<h1 id="heading-discovering-stylus">Discovering Stylus</h1>
<p>I've been using Stylus since 2014 for over seven years and have always been dismissive about any other CSS preprocessor.</p>
<p>Stylus was simply the best. Not only did it allow the nesting of selectors and the use of mixins. It radically stripped down CSS syntax to the bare minimum. It removed semicolons, compound brackets, and even colons, and replaced them with indentations and spaces.</p>
<p>It allowed the programmer to think spatially, in the context of the DOM. While chaining class names is hell in pure CSS, in Stylus it's all about structured and logical code. I was also able to write the style first and then write the HTML for it.</p>
<p>For example, when styling a contact box, I can write simply:</p>
<pre><code class="lang-scss"><span class="hljs-selector-class">.contact</span>
    &amp;-box
        &amp;-heading
            <span class="hljs-attribute">font-size</span> 1<span class="hljs-selector-class">.5rem</span>

            &amp;<span class="hljs-selector-pseudo">:hover</span>
                <span class="hljs-attribute">color</span> midnightBlue

        &amp;-info
            <span class="hljs-attribute">font-size</span> 1<span class="hljs-selector-class">.1rem</span>
</code></pre>
<p>Which already defines the HTML structure. The same properties written in pure CSS would be flatter and less understandable.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.contact-box-heading</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.5rem</span>;
}

<span class="hljs-selector-class">.contact-box-heading</span><span class="hljs-selector-pseudo">:hover</span> {
    <span class="hljs-attribute">color</span>: midnightBlue;
}

<span class="hljs-selector-class">.contact-box-info</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-number">1.1rem</span>;
}
</code></pre>
<p>Of course, other CSS preprocessors had this kind of superpower. The winning difference was that Stylus got rid of all the annoying nonsense that stifled creativity and flow such as curly braces, dollar signs, colons, and semicolons. Even variables didn't need to be denoted by special characters - they were just simple words.</p>
<p>But you could still use them. Another advantage of Stylus was that you could put pure CSS into Stylus code and it would still work.</p>
<p>Soon I also started using stylus packages that allowed me to create layouts on a professional level: among others, mainly the <strong>jeet</strong> package for grid and columns (this was before grid and flex were supported in most browsers) and <strong>rupture</strong> to make breakpoints handling much easier.</p>
<p>The best thing is that I wasn't forced to use some pre-baked solutions and I built everything from scratch.</p>
<p>I have worked with Stylus on more than 30 projects, some of which have been very large, with more than 200 individual <code>.styl</code> files. Stylus has proven to be robust and scalable, easy to use with or without a module bundler, time-saving and highly rewarding.</p>
<h1 id="heading-farewell">Farewell</h1>
<p>By 2020, problems began to emerge. The first was that compilation errors became more and more common. This was mainly caused by misplaced whitespaces or bad indentation. The problem was that the IDE's formatting and linting plugins were out of date and didn't recognize some syntactical features. Also, the hinting was often broken or did not include some of the newer CSS properties.</p>
<p>Sometimes Stylus was impossible to use because the helper plugins were driving me crazy. It is also important to note that Stylus has never seen a major release: at the time of writing, the latest version is 0.59.0. Also, the project was poorly maintained and Stylus wasn't even that popular anymore: according to <a target="_blank" href="https://2021.stateofcss.com/en-US/technologies">The State of CSS of 2021</a>, only about 15% of all developers used <strong>Stylus</strong> and satisfaction reached only 35%. In comparison, <strong>Sass</strong> was the preprocessor of choice for 70% of developers and enjoyed 84% satisfaction.</p>
<p>I ran out of patience when I set up a new project in Angular and found out that Stylus is no longer offered for writing styles. It was still possible to set it up for use in the application at the time, but the Angular team had clearly stated that it <a target="_blank" href="https://github.com/angular/angular-cli/issues/22432">would not be supported in the future</a> (only 0.3% of all users were using it).</p>
<h1 id="heading-i-choose-you-sass">I choose you, Sass!</h1>
<p>I had to make a difficult decision to move from Stylus to another preprocessor. I chose Sass for a number of reasons.</p>
<p>Firstly, as I mentioned, it is the most popular of them all. I'd always been put off by its ugly sibling, SCSS, and I had no idea what the difference was.</p>
<p>But SASS is great. It is very similar to Stylus, except for the use of colons and syntax strictness. It has some of the same drawbacks as Stylus, such as delayed support for new CSS features. However, it wasn't hard at all to migrate most of the custom mixins to Sass.</p>
<p>The IDE plugins are well-maintained and the community is huge. I'm confident I won't be forced to switch to anything else for years to come.</p>
<h1 id="heading-what-do-i-miss">What do I miss</h1>
<p>There are still a couple of features that I really liked in Stylus that I would like to see implemented in SASS.</p>
<h2 id="heading-hashes">Hashes</h2>
<p>The most painful are the <strong>hash</strong> objects. In Stylus it was a piece of cake:</p>
<pre><code class="lang-scss"><span class="hljs-comment">/** Stylus **/</span>

foo = {
  bar: hi,
  baz: hey
}

foo.baz
// =&gt; hey

foo[baz]
// =&gt; hey

foo[<span class="hljs-string">'baz'</span>]
// =&gt; hey
</code></pre>
<p>Not so in Sass. It has <strong>maps</strong> that are limited compared to Stylus hashes.</p>
<pre><code class="lang-scss"><span class="hljs-variable">$foo</span>: (<span class="hljs-string">"bar"</span>: <span class="hljs-string">"hi"</span>, <span class="hljs-string">"baz"</span>: <span class="hljs-string">"hey"</span>)

map.get(<span class="hljs-variable">$foo</span>, <span class="hljs-string">"baz"</span>)

// =&gt; hey
</code></pre>
<p>Worst of all, Sass requires maps to be written on a single line. I got used to creating hashes for colors with both light and dark mode variants, and that was no longer possible with Sass. Ultimately, I ended up putting the multi-line map in a <code>.scss</code> file and importing it into a <code>.sass</code> file.</p>
<h2 id="heading-imports-and-files-structure">Imports and files structure</h2>
<p>I like being able to import my styles into a single file since I use Webpack as a module bundler for most of my projects. When I was using Stylus, I was used to a certain directory structure that I couldn't reproduce with Sass:</p>
<p>There were some main directories (<code>base</code>, <code>layout</code>, <code>partials</code> etc.) containing subdirectories named after the function or purpose.</p>
<pre><code class="lang-plaintext">├── styles
│   ├── base
│   │   ├── color
│   │   ├── reset
│   │   └── typography
│   │
│   ├── layout
│   │   ├── body
│   │   ├── footer
│   │   └── navbar
│   │
│   ├── partials
│   │   ├── container
│   │   ├── flash
│   │   └── form
│   │       ├── checkbox
│   │       └── input
.   .
.   .
.   .
</code></pre>
<p>Each subdirectory contained another subdirectory or an <code>index.styl</code> file. All I had to do was to import all the files in the main directories using a wildcard. This represents a pattern called <strong>screaming architecture</strong>, where the names of the folders represent the function of the files in them.</p>
<pre><code class="lang-scss"><span class="hljs-comment">/** Stylus **/</span>

<span class="hljs-keyword">@import</span> <span class="hljs-string">"./base/**/index.styl"</span>
<span class="hljs-keyword">@import</span> <span class="hljs-string">"./layout/**/index.styl"</span>
<span class="hljs-keyword">@import</span> <span class="hljs-string">"./partials/**/index.styl"</span>
</code></pre>
<p>No explicit import was required. Unfortunately, this is only partially possible in Sass, so now I have to explicitly import each file I create. I prefer to keep my styles separate and organized. People who do not separate their Sass files into specific directories are beyond my comprehension although I know that many are quite happy about it.</p>
<p>I had to adapt another way of storing stylesheets that is ultimately very similar to the original, with an extra step of manually importing each newly added file.</p>
<pre><code class="lang-plaintext">├── styles
│   ├── base
│   │   ├── _color.sass
│   │   ├── _reset.sass
│   │   ├── _typography.sass
│   │   └── all.sass
│   │
│   ├── layout
│   │   ├── _body.sass
│   │   ├── _footer.sass
│   │   ├── _navbar.sass
│   │   └── all.sass
│   │
│   ├── partials
│   │   ├── _container.sass
│   │   ├── _flash.sass
│   │   └── form
│   │   │   ├── _checkbox.sass
│   │   │   └── _input.sass
│   │   │
.   .   └── all.sass
.   .
</code></pre>
<pre><code class="lang-scss"><span class="hljs-keyword">@import</span> <span class="hljs-string">'base/all'</span>
<span class="hljs-keyword">@import</span> <span class="hljs-string">'layout/all'</span>
<span class="hljs-keyword">@import</span> <span class="hljs-string">'partials/all'</span>
</code></pre>
<h2 id="heading-operators-and-built-in-functions">Operators and built-in functions</h2>
<p>Compared to Stylus, Sass has fewer built-in functions and mathematical operations. Also, interpolation is more cumbersome in Sass, and all the at-rules are less straightforward. But that may just be a matter of habit.</p>
<p>Noteworthy are the loops: Sass has <code>@each</code> and <code>@for</code>. I kind of hate it. The stylus <code>for</code> is much more versatile.</p>
<pre><code class="lang-scss"><span class="hljs-comment">/** Sass **/</span>

<span class="hljs-variable">$colors</span>: <span class="hljs-string">"red"</span>, <span class="hljs-string">"green"</span>, <span class="hljs-string">"blue"</span>;

<span class="hljs-keyword">@each</span> <span class="hljs-variable">$color</span> in <span class="hljs-variable">$colors</span>
    .#{<span class="hljs-variable">$color</span>}
        <span class="hljs-attribute">color</span>: <span class="hljs-variable">$color</span>


/** Stylus **/

color = ( red green blue )

for color in colors
    .{color}
        color: color
</code></pre>
<p>As for the range:</p>
<pre><code class="lang-scss"><span class="hljs-comment">/** Sass **/</span>

<span class="hljs-keyword">@for</span> <span class="hljs-variable">$i</span> from <span class="hljs-number">1</span> through <span class="hljs-number">3</span> 
  .branch:nth-child(<span class="hljs-number">3</span>n + #{<span class="hljs-variable">$i</span>})
    <span class="hljs-attribute">margin-left</span>: #{<span class="hljs-variable">$i</span> * <span class="hljs-number">10</span>}px

/** Stylus **/ 

for i in (<span class="hljs-number">1</span>..<span class="hljs-number">3</span>)
    .branch:nth-child(<span class="hljs-number">3</span>n + {i})
        margin-left: {i * <span class="hljs-number">10</span>}px
</code></pre>
<p>Other than that, I think the sass is great and I have gotten completely used to it by now.</p>
]]></content:encoded></item></channel></rss>