<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/css/</id>
  <link href="https://www.endpointdev.com/blog/tags/css/"/>
  <link href="https://www.endpointdev.com/blog/tags/css/" rel="self"/>
  <updated>2025-08-25T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Using esbuild and pnpm to Set Up Frontend Asset Bundling in an ASP.NET Core Web App</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2025/08/using-esbuild-to-set-up-frontend-asset-bundling-in-an-asp-net-core-web-app/"/>
      <id>https://www.endpointdev.com/blog/2025/08/using-esbuild-to-set-up-frontend-asset-bundling-in-an-asp-net-core-web-app/</id>
      <published>2025-08-25T00:00:00+00:00</published>
      <author>
        <name>Kevin Campusano</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2025/08/using-esbuild-to-set-up-frontend-asset-bundling-in-an-asp-net-core-web-app/mountains.webp&#34; alt=&#34;Layers of mountains are exposed by light with a red tint&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen, 2025. --&gt;
&lt;p&gt;Recently we had to build an admin dashboard on ASP.NET Core. We decided to hit the ground running by looking for a template online. Luckily, we found a very cool one from Start Bootstrap that &lt;a href=&#34;https://startbootstrap.com/template/sb-admin&#34;&gt;met our requirements&lt;/a&gt;. It was built using &lt;a href=&#34;https://getbootstrap.com/&#34;&gt;Bootstrap&lt;/a&gt;, had nice styling, and included examples of graphs, tables, and basic common pages like login and registration.&lt;/p&gt;
&lt;p&gt;However, integrating the template into an ASP.NET Core web app was a bit involved. The template uses tools like &lt;a href=&#34;https://pugjs.org/api/getting-started.html&#34;&gt;Pug&lt;/a&gt; and &lt;a href=&#34;https://sass-lang.com/documentation/syntax/&#34;&gt;Sass/SCSS&lt;/a&gt;, which are not supported out of the box by ASP.NET. So some work had to be done to properly integrate it.&lt;/p&gt;
&lt;p&gt;We ended up with a nice approach for handling frontend asset bundling using &lt;a href=&#34;https://pnpm.io/&#34;&gt;pnpm&lt;/a&gt; and &lt;a href=&#34;https://esbuild.github.io/&#34;&gt;esbuild&lt;/a&gt;, with support for JavaScript and Sass.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can find a codebase that uses the setup we&amp;rsquo;ll be discussing here on &lt;a href=&#34;https://github.com/megakevin/razor-start-bootstrap-admin&#34;&gt;Github&lt;/a&gt;. It&amp;rsquo;s an empty ASP.NET Core Razor Pages project that implements Start Bootrap&amp;rsquo;s admin template. Feel free to review it alongside this article and/or use it for your own projects.&lt;/p&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;We&amp;rsquo;ve also &lt;a href=&#34;https://www.nuget.org/packages/EndPointDev.RazorEsbuildProjectTemplate&#34;&gt;uploaded to NuGet&lt;/a&gt; a template for an empty ASP.NET Core Razor Pages web app that has implemented the esbuild-based frontend asset bundling.&lt;/p&gt;&lt;/blockquote&gt;
&lt;h3 id=&#34;installing-pnpm-and-the-necessary-packages&#34;&gt;Installing pnpm and the necessary packages&lt;/h3&gt;
&lt;p&gt;First of all we need to have the &lt;a href=&#34;https://dotnet.microsoft.com/en-us/download&#34;&gt;.NET framework installed&lt;/a&gt;. We also need to &lt;a href=&#34;https://nodejs.org/en/download&#34;&gt;install Node.js&lt;/a&gt; and &lt;a href=&#34;https://pnpm.io/installation&#34;&gt;the pnpm package manager&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ dotnet --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9.0.302
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ node --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;v22.18.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pnpm --version
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;10.14.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once we have those, we need a Razor Pages project to apply the changes to. For our purposes, I&amp;rsquo;m going to assume we&amp;rsquo;re starting off with a fresh project, created using something like &lt;code&gt;dotnet new webapp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With that out of the way, we can create a &lt;code&gt;package.json&lt;/code&gt; file in the root of our project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pnpm init
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Wrote to /path/to/code/package.json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;demo&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;index.js&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;echo \&amp;#34;Error: no test specified\&amp;#34; &amp;amp;&amp;amp; exit 1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;keywords&amp;#34;&lt;/span&gt;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ISC&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;packageManager&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm@10.14.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can adjust the resulting &lt;code&gt;package.json&lt;/code&gt; to better reflect our project. Maybe remove the &lt;code&gt;main&lt;/code&gt; and &lt;code&gt;scripts.test&lt;/code&gt; settings, which we don&amp;rsquo;t need. Maybe also set a &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In any case, now that we have this, we can install the Node.js packages that we need. I mentioned that we were going to use esbuild and SCSS so let&amp;rsquo;s install those as dev dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pnpm add esbuild esbuild-sass-plugin sass@1.78.0 --save-dev
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Packages: +41
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++++++++++++++++++++++++++++++++++++++++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Progress: resolved 103, reused 50, downloaded 0, added 41, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;devDependencies:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ esbuild 0.25.9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ esbuild-sass-plugin 3.3.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ sass 1.78.0 (1.90.0 is available)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;╭ Warning ───────────────────────────────────────────────────────────────────────────────────╮
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│                                                                                            │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   Ignored build scripts: esbuild.                                                          │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   Run &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm approve-builds&amp;#34;&lt;/span&gt; to pick which dependencies should be allowed to run scripts.   │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│                                                                                            │
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;╰────────────────────────────────────────────────────────────────────────────────────────────╯
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Done in 2.5s using pnpm v10.14.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve pinned the version of the &lt;code&gt;sass&lt;/code&gt; package to &lt;code&gt;1.78.0&lt;/code&gt; in order to work around some compatibility warnings with Bootstrap&amp;rsquo;s stylesheets. You may or may not need to do this in your own projects.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;We have to address the warning message and allow &lt;code&gt;esbuild&lt;/code&gt; to run scripts. Running &lt;code&gt;pnpm approve-builds&lt;/code&gt; and selecting &lt;code&gt;esbuild&lt;/code&gt; (by pressing either the &amp;ldquo;Space&amp;rdquo; or &amp;ldquo;a&amp;rdquo; keys) takes care of that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pnpm approve-builds
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;✔ Choose which packages to build (Press &amp;lt;space&amp;gt; to &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;select&lt;/span&gt;, &amp;lt;a&amp;gt; to toggle all, &amp;lt;i&amp;gt; to invert selection) · esbuild
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;✔ The next packages will now be built: esbuild.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Do you approve? (y/N) · &lt;span style=&#34;color:#038&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;node_modules/.pnpm/esbuild@0.25.9/node_modules/esbuild: Running postinstall script, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt; in 40ms&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With that, the &lt;code&gt;package.json&lt;/code&gt; file should be looking like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./package.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;demo&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;keywords&amp;#34;&lt;/span&gt;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ISC&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;packageManager&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm@10.14.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;devDependencies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;esbuild&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;^0.25.9&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;esbuild-sass-plugin&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;^3.3.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;sass&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.78.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There should also be a new &lt;code&gt;pnpm-workspace.yaml&lt;/code&gt; file that contains the setting for the approval we gave for &lt;code&gt;esbuild&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# ./pnpm-workspace.yaml&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;onlyBuiltDependencies&lt;/span&gt;:&lt;span style=&#34;color:#bbb&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bbb&#34;&gt;  &lt;/span&gt;- esbuild&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this particular example, we&amp;rsquo;re adapting Start Bootrap&amp;rsquo;s admin template, so we&amp;rsquo;re going to install the packages that it needs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pnpm add @fortawesome/fontawesome-free bootstrap chart.js jquery simple-datatables
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Packages: +9
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+++++++++
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Progress: resolved 112, reused 59, downloaded 0, added 9, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dependencies:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ @fortawesome/fontawesome-free 7.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ bootstrap 5.3.7
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ chart.js 4.5.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ jquery 3.7.1
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;+ simple-datatables 10.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Done in 2.9s using pnpm v10.14.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These are the ones we need for this project but of course, in your own projects you can install whatever you want.&lt;/p&gt;
&lt;h3 id=&#34;authoring-javascript-and-scss-source-files&#34;&gt;Authoring JavaScript and SCSS source files&lt;/h3&gt;
&lt;p&gt;Now that we have the Node.js part of the project set up, we need a place where we can put our JavaScript and SCSS files. For that, we created two new directories: &lt;code&gt;JavaScript&lt;/code&gt; and &lt;code&gt;Stylesheets&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since we&amp;rsquo;re adapting Start Bootrap&amp;rsquo;s admin template, we copied all its SCSS files into the &lt;code&gt;Stylesheets&lt;/code&gt; directory and put its JavaScript into the &lt;code&gt;JavaScript&lt;/code&gt; directory. It all ended up looking like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+├── JavaScript
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   └── site.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; ├── Pages
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+├── Stylesheets
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   ├── layout
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   ├── navigation
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   ├── plugins
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   ├── variables
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   ├── _global.scss
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   ├── site.scss
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+│   └── _variables.scss
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; ├── wwwroot
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; │   ├── css
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; │   ├── js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; │   └── favicon.ico
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ├── appsettings.Development.json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ├── appsettings.json
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+├── package.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+├── pnpm-lock.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+├── pnpm-workspace.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; ├── Program.cs
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ├── RazorStartBootstrapAdmin.csproj
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; └── README.md
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course, the specific file contents will be different in your own projects, but the take home message is that these two new directories are meant for the source files of your frontend assets.&lt;/p&gt;
&lt;h3 id=&#34;bundling-frontend-assets-with-esbuild&#34;&gt;Bundling frontend assets with esbuild&lt;/h3&gt;
&lt;p&gt;With that, we have the NodeJS package management ready, the tools we need, and a project directory structure that supports writing JavaScript and SCSS.&lt;/p&gt;
&lt;p&gt;Now we need to put together an &lt;code&gt;esbuild.config.mjs&lt;/code&gt; file that processes these files and produces the bundles. Here it is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./esbuild.config.mjs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; * as esbuild from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;esbuild&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { sassPlugin } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;esbuild-sass-plugin&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// SCSS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// This is a list of all the SCSS files that we want to bundle and their
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// respective output files. In this project&amp;#39;s case, we have only one.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// We put the resulting file under ./wwwroot/css. &amp;#34;wwwroot&amp;#34; is the default
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// location used to expose files to the public in ASP.NET Core Razor Pages
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// projects.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; scssFiles = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./Stylesheets/site.scss&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/css/site.css&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Here we tell esbuild to take the entry SCSS files as input and produce CSS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// files ready to be interpreted by a browser. Since the source files are SCSS,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// we use the esbuild-sass-plugin plugin to translate them into CSS.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;scssFiles.forEach(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; file =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; esbuild.build({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryPoints: [file.entry],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bundle: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sourcemap: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Some libraries, like Bootstrap, include icons as woff and woff2 font
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// files. To handle this, we specify this loader setting. Instructing
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// esbuild to use the &amp;#34;file&amp;#34; loader, when it encounters such files. The
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// &amp;#34;file&amp;#34; loader takes care of copying the files into the output
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// location.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// More info: https://esbuild.github.io/content-types/#file
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    loader: { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;.woff&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;.woff2&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    outfile: file.outfile,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    plugins: [sassPlugin()]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// JavaScript
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Similar to the stylesheet files, for JavaScript we also declare a list of the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// files that we want to bundle.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; jsFiles = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./JavaScript/site.js&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/js/site.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Bundling here is simpler than SCSS because we don&amp;#39;t need custom loaders or
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// plugins. Just specify entry points and output files and esbuild knows what to
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// do.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;jsFiles.forEach(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; file =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; esbuild.build({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryPoints: [file.entry],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bundle: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sourcemap: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    outfile: file.outfile,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;One important thing to note here is that with &lt;code&gt;esbuild&lt;/code&gt;, we can safely use JavaScript modules and &lt;code&gt;import&lt;/code&gt; statements for both JavaScript and SCSS. This means that our frontend logic and styling rules can be broken up into any number of files, forming a tree of dependencies through &lt;code&gt;import&lt;/code&gt; statements. We need only to specify the root files, or entry points, and &lt;code&gt;esbuild&lt;/code&gt; takes care of building a complete and self-contained bundle. Not really a revolutionary idea in the grand scheme of things, but not always a given when working with JavaScript on the browser.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;With this, we can trigger the bundling process: &lt;code&gt;node esbuild.config.mjs&lt;/code&gt;. However, it&amp;rsquo;d be nice to have it better integrated with a typical .NET development flow. For that, we can add the following under &lt;code&gt;scripts&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./package.json
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;build&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;node esbuild.config.mjs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This allows us to run &lt;code&gt;pnpm run build&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Finally, we can have this command run automatically as part of &lt;code&gt;dotnet build&lt;/code&gt; if we add the following to our &lt;code&gt;.csproj&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ./RazorStartBootstrapAdmin.csproj --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Project&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Sdk=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Microsoft.NET.Sdk.Web&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Target&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;BundleFrontendAssets&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;BeforeTargets=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Build&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Exec&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Command=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm install&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Exec&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Command=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm run build&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All this will result in our build process producing &lt;code&gt;./wwwroot/css/site.css&lt;/code&gt;, and &lt;code&gt;./wwwroot/js/site.js&lt;/code&gt; bundles. Which we can include in our &lt;code&gt;.cshtml&lt;/code&gt; files like we would any other &lt;code&gt;.js&lt;/code&gt; or &lt;code&gt;.css&lt;/code&gt; file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ./Pages/Shared/_Layout.cshtml --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;~/css/site.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;asp-append-version&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;~/js/site.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;asp-append-version&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;importing-libraries-as-modules&#34;&gt;Importing libraries as modules&lt;/h3&gt;
&lt;p&gt;One interesting aspect to note is that, with &lt;code&gt;esbuild&lt;/code&gt;, we are using &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules&#34;&gt;JavaScript modules&lt;/a&gt; with &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_features_into_your_script&#34;&gt;&lt;code&gt;import&lt;/code&gt; statements&lt;/a&gt;. This is particularly important for libraries, since some of them won&amp;rsquo;t necessarily support being included as JavaScript modules by default or in an obvious manner.&lt;/p&gt;
&lt;p&gt;Our &lt;code&gt;site.js&lt;/code&gt; demonstrates this. For example, it loads Bootstrap and the Font Awesome icons using the following statements:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./JavaScript/site.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;bootstrap&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;@fortawesome/fontawesome-free/js/all&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This makes it so any page that includes &lt;code&gt;site.js&lt;/code&gt; will also have Bootstrap and the Font Awesome icons available.&lt;/p&gt;
&lt;p&gt;To get the same for something like JQuery, for example, the strategy is a little different:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./JavaScript/site.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; jQuery from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;jquery&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;window&lt;/span&gt;.$ = &lt;span style=&#34;color:#038&#34;&gt;window&lt;/span&gt;.jQuery = jQuery;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A similar scenario happens with the stylesheets. For SCSS, we have to use the &lt;code&gt;@import&lt;/code&gt; statement. Our &lt;code&gt;site.scss&lt;/code&gt; contains examples of this. Here&amp;rsquo;s how we load Bootstrap&amp;rsquo;s CSS, for instance:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scss&#34; data-lang=&#34;scss&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./Stylesheets/site.scss
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;@import&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;bootstrap/scss/bootstrap.scss&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In your projects, you&amp;rsquo;ll encounter libraries with varying levels of support for JavaScript modules, and you will have to adapt accordingly, depending on the library itself and how you want to use it.&lt;/p&gt;
&lt;h3 id=&#34;importing-libraries-via-html-tags&#34;&gt;Importing libraries via HTML tags&lt;/h3&gt;
&lt;p&gt;There are also some libraries that only work via traditional &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags. For these, you might want to have &lt;code&gt;esbuild&lt;/code&gt; copy files directly from the &lt;code&gt;node_modules&lt;/code&gt; directory into &lt;code&gt;wwwroot&lt;/code&gt;, without any preprocessing. You could use something like this in your &lt;code&gt;esbuild.config.mjs&lt;/code&gt; file for that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// ./esbuild.config.mjs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Raw files
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; rawFiles = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./node_modules/path/to/package.js&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/lib/package.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./node_modules/path/to/package.css&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/lib/package.css&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rawFiles.forEach(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; file =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; esbuild.build({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryPoints: [file.entry],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bundle: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sourcemap: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    loader: { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.*&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;copy&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    outfile: file.outfile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can include the files from &lt;code&gt;wwwroot&lt;/code&gt; using the appropriate &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot;&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;h3 id=&#34;summary&#34;&gt;Summary&lt;/h3&gt;
&lt;p&gt;So, in the end, using &lt;code&gt;esbuild&lt;/code&gt; and &lt;code&gt;pnpm&lt;/code&gt; to set up frontend asset bundling in an ASP.NET Core web app is perfectly doable and can be summarized like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Install NodeJS and &lt;code&gt;pnpm&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;package.json&lt;/code&gt; file with &lt;code&gt;pnpm init&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install &lt;code&gt;esbuild&lt;/code&gt; as a dev dependency with &lt;code&gt;pnpm add esbuild --save-dev&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Also make sure to run &lt;code&gt;pnpm approve-builds&lt;/code&gt; to allow &lt;code&gt;esbuild&lt;/code&gt; to run scripts&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install any additional preprocessor that you might need like &lt;code&gt;sass&lt;/code&gt; with &lt;code&gt;esbuild-sass-plugin&lt;/code&gt;, etc.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create &lt;code&gt;JavaScript&lt;/code&gt; and &lt;code&gt;Stylesheets&lt;/code&gt; directories and put your source files in them&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add an &lt;code&gt;esbuild.config.mjs&lt;/code&gt; file that can bundle your assets&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Include the asset bundling step as part of the &lt;code&gt;dotnet build&lt;/code&gt; command&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your package.json should end up looking something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;description&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;scripts&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Register this so that esbuild can be called with &amp;#34;pnpm run build&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;build&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;node esbuild.config.mjs&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;keywords&amp;#34;&lt;/span&gt;: [],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;author&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;ISC&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;dependencies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Add your dependencies here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;devDependencies&amp;#34;&lt;/span&gt;: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;esbuild&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;0.25.9&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// Add other preprocessors and plugins here, like:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;esbuild-sass-plugin&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;3.3.1&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;#34;sass&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1.78.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here&amp;rsquo;s an example of an &lt;code&gt;esbuild.config.mjs&lt;/code&gt; that covers the common scenarios:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; * as esbuild from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;esbuild&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; { sassPlugin } from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;esbuild-sass-plugin&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// SCSS
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; scssFiles = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./Stylesheets/site.scss&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/css/site.css&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// Add other stylesheet files here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scssFiles.forEach(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; file =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; esbuild.build({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryPoints: [file.entry],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bundle: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sourcemap: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    loader: { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;.woff&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;.woff2&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;file&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    outfile: file.outfile,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    plugins: [sassPlugin()]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// JavaScript
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; jsFiles = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./JavaScript/site.js&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/js/site.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// Add other JavaScript files here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jsFiles.forEach(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; file =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; esbuild.build({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryPoints: [file.entry],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bundle: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sourcemap: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    outfile: file.outfile,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Raw files
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; rawFiles = [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./node_modules/path/to/package.js&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/lib/package.js&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { entry: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./node_modules/path/to/package.css&amp;#39;&lt;/span&gt;, outfile: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;./wwwroot/lib/package.css&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// Add other library files here.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rawFiles.forEach(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;async&lt;/span&gt; file =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;await&lt;/span&gt; esbuild.build({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    entryPoints: [file.entry],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    bundle: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    sourcemap: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    loader: { &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.*&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;copy&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    outfile: file.outfile
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the addition that the &lt;code&gt;.csproj&lt;/code&gt; file needs in order to bundle the frontend assets during &lt;code&gt;dotnet build&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-xml&#34; data-lang=&#34;xml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Project&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Sdk=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Microsoft.NET.Sdk.Web&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Target&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Name=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;BundleFrontendAssets&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;BeforeTargets=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Build&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Exec&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Command=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm install&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;Exec&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;Command=&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;pnpm run build&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/Target&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With that, you&amp;rsquo;re free to add the bundles and raw files in your pages using traditional methods like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;~/css/site.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;asp-append-version&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;~/lib/package.css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;asp-append-version&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and&amp;hellip;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;~/js/site.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;asp-append-version&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;~/lib/package.js&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;asp-append-version&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you create more entrypoint JavaScript and SCSS files, you have to remember to add them to their respective arrays in &lt;code&gt;esbuild.config.mjs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can add more packages using &lt;code&gt;pnpm add &amp;lt;package_name&amp;gt;&lt;/code&gt;. Just remember that they have to be imported by your JavaScript files as modules. If you need to add raw files, especially from libraries that don&amp;rsquo;t support being imported as JavaScript modules, the &lt;code&gt;esbuild.config.mjs&lt;/code&gt; file also supports that thanks to the &amp;ldquo;raw files&amp;rdquo; section. These raw files can be loaded normally via &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; HTML tags.&lt;/p&gt;
&lt;p&gt;All right, that&amp;rsquo;s it for now. We&amp;rsquo;ve seen how to integrate &lt;code&gt;esbuild&lt;/code&gt; with ASP.NET Core in order to setup a basic frontend asset bundling process. We did that through adapting Smart Bootstrap&amp;rsquo;s free admin template into an ASP.NET Core Razor Pages web app project — a project that&amp;rsquo;s up on &lt;a href=&#34;https://github.com/megakevin/razor-start-bootstrap-admin&#34;&gt;GitHub&lt;/a&gt;. We saw how to organize source files in our repo, a basic &lt;code&gt;esbuild&lt;/code&gt; config script that handles the most common scenarios, and how to handle a few different cases when it comes to including NodeJS packages into our apps.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Comparison of Lightweight CSS Frameworks</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2022/01/comparison-of-lightweight-css-frameworks/"/>
      <id>https://www.endpointdev.com/blog/2022/01/comparison-of-lightweight-css-frameworks/</id>
      <published>2022-01-13T00:00:00+00:00</published>
      <author>
        <name>Seth Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2022/01/comparison-of-lightweight-css-frameworks/house-frame.jpg&#34; alt=&#34;The frame of a house in front of a mountain range&#34;&gt;&lt;/p&gt;
&lt;!-- Photo by Seth Jensen --&gt;
&lt;p&gt;Several months ago I was building a new website and needed a CSS framework. There are many new CSS frameworks around now, so I decided to do several small trial runs and compare them to find the most fitting for our site.&lt;/p&gt;
&lt;p&gt;Initially I tried using Foundation, which this site is built on, but I ran into a problem: Foundation and other popular frameworks are powerful, but they have more features than I needed, and they take up too much disk space for a modest website. Foundation is about 6000 lines long and 200kB unminified. It can be shrunk by removing components you don&amp;rsquo;t need, but the time it takes to slim a large CSS framework down to your needs can be more than it&amp;rsquo;s worth, especially if you want to change any styling.&lt;/p&gt;
&lt;p&gt;Instead of adapting a larger framework to my needs, I looked into lightweight CSS frameworks. These aim to provide boilerplate components, better styling for buttons, forms, tables, and the like, all at the cost of very little disk space.&lt;/p&gt;
&lt;p&gt;I like to modify the source CSS as needed, so all of the sizes I list will be unzipped and unminified. They are also from my brief real-world testing on one machine, so your mileage may vary.&lt;/p&gt;
&lt;h3 id=&#34;bulma&#34;&gt;Bulma&lt;/h3&gt;
&lt;p&gt;Bulma looked very attractive at first. It has sleek, modern design and is quite popular, with a good-sized community for support. But for our site, it was still too big. I only used a few components and layout helpers, a fraction of its 260kB — around 50kB bigger than Foundation, in my tests!&lt;/p&gt;
&lt;h3 id=&#34;minicss&#34;&gt;mini.css&lt;/h3&gt;
&lt;p&gt;mini.css had some great things going for it, but got pushed out by even smaller options which I&amp;rsquo;ll cover shortly. It took up about 46kB with all the bells and whistles.&lt;/p&gt;
&lt;p&gt;The use of flex is a bonus, but it&amp;rsquo;s a little too style agnostic for the website I was working on; I would have overridden a lot of its styling, making the overhead size even larger.&lt;/p&gt;
&lt;p&gt;It has options for using SCSS or CSS variables, which I always like to see. I prefer SCSS&amp;rsquo;s added features and variables, but if you would rather use vanilla CSS, mini.css has a plain option using CSS variables, which I don&amp;rsquo;t see too often.&lt;/p&gt;
&lt;h3 id=&#34;purecss&#34;&gt;Pure.css&lt;/h3&gt;
&lt;p&gt;Pure.css offers similar features to the other frameworks on this list, and weighing in at around 17kB, it competes well in size. However, I wasn&amp;rsquo;t a big fan of its look, and with some odd omissions, notably, the absence of a &lt;code&gt;container&lt;/code&gt; class for horizontally centering content, it was edged out by the competition.&lt;/p&gt;
&lt;h3 id=&#34;skeleton&#34;&gt;Skeleton&lt;/h3&gt;
&lt;p&gt;Skeleton has very clean styling and a good selection of minimal components. It&amp;rsquo;s tiny, weighing in at 12kB. Unfortunately, it hasn&amp;rsquo;t had a release since 2014, and uses &lt;code&gt;float&lt;/code&gt; instead of Flexbox, which took it out of the running for building a more modern site.&lt;/p&gt;
&lt;h3 id=&#34;milligram&#34;&gt;Milligram&lt;/h3&gt;
&lt;p&gt;Milligram feels like a spiritual successor to Skeleton: It covers a similar scope, and has a simple, clean design reminiscent of Skeleton&amp;rsquo;s. In lieu of using classes, it usually applies styling directly to HTML tags. This is a choice I like, since I don&amp;rsquo;t follow the Tailwind CSS approach of creating websites purely in HTML, with agnostic classes applied to the layout.&lt;/p&gt;
&lt;p&gt;It also has an SCSS offering, so it&amp;rsquo;s easy to drop components you don&amp;rsquo;t want, making it even tinier!&lt;/p&gt;
&lt;p&gt;The size and simplicity of Milligram made it win the bid. It has worked quite well, providing just enough framework to be useful for small websites, but getting out of the way so that you can do your own styling.&lt;/p&gt;
&lt;h3 id=&#34;making-the-most-of-your-lightweight-framework&#34;&gt;Making the most of your lightweight framework&lt;/h3&gt;
&lt;p&gt;Hopefully this post will give you an idea of what each of these frameworks is like, but the best way to test them is by trying them yourself! These five were fairly quick to spin up and test out on the website I was working on, and doing the same will give you the best idea of what your website needs.&lt;/p&gt;
&lt;p&gt;With frameworks that are only a few kilobytes, you can also read through the entire source. I tried to look through enough of each framework&amp;rsquo;s CSS files to become familiar with its way of doing things. This eased the whole website-building process, and will help you find a framework that matches your style of web development.&lt;/p&gt;
&lt;p&gt;Also see my colleague Afif&amp;rsquo;s article &lt;a href=&#34;/blog/2021/12/responsive-website-with-tailwindcss/&#34;&gt;Building responsive websites with Tailwind CSS&lt;/a&gt; for an in-depth look at Tailwind CSS.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Building responsive websites with Tailwind CSS</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2021/12/responsive-website-with-tailwindcss/"/>
      <id>https://www.endpointdev.com/blog/2021/12/responsive-website-with-tailwindcss/</id>
      <published>2021-12-03T00:00:00+00:00</published>
      <author>
        <name>Afif Sohaili</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2021/12/responsive-website-with-tailwindcss/banner.jpg&#34; alt=&#34;Sunset over lake and mountains&#34;&gt;&lt;/p&gt;
&lt;!-- photo by Seth Jensen --&gt;
&lt;p&gt;&lt;a href=&#34;https://tailwindcss.com/&#34;&gt;Tailwind CSS&lt;/a&gt; is a CSS framework, like Bootstrap, Bulma, and Foundation. However, Tailwind does things in a less conventional way when compared to traditional CSS frameworks. Instead of providing CSS classes based on components or functional roles (e.g. &lt;code&gt;.card&lt;/code&gt; or &lt;code&gt;.row&lt;/code&gt;), Tailwind only provides utility classes, in which each class does only one specific thing a CSS attribute usually does, such as &lt;code&gt;m-4&lt;/code&gt; for &lt;code&gt;margin: 1rem&lt;/code&gt; or &lt;code&gt;mt-8&lt;/code&gt; for &lt;code&gt;margin-top: 2rem&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In Bootstrap, one can simply apply the provided &lt;code&gt;.card&lt;/code&gt; CSS class to have a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; styled like a card the Bootstrap way. In Tailwind, the styles have to be constructed with a string of different atomic classes. E.g. the equivalent of a Bootstrap&amp;rsquo;s &lt;code&gt;.card&lt;/code&gt; would be something like &lt;code&gt;relative flex flex-col break-words bg-white bg-clip-border min-w-0 rounded border&lt;/code&gt;. Verbose, yes, but this gives flexibility for the developers to define the appearance of a &lt;code&gt;.card&lt;/code&gt; element themselves (e.g. there could be multiple variants of appearances of a &lt;code&gt;.card&lt;/code&gt;) without having to worry about overriding inherited/​cascading CSS classes, which are typically the cause of many CSS bugs in production.&lt;/p&gt;
&lt;h3 id=&#34;atomic-css&#34;&gt;Atomic CSS&lt;/h3&gt;
&lt;p&gt;The first thing most notice when developing with Tailwind is how wordy CSS class lists can get. It feels almost like using the &lt;code&gt;style=&amp;quot;&amp;quot;&lt;/code&gt; attribute to write CSS. In the traditional approach to CSS, suppose there are two elements with identical margins:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;card&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;block&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;rem&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;container&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;rem&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, we can see that margin is declared twice. Those duplicates are going to be a few extra bytes in the final CSS payload.&lt;/p&gt;
&lt;p&gt;With Tailwind, however, this is how the equivalent would be written:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;block m-4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;m-4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, both of the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;s are reusing the same class &lt;code&gt;m-4&lt;/code&gt;, which is provided out-of-the-box by Tailwind. This approach ensures that the project&amp;rsquo;s CSS does not grow, which is important for good user experience. Constructing the CSS of a page is a render-blocking task in a web page load. So, the bigger the CSS, the longer the wait time for a user to see something on the browser. Yes, the HTML payload will grow, but just by a little.&lt;/p&gt;
&lt;p&gt;One of the differences between using Tailwind CSS classes and using &lt;code&gt;style&lt;/code&gt; attribute is that the latter cannot be used to style pseudoclasses (e.g. &lt;code&gt;:hover&lt;/code&gt;, &lt;code&gt;:disabled&lt;/code&gt;). With CSS classes, that is achievable, but there are special prefixes that Tailwind provides for each of the variants to take effect.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- margin: 1rem by default, margin: 2rem on hover --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;m-4 hover:m-8&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- white background by default, light gray background when disabled --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;input&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;bg-white disabled:bg-gray-100&amp;#34;&lt;/span&gt;/&amp;gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Keep in mind that not all variants/​pseudoclasses are supported by default, as this would make the development output of a Tailwind CSS file really big to cater all of the possible variants. To have them supported, it has to be configured inside the project&amp;rsquo;s &lt;code&gt;tailwind.config.js&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// tailwind.config.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;module.exports = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  variants: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    extend: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      backgroundColor: [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;active&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;      borderColor: [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;focus-visible&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;first&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;      textColor: [&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;visited&amp;#39;&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or, if the project is on Tailwind CSS v2.1+, the developers can enable Just-in-Time mode, which grants access to all variants out-of-the-box while also being more functional in development mode.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&#34;https://tailwindcss.com/docs/just-in-time-mode&#34;&gt;Just-in-Time mode&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h3 id=&#34;shaking-off-the-unused-css&#34;&gt;Shaking off the unused CSS&lt;/h3&gt;
&lt;p&gt;By default, Tailwind will be loading the whole Tailwind CSS project files, with CSS declarations on almost every possible CSS rule. There are a lot in there that a developer might never use. To put that into context, there are 105 different values just for grid and flexbox gaps. Most projects aren&amp;rsquo;t likely to use them all, so Tailwind needs a way to remove the unused CSS when generating the final CSS build for production use.&lt;/p&gt;
&lt;p&gt;This is where PurgeCSS comes in. PurgeCSS is a plugin that analyzes all CSS, HTML, and JavaScript files in the project and removes unused CSS declarations from the final build. This tool is available as a PostCSS, Webpack, Gulp, Grunt, or Gatsby plugin.&lt;/p&gt;
&lt;p&gt;Because PurgeCSS analyzes the project&amp;rsquo;s source code to find exact matches of a given CSS style, a CSS class cannot be used through string concatenations or PurgeCSS will not be able to detect that the given Tailwind class is used.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-react&#34; data-lang=&#34;react&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// SomeComponent.jsx
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; SomeComponent = (props) =&amp;gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;className&lt;/span&gt;={&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;text-&amp;#39;&lt;/span&gt; + props.color}&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Some text
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// &amp;lt;SomeComponent color=&amp;#39;gray-400&amp;#39;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// In this case, `text-gray-400` will be removed by PurgeCSS in the final CSS 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;// production build because it does not know that the component is using it.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;drying-it-up&#34;&gt;DRYing it up&lt;/h3&gt;
&lt;p&gt;Suppose we have two cards on the page and we want their appearance to be consistent. In the traditional CSS approach, both these two cards will just have the &lt;code&gt;.card&lt;/code&gt; CSS class, and the same styles would be applied to both of them. In Tailwind we can&amp;rsquo;t do that, however, and it doesn&amp;rsquo;t make sense to be repeating 7 or 8 or more different class names on both HTML elements on the page.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-react&#34; data-lang=&#34;react&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;const&lt;/span&gt; AppButton = () =&amp;gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;className&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;py-2 px-4 font-semibold rounded-lg shadow-md&amp;#39;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    I&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;&amp;#39;&lt;/span&gt;m a button
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// Just use &amp;lt;AppButton&amp;gt; everywhere and their appearances will be consistent
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;// No need to repeat the CSS classes for all three components
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;render(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Form&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;AppButton&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;AppButton&lt;/span&gt;/&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;AppButton&lt;/span&gt;/&amp;gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Form&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Therefore, Tailwind can be easier to implement in component-based frameworks, such as Vue or React. But even if you&amp;rsquo;re not using any of them and are just building a plain HTML file, Tailwind provides a way to compose these classes together by using &lt;code&gt;@apply&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@apply&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;py-2&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;px-4&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;font-semibold&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;rounded-lg&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;shadow-md&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;success&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;@apply&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;py-2&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;px-4&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;font-semibold&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;rounded-lg&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;shadow-md&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;text-white&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;bg-green-400&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, &lt;code&gt;.button&lt;/code&gt; and &lt;code&gt;.button.success&lt;/code&gt; classes will be available to us for reuse as in traditional CSS.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- py-2 px-4 font-semibold rounded-lg shadow-md gets applied when using &amp;#34;button&amp;#34; --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt;&amp;gt;I&amp;#39;m a button&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- py-2 px-4 font-semibold rounded-lg shadow-md text-white bg-green-400 gets applied --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;button success&amp;#34;&lt;/span&gt;&amp;gt;I&amp;#39;m a green button&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;building-a-responsive-page-using-tailwind&#34;&gt;Building a responsive page using Tailwind&lt;/h3&gt;
&lt;p&gt;Now let&amp;rsquo;s look at responsive design. Suppose we want to implement a page with a navigation bar, a sidebar, a content area, and a footer:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/12/responsive-website-with-tailwindcss/responsive-desktop.png&#34; alt=&#34;Layout with Tailwind CSS - desktop view&#34;&gt;&lt;/p&gt;
&lt;p&gt;And the sidebar and content area should collapse into one column on mobile devices, like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/12/responsive-website-with-tailwindcss/responsive-mobile.png&#34; alt=&#34;Layout with Tailwind CSS - mobile view&#34;&gt;&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s have the basic page layout:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;nav&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;p-4 bg-gray-100&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flex gap-2 justify-end&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;Home&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;About&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;Contact&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;nav&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flex flex-col&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;aside&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flex items-center justify-center p-4 bg-red-100&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Sidebar
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;aside&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;min-h-screen p-4 bg-green-100&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Sit eos nam quam nemo qui. Quas recusandae praesentium ratione incidunt sunt commodi labore Nemo nemo error molestias saepe ducimus? Porro reprehenderit voluptatibus nihil voluptate quia. Voluptatibus autem maiores vero?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Consectetur veniam voluptate esse amet debitis eius? Voluptatem officia quibusdam voluptates cum rerum Odio rem maiores laborum commodi cum. Nobis numquam quia nemo maiores repellendus error fuga Repellendus consequatur laudantium?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Elit vitae sit reprehenderit sit laboriosam Ratione iusto numquam corrupti ullam libero! Nisi veritatis facere repudiandae eos perspiciatis recusandae veritatis. Cupiditate temporibus repellat tempore optio numquam id! Perferendis maxime unde
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Dolor autem dolore tempora atque provident. Maxime quos ipsum porro non suscipit. Consectetur et perspiciatis perspiciatis illum quos Ab nostrum unde facere nemo mollitia, saepe ab? Vitae tempore hic accusamus
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      Elit labore odit error pariatur cupiditate Ex sequi accusantium maxime et vero Unde quo laboriosam illo ipsam modi eaque Delectus dolorem quas quidem reprehenderit fugiat! Exercitationem provident voluptatum perferendis ut.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;p&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;main&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;p-4 bg-yellow-100&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h5&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;font-bold&amp;#34;&lt;/span&gt;&amp;gt;Footer links&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;h5&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;Home&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;About&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;Contact&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tailwind official documentation recommends taking a mobile-first approach. Hence, all classes without any screen-size variants will be applied to all screen sizes. Tailwind then provides several screen-size variants such as &lt;code&gt;sm&lt;/code&gt;, &lt;code&gt;lg&lt;/code&gt;, &lt;code&gt;xl&lt;/code&gt;, and &lt;code&gt;2xl&lt;/code&gt; that can be used to control the appearance on specific screen sizes range.&lt;/p&gt;
&lt;p&gt;This is what we&amp;rsquo;re doing here. As you can see, we&amp;rsquo;re using flexbox layout to collapse all elements down to a single column.&lt;/p&gt;
&lt;h4 id=&#34;responsive-variants&#34;&gt;Responsive variants&lt;/h4&gt;
&lt;p&gt;Now, let&amp;rsquo;s add Tailwind&amp;rsquo;s responsive variants so that the page is responsive to screen sizes. In our case, what we would want is to have &lt;code&gt;aside&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; placed side-by-side when there&amp;rsquo;s enough real estate on the screen. To achieve that, we would need to switch the &lt;code&gt;flex-col&lt;/code&gt; class to &lt;code&gt;flex-row&lt;/code&gt; on bigger screen sizes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flex flex-col md:flex-row&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;aside&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;flex items-center justify-center p-4 bg-red-100 md:flex-none md:w-1/3 lg:w-1/4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- sidebar --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;aside&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;main&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;min-h-screen p-4 bg-green-100&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- main content --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;main&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;flex-col md:flex-row&lt;/code&gt; here does the trick for us. &lt;code&gt;md&lt;/code&gt; variants, by default, kick in when the screen width is at a minimum of 768px. At that point, our flexbox will change from the column layout to the row layout, displaying our &lt;code&gt;aside&lt;/code&gt; and &lt;code&gt;main&lt;/code&gt; elements side-by-side in one row. To better distribute the width, we specify &lt;code&gt;md:w-1/3&lt;/code&gt; and &lt;code&gt;lg:w-1/4&lt;/code&gt; classes to the sidebar. &lt;code&gt;w-1/3&lt;/code&gt; and &lt;code&gt;w-1/4&lt;/code&gt; sets the width of the elements to one-third and one-fourth of the parent container respectively. The &lt;code&gt;md&lt;/code&gt; and &lt;code&gt;lg&lt;/code&gt; variants both control at what screen sizes should Tailwind apply which styles.&lt;/p&gt;
&lt;iframe width=&#34;770&#34; height=&#34;434&#34; src=&#34;https://www.youtube.com/embed/M9Wj5dG_N6w&#34; title=&#34;YouTube video player&#34; frameborder=&#34;0&#34; allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture&#34; allowfullscreen&gt;&lt;/iframe&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;It can be a bit daunting to start, but once you get a handle on it, Tailwind CSS is a great option for rapidly building user interfaces with total control over the styles. Unlike other frameworks, Tailwind does not attempt to provide a default styling of any component, allowing every site that uses Tailwind to be truly unique from another.&lt;/p&gt;
&lt;p&gt;These responsive variants can be applied to any other CSS class from Tailwind, providing a powerful way to build responsive user interfaces. The very thin abstraction over CSS provides developers with a greater flexibility and control over the design while being a good constraint to guide the development process.&lt;/p&gt;
&lt;p&gt;Happy styling!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Catching CSS Regressions and Visual Bugs in Continuous Integration</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/"/>
      <id>https://www.endpointdev.com/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/</id>
      <published>2021-06-24T00:00:00+00:00</published>
      <author>
        <name>Afif Sohaili</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/banner.jpg&#34; alt=&#34;Blue patterns&#34;&gt;
&lt;a href=&#34;https://unsplash.com/photos/6elNtGvY2S0&#34;&gt;Photo&lt;/a&gt; by &lt;a href=&#34;https://unsplash.com/@macnicolae&#34;&gt;Alexandra Nicolae&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Many web projects nowadays are equipped to simulate real users and automatically test a real use case, but these end-to-end tests still have a weakness. Browser automation tools run tests by performing the interactions and assertions in the context of the DOM of the pages. That is very different from how humans use web applications, which is by looking at the user interface. Due to this, the tests’ definition of a “functional web app” differs from that of a real human.&lt;/p&gt;
&lt;p&gt;For example, let’s take a simple music player with two buttons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;One in green with a play icon, and&lt;/li&gt;
&lt;li&gt;One in red with a stop icon.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The HTML would look something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&amp;lt;!-- music player --&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;button is-red&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;icon icon-stop&amp;#34;&lt;/span&gt;/&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;button is-green&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;icon icon-play&amp;#34;&lt;/span&gt;/&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In our end-to-end tests, one would typically instruct the test to check:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If the expected classnames exist.&lt;/li&gt;
&lt;li&gt;If clicking the stop button stops the music.&lt;/li&gt;
&lt;li&gt;If clicking the play button plays the music.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If all of the above conditions were met, then the app is considered “functional”. However, the tests have no way to verify if the right colors are actually reflected on the buttons, or if the SVG icons on the button are properly loaded and shown to the users. Unfortunately, for a real user, both of these are very crucial in telling the user how the app functions. If the stylings for the buttons are not implemented or the SVG icons for the buttons fail to load, users will not have a clear indication on how the app works, and the app will &lt;em&gt;not&lt;/em&gt; be considered “functional” by real users, even though the functionalities of both buttons are wired correctly in the code.&lt;/p&gt;
&lt;p&gt;Web developers also frequently deal with styling regressions. This can happen due to the “cascading” characteristic of CSS: Badly scoped CSS values may affect other elements in unrelated areas unintentionally. Many times, styling regressions slip past even the end-to-end tests with browser automation because, again, end-to-end tests only verify that the app’s functionalities are wired together, but do not check if things appear the right way visually.&lt;/p&gt;
&lt;h3 id=&#34;visual-regression-testing-to-the-rescue&#34;&gt;Visual regression testing to the rescue&lt;/h3&gt;
&lt;p&gt;Visual regression testing adds another quality gate in the workflow to allow developers to verify that, after a code change, the user sees what is expected. For example, if the code change is supposed to modify the appearance of an element, developers can verify that it’s doing just that, or at the very least, the code change should not adversely affect other areas. Visual regression testing involves taking screenshots of tested scenarios with changes and comparing them against the baseline (usually screenshots from the stable branch).&lt;/p&gt;
&lt;p&gt;This type of test complements the other testing categories in the test pyramid and ensures user experience is not adversely affected from any given code changes. For more information on the test pyramid and different categories of testing, visit &lt;a href=&#34;/blog/2020/09/automated-testing-with-symfony/&#34;&gt;this blog post&lt;/a&gt; by my colleague, Kevin.&lt;/p&gt;
&lt;p&gt;There are many tools that help with visual regression testing. Here are some tools that you could look into:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://percy.io/&#34;&gt;Percy.io&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Generous free tier to get you started.&lt;/li&gt;
&lt;li&gt;5000 free screenshots per month with unlimited team members. This should get you going just fine for smaller projects.&lt;/li&gt;
&lt;li&gt;Integrate with many mainstream end-to-end tests frameworks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://applitools.com/&#34;&gt;Applitools&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;Uses AI-powered computer vision for visual diffing. Said to reduce a lot of false positives and be more efficient.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.testim.io/&#34;&gt;Testim.io&lt;/a&gt; Automation
&lt;ul&gt;
&lt;li&gt;Another service that uses AI-powered computer vision.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://garris.github.io/BackstopJS/&#34;&gt;BackstopJS&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;A Node.js library you can set up yourself.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each tool has its own strengths and weaknesses. For today’s demonstration, we are going to look at implementing visual regression testing with Percy and see how it works.&lt;/p&gt;
&lt;h3 id=&#34;integrating-percy&#34;&gt;Integrating Percy&lt;/h3&gt;
&lt;p&gt;Percy provides comprehensive guides to get you started with many popular end-to-end test frameworks such as Selenium, Cypress, TestCafe, and Capybara. You can check the documentation to see how to integrate it with your project. Since we work with Rails a lot at End Point, we are going to demonstrate Percy within a Rails project alongside Rspec/​Capybara-driven end-to-end tests.&lt;/p&gt;
&lt;p&gt;In this article, we are going to use this &lt;a href=&#34;https://github.com/afifsohaili-ep/dockified-demo&#34;&gt;simple Rails project&lt;/a&gt; I built for fun as the demo. It is just a simple wiki project using Vue and Rails. Let’s start.&lt;/p&gt;
&lt;h4 id=&#34;1-register-an-account-at-percyio&#34;&gt;1. Register an account at percy.io&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;Head to &lt;a href=&#34;https://percy.io&#34;&gt;percy.io&lt;/a&gt; and click the “Start for Free” button on the top-right side.&lt;/li&gt;
&lt;li&gt;Choose the preferred sign up method. In this case, we are just going to use email and password, so we will choose &lt;em&gt;Sign Up with Browserstack&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Fill in the email and password and complete the registration. It will then send an email to ask us to verify our email address. Let’s check our email and complete the email verification.&lt;/li&gt;
&lt;li&gt;Next, we will see the Get Started screen. We will choose &lt;em&gt;Create a New Project&lt;/em&gt; and give it a relevant name.&lt;/li&gt;
&lt;li&gt;We have successfully created a new percy.io project and should be on the project page. There are some links to setup guides that can help us integrate Percy into our project.
&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/first-setup.png&#34; alt=&#34;Our project page&#34;&gt;&lt;/li&gt;
&lt;li&gt;Let’s navigate to &lt;em&gt;Project Settings&lt;/em&gt;. We will scroll down to the &lt;em&gt;Branch Settings&lt;/em&gt; section and make sure the &lt;em&gt;Default base branch&lt;/em&gt; points to the primary branch of our project’s repository. This is usually &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt; depending on your team’s workflow. You might want to make the same branch auto-approved as well. That way, screenshots from this branch will be treated as the baseline and will be used when comparing against the development branches. In our case, we are using the &lt;code&gt;main&lt;/code&gt; branch so we will specify that in both fields.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Great, we have now successfully set up Percy. There are other configurations in the Project Settings page (e.g. browsers to enable, diff sensitivity, and whether or not to allow public viewers), but we do not have to care about them for the purpose of this demo. You can always come back and tweak this later according to your project’s requirements.&lt;/p&gt;
&lt;h4 id=&#34;2-integrate-with-the-rails-project&#34;&gt;2. Integrate with the Rails project&lt;/h4&gt;
&lt;p&gt;Now, let’s look at how to integrate Percy with our demo Rails project. Percy provides a comprehensive guide to do that &lt;a href=&#34;https://docs.percy.io/docs/capybara&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;1. First, let’s export the &lt;code&gt;PERCY_TOKEN&lt;/code&gt; provided to us in the &lt;em&gt;Builds&lt;/em&gt; page into our environment variable.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;PERCY_TOKEN&lt;/span&gt;=&amp;lt;value&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;2. Then, we will add &lt;code&gt;percy-capybara&lt;/code&gt; into our Gemfile and run &lt;code&gt;bundle install&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gem &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;percy-capybara&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;3. Next, let’s install &lt;code&gt;@percy/agent&lt;/code&gt; via npm/​Yarn.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yarn add --dev @percy/agent&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s it! Now let’s look at adding Percy to our feature specs.&lt;/p&gt;
&lt;h4 id=&#34;3-percy-in-feature-specs&#34;&gt;3. Percy in Feature Specs&lt;/h4&gt;
&lt;p&gt;Percy has to be integrated into feature specs (i.e. end-to-end tests) because it requires the app to be running in order for it to be able to take screenshots. Hence, it will not work in unit tests where the application context is mocked and chunks of code are tested in isolation.&lt;/p&gt;
&lt;p&gt;First, we will check out the primary working branch &lt;code&gt;main&lt;/code&gt; and take a look at the existing feature specs:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# spec/integration/document_spec.rb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;rails_helper&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;RSpec&lt;/span&gt;.feature &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Add documents&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;js&lt;/span&gt;: &lt;span style=&#34;color:#080&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  before &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:each&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;User&lt;/span&gt;.create(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;email&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;user@example.com&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visit &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/documents/new&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    within(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#new_user&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      fill_in &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Email&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;with&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;user@example.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      fill_in &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Password&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;with&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    click_button &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Log in&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scenario &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;User visits page to create new document&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create new document&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scenario &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;User sees validation errors&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    click_button &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Title can&amp;#39;t be blank&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Body can&amp;#39;t be blank&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Body is too short (minimum is 10 characters)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The feature specs are pretty simple. &lt;code&gt;/documents/new&lt;/code&gt; is a route that only registered users can access, so upon visiting the path, &lt;code&gt;devise&lt;/code&gt; is going to ask the visitor to authenticate before they can access the page.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The first test case verifies that the user can see the &lt;code&gt;Create new document&lt;/code&gt; page upon successfully signing in.&lt;/li&gt;
&lt;li&gt;The second case verifies that the user will see validation errors if they do not fill in the required details for the new document.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5 id=&#34;adding-percy-into-the-mix&#34;&gt;Adding Percy into the mix&lt;/h5&gt;
&lt;p&gt;To add Percy, simply &lt;code&gt;require &amp;quot;percy&amp;quot;&lt;/code&gt; at the top of the spec file and add &lt;code&gt;Percy.snapshot(page, { name: &#39;&amp;lt;screenshot description&amp;gt;&#39; })&lt;/code&gt; on the lines in which we want Percy to capture.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# spec/integration/document_spec.rb&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;rails_helper&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;# Include Percy in our feature specs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#038&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;percy&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;RSpec&lt;/span&gt;.feature &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Add documents&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;js&lt;/span&gt;: &lt;span style=&#34;color:#080&#34;&gt;true&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  before &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:each&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;User&lt;/span&gt;.create(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;email&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;user@example.com&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;password&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    visit &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/documents/new&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    within(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;#new_user&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      fill_in &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Email&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;with&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;user@example.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      fill_in &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Password&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;with&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;password&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    click_button &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Log in&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scenario &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;User visits page to create new document&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create new document&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# Screenshot when we&amp;#39;re redirected to the create new document page&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Percy&lt;/span&gt;.snapshot(page, { &lt;span style=&#34;color:#038&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create document page&amp;#39;&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  scenario &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;User sees validation errors&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    click_button &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Title can&amp;#39;t be blank&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Body can&amp;#39;t be blank&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    expect(page).to have_text(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Body is too short (minimum is 10 characters)&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# Screenshot when we see the errors&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Percy&lt;/span&gt;.snapshot(page, { &lt;span style=&#34;color:#038&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create document page validation error&amp;#39;&lt;/span&gt; })
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That’s it! Easy enough, right? Next, let’s run the tests so that the screenshots are taken and sent to percy.io. To do this, we cannot run the usual &lt;code&gt;bundle exec rspec&lt;/code&gt;. Instead, we will have to run Percy and pass &lt;code&gt;rspec&lt;/code&gt; to it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ yarn percy &lt;span style=&#34;color:#038&#34;&gt;exec&lt;/span&gt; -- rspec&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: This is the command that you should use if you have continuous integration set up.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;And we’re done here! Now, if we go to percy.io, we can see that a new build has been created for us. After a few minutes, we should see the screenshots of the app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/first-build.png&#34; alt=&#34;Our first build on Percy&#34;&gt;&lt;/p&gt;
&lt;h4 id=&#34;4-introduce-visual-changes-and-see-how-percyio-compares&#34;&gt;4. Introduce visual changes and see how percy.io compares&lt;/h4&gt;
&lt;p&gt;The last step we ran was on the primary working branch. Since we set this branch as the baseline and that the screenshots from this branch would be auto-approved, we are not going to be asked to verify anything on this build.&lt;/p&gt;
&lt;p&gt;Therefore, to demonstrate the visual diff-ing feature of Percy, let’s create another branch &lt;code&gt;highlight-create-button&lt;/code&gt;, and let’s make the &lt;code&gt;Create Document&lt;/code&gt; button appear bigger as well as change the text to just say &lt;code&gt;Create&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;%# app/views/documents/_form.html.erb %&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;%#&lt;/span&gt; ... &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;%&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;%# Old button %&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;%#= form.submit class: &amp;#39;button is-primary&amp;#39; %&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;%#&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;New&lt;/span&gt; button &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;%&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;lt;%= form.submit &amp;#34;Create&amp;#34;, class: &amp;#39;button is-primary is-large&amp;#39; %&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Awesome! Now, let’s rerun &lt;code&gt;yarn percy exec -- rspec&lt;/code&gt; and analyse the visual diff on percy.io.&lt;/p&gt;
&lt;p&gt;Once percy.io is done processing the new screenshots, it will compare the screenshots against the baseline in the &lt;code&gt;main&lt;/code&gt; branch. We will see this in our new build:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/visual-diff-sample.png&#34; alt=&#34;Visual diff on Percy&#34;&gt;&lt;/p&gt;
&lt;p&gt;As you can see, Percy highlights any changed areas in red. This makes it easier for us to spot the differences. In this case, it is expected for the button to change, so we can just go ahead and approve the build with the green button at the top.&lt;/p&gt;
&lt;h4 id=&#34;5-what-about-style-regressions&#34;&gt;5. What about style regressions?&lt;/h4&gt;
&lt;p&gt;Let’s do one more demonstration. This time, let’s simulate a CSS change gone wrong:&lt;/p&gt;
&lt;p&gt;Create another git branch called &lt;code&gt;css-regression&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add a &lt;code&gt;text-indent: -5rem&lt;/code&gt; to the error messages to push the text out of its container. This is what it would look like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/css-regression.png&#34; alt=&#34;Regression&#34;&gt;&lt;/p&gt;
&lt;p&gt;Let’s run &lt;code&gt;bundle exec rspec&lt;/code&gt;. We will get this output:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; bundle exec rspec
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Capybara starting Puma...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Version 5.3.2 , codename: Sweetnighter
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Min threads: 0, max threads: 4
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* Listening on http://127.0.0.1:65318
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;..
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Finished in 2.62 seconds (files took 1.3 seconds to load)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2 examples, 0 failures&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the tests were not able to catch this styling regression. This is because the error messages specified in the assertion still exist on the page, so the use case is not considered broken in the “eyes” of the regular feature specs.&lt;/p&gt;
&lt;p&gt;Now, run &lt;code&gt;yarn percy exec -- rspec&lt;/code&gt; to send the screenshots to percy.io to be processed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/percy-regression.png&#34; alt=&#34;Regression on Percy&#34;&gt;&lt;/p&gt;
&lt;p&gt;Great, percy.io was able to catch the regression here in the visual diff! A reviewer can just mark the build as “Requested changes” and leave a comment in there to have it fixed.&lt;/p&gt;
&lt;h4 id=&#34;6-responsive-design-and-cross-browser-testing&#34;&gt;6. Responsive design and cross-browser testing&lt;/h4&gt;
&lt;p&gt;Percy can also help test your app’s UI on different browsers — namely Edge, Firefox, and Chrome. By default, all three browsers are enabled. You do not need to do anything else.&lt;/p&gt;
&lt;p&gt;It can be used to test against different screen sizes as well. You can just select the screen sizes that are relevant to you and instruct Percy to take screenshots at those screen sizes automatically. This is particularly helpful as testing on several screen size variants can be very time-consuming. With Percy, you do not have to pay attention to the screenshot variants that do not diverge from the baseline.&lt;/p&gt;
&lt;p&gt;In order to specify screen sizes, just pass a list of screen sizes that you are interested in, like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Percy&lt;/span&gt;.snapshot(page, { &lt;span style=&#34;color:#038&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Create document page&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;widths&lt;/span&gt;: [&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;480&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;768&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1024&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1366&lt;/span&gt;] })&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Rerun &lt;code&gt;yarn percy exec -- rspec&lt;/code&gt;. We can now see the different variants (browsers and screen sizes) of each scenario on the top-right corner of the screen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2021/06/catching-css-regressions-visual-bugs-in-ci/variants.png&#34; alt=&#34;Variants&#34;&gt;&lt;/p&gt;
&lt;p&gt;That’s it! We have successfully demonstrated how Percy can help us verify expected UI changes and catch visual regressions.&lt;/p&gt;
&lt;h3 id=&#34;caveats&#34;&gt;Caveats&lt;/h3&gt;
&lt;p&gt;As helpful and as crucial as it is, visual regression testing is not without its caveats. One of the most common issues with visual regression testing is, in some cases, it can produce a huge amount of false positives. Major-but-intentional layout shifts and changes to shared elements may result in having to review a huge amount of screenshots in the project.&lt;/p&gt;
&lt;p&gt;For example, let’s say you increase the height of the site header (which is a common element in &lt;em&gt;all&lt;/em&gt; pages) by 30px. When Percy processes the screenshots, it will invalidate most of the screenshots in the project, because elements would have been shifted down by 30px as a result of the taller header. For large projects, reviewing each screenshot one-by-one can be a hassle, especially with the tens of permutations for each screenshot to cater different screen sizes and browsers. As a result, one would be tempted to just click “Approve build”, thinking all changed areas would just be elements being pushed down, but that may not necessarily be true for elements with &lt;code&gt;position: absolute;&lt;/code&gt;; they might get hidden behind the now taller header, and this may cause visual regressions to still slip into production, which kind of defeats visual testing’s original purpose.&lt;/p&gt;
&lt;p&gt;Other than that, dealing with external resources can also result in flaky builds (e.g. if a page has an iframe or links to an external image). There are a lot of ways in which an external resource can change, e.g. image quality, content, updated resource, etc., and because these resources are outside of our control, they may become a source of false positives and a nuisance to the reviewers.&lt;/p&gt;
&lt;p&gt;One way to deal with this is to not screenshot whole pages. Instead, screenshot only the individual components that are relevant to each scenario. This way, layout shifts in other parts of the pages will not affect the build in major ways, and it also helps cut out the changes from external resources on the page. Unfortunately, Percy does not have the capability to do this &lt;a href=&#34;https://github.com/percy/percy-cypress/issues/56#issuecomment-824183541&#34;&gt;yet&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;So, there you go! I hope this article has given you a good introduction to visual regression testing, why should you have it, and how to get started with it. Hope it will benefit you and your team in pushing great web applications!&lt;/p&gt;
&lt;h3 id=&#34;other-resources&#34;&gt;Other resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=spyKZ-p3UgE&#34;&gt;(YouTube) Your Tests Lack Vision: Adding Eyes to your Automation Framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=_ls5P97-REU&#34;&gt;(YouTube) Visual Regression Testing for Your Web Apps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://techblog.commercetools.com/keeping-a-react-design-system-consistent-f055160d5166&#34;&gt;Keeping a React Design System consistent: using visual regression testing to save time and headaches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@philgourley/making-visual-regression-useful-acfae27e5031&#34;&gt;Making visual regression useful&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>Jamstack Conf Virtual 2020: Thoughts &amp; Highlights</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2020/06/jamstack-conf-virtual-may-2020/"/>
      <id>https://www.endpointdev.com/blog/2020/06/jamstack-conf-virtual-may-2020/</id>
      <published>2020-06-16T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/conference.jpg&#34; alt=&#34;Conference&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;welcome-to-jamstack-conf-virtual-2020&#34;&gt;Welcome to Jamstack Conf Virtual 2020&lt;/h3&gt;
&lt;p&gt;Last week I attended &lt;a href=&#34;https://jamstackconf.com/2020/may/&#34;&gt;Jamstack Conf Virtual 2020&lt;/a&gt;. It had originally been slated to take place in London, UK but was later transformed into a virtual event in light of the COVID-19 pandemic. The conference began at 2pm London time (thankfully I double-checked this the night before!)—​6am for those of us in the Pacific Time Zone.&lt;/p&gt;
&lt;blockquote class=&#34;twitter-tweet&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;Up early for &lt;a href=&#34;https://twitter.com/hashtag/jamstackconf?src=hash&amp;amp;ref_src=twsrc%5Etfw&#34;&gt;#jamstackconf&lt;/a&gt; 😎☕️ &lt;a href=&#34;https://t.co/ydjvrHWCZH&#34;&gt;pic.twitter.com/ydjvrHWCZH&lt;/a&gt;&lt;/p&gt;— Greg Davidson (@syncopated) &lt;a href=&#34;https://twitter.com/syncopated/status/1265637434638778368?ref_src=twsrc%5Etfw&#34;&gt;May 27, 2020&lt;/a&gt;&lt;/blockquote&gt; &lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
&lt;p&gt;Before getting too much further I wanted to mention that if you are not familiar with the Jamstack, You can read more about it at &lt;a href=&#34;https://jamstack.org/&#34;&gt;jamstack.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To virtually participate in the conference we used an app called &lt;a href=&#34;https://hopin.com/&#34;&gt;Hopin&lt;/a&gt;. I had not heard of it before but was impressed with how well it worked. There were over 3000 attendees from 130+ countries one of the times I checked. &lt;a href=&#34;https://www.hawksworx.com/&#34;&gt;Phil Hawksworth&lt;/a&gt; was the Host/​MC for the event and did a great job. There were virtual spaces for the stage, sessions, expo (vendors), and networking. If you opted to, the networking feature paired you with a random attendee for a video chat. I’m not sure what I expected going into it but I thought it was fun. I met a fellow developer from the Dominican Republic. The experience was very similar though more serendipitous than the hallway track or lunch line at an in-person conference.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/phil-welcome.png&#34; alt=&#34;Phil Hawksworth welcoming the attendees&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;keynote&#34;&gt;Keynote&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/biilmann&#34;&gt;Matt Biilmann&lt;/a&gt; opened the conference with a keynote address about the challenges we face as a developer community trying to improve access to accurate, timely and locally relevant information to a global audience. Many billions of users with all kinds of devices and varying levels of connectivity. He moved on to share how Netlify is trying to enable developers to “build websites instead of infrastructure” and “ensure all the best practices become common practices” through features like git-based deployments, build plugins, and edge handlers (more on those later).&lt;/p&gt;
&lt;h3 id=&#34;state-of-the-jamstack-survey-results&#34;&gt;State of the Jamstack Survey results&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/laurie-voss-talk.png&#34; alt=&#34;Laurie Voss reporting findings from the Jamstack Survey 2020&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://seldo.com/&#34;&gt;Laurie Voss&lt;/a&gt; &lt;a href=&#34;https://slides.com/seldo/jamstack-survey-2020#/&#34;&gt;walked us through&lt;/a&gt; the results of the &lt;a href=&#34;https://www.netlify.com/blog/2020/05/27/state-of-the-jamstack-survey-2020-first-results/&#34;&gt;Jamstack Survey 2020&lt;/a&gt;. There were some interesting findings and surprises. Later on I read &lt;a href=&#34;https://seldo.com/posts/you-will-never-be-a-full-stack-developer/&#34;&gt;Laurie’s post&lt;/a&gt; (which Matt had mentioned in his talk) and found that very interesting as well.&lt;/p&gt;
&lt;h3 id=&#34;fireside-chat-with-harper-reed&#34;&gt;Fireside chat with Harper Reed&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/harper-phae-talk.png&#34; alt=&#34;Frances Berriman interviewed Harper Reed - fireside chat style&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://fberriman.com/&#34;&gt;Frances Berriman&lt;/a&gt; chatted with &lt;a href=&#34;https://harperreed.com/&#34;&gt;Harper Reed&lt;/a&gt; and asked him about his application of Jamstack principles from years ago when he led the technology team for Barack Obama’s election campaign. He described the need to “get far with very limited resources” and spoke about experimenting with serving HTML from Google App Engine and Amazon S3. Using pre-built HTML allowed them to scale very efficiently and he opted to use message queues rather than interacting with the database to keep things very quick for users.&lt;/p&gt;
&lt;p&gt;Another benefit Harper noted was how quickly and easily new team members could be onboarded. Folks who knew HTML, CSS and JavaScript would be up to speed and productive in no time. He admitted it’s more complicated today 😀. Speed is another benefit—he just loves when he comes across a super-fast web site (often mostly static).&lt;/p&gt;
&lt;h3 id=&#34;lightning-launch-netlify-&#34;&gt;Lightning Launch: Netlify ⚡&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/calavera&#34;&gt;David Calavera&lt;/a&gt; gave a demo of Netlify’s new Edge Handlers feature which lets developers add logic to their code at the edge (e.g. the CDN servers geographically closest to the user). He demonstrated how Edge Handlers make it possible to examine the headers of the request to tailor the response to that unique request. Check out the &lt;a href=&#34;https://www.youtube.com/watch?v=D44n8YVb5iI&#34;&gt;video of his talk&lt;/a&gt; to watch him live code an example. I believe &lt;a href=&#34;https://workers.cloudflare.com/&#34;&gt;Cloudflare Workers&lt;/a&gt; and Fastly’s &lt;a href=&#34;https://www.fastly.com/products/edge-compute/serverless&#34;&gt;Edge Compute&lt;/a&gt; are operating in a similar problem space. I plan to look into each of these offerings more thoroughly in future.&lt;/p&gt;
&lt;h3 id=&#34;lightning-launch-prismic-&#34;&gt;Lightning Launch: Prismic ⚡&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/RenaudBressand&#34;&gt;Renaud Bressand&lt;/a&gt; from Prismic demoed &lt;a href=&#34;https://www.slicemachine.dev/&#34;&gt;Slicemachine&lt;/a&gt;—​a new feature from Prismic which lets you combine &lt;a href=&#34;https://nuxtjs.org/&#34;&gt;nuxt&lt;/a&gt;/​Vue components with content managed in Prismic. It looked like a very compelling way of enabling better collaboration between developers and content creators.&lt;/p&gt;
&lt;h3 id=&#34;lightning-launch-redwoodjs-&#34;&gt;Lightning Launch: RedwoodJS ⚡&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://tom.preston-werner.com/&#34;&gt;Tom Preston-Werner&lt;/a&gt; demoed his latest project &lt;a href=&#34;https://redwoodjs.com/&#34;&gt;RedwoodJS&lt;/a&gt;. I had heard Tom speak about this on a few podcasts recently and it was nice to see him demo it for us. It looks interesting and feels reminiscent of &lt;a href=&#34;https://rubyonrails.org/&#34;&gt;Rails&lt;/a&gt;. RedwoodJS simplifies wiring up your database to a &lt;a href=&#34;https://graphql.org/&#34;&gt;GraphQL&lt;/a&gt; API (they use &lt;a href=&#34;https://www.prisma.io/&#34;&gt;Prisma&lt;/a&gt; for this) and integrating it into a React application. Tom is also the creator of &lt;a href=&#34;https://jekyllrb.com/&#34;&gt;Jekyll&lt;/a&gt;—​a Jamstack-style tool which has been around for many years. It was nice to see several speakers give him some recognition for his work on that project.&lt;/p&gt;
&lt;h3 id=&#34;the-covid-tracking-project-0-to-2m-api-requests-in-3-months&#34;&gt;The COVID Tracking Project: 0 to 2M API requests in 3 months&lt;/h3&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/kissane.png&#34; alt=&#34;Erin Kissane presenting The COVID Tracking Project&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://incisive.nu/&#34;&gt;Erin Kissane&lt;/a&gt; gave an inspiring talk about her work on &lt;a href=&#34;https://covidtracking.com&#34;&gt;The COVID Tracking Project&lt;/a&gt;. She described it as an “interim public data rescue project”. Erin and some friends, journalists and volunteers worked together to create the site. They started by scraping COVID data from each state’s web site and storing it in a Google Sheet. They used &lt;a href=&#34;https://www.gatsbyjs.com/&#34;&gt;Gatsby&lt;/a&gt;, &lt;a href=&#34;https://www.contentful.com/&#34;&gt;Contentful&lt;/a&gt;, and &lt;a href=&#34;https://css-tricks.com/introducing-sass-modules/&#34;&gt;Sass modules&lt;/a&gt; and hosted the site on Netlify. Using the Jamstack approach allowed the site to remain performant and continue to be responsive under some huge traffic spikes. Over time, they iterated on the design and continue to improve the site daily. I highly recommend checking out the &lt;a href=&#34;https://www.youtube.com/watch?v=ryngYoHXNfQ&#34;&gt;video of the talk&lt;/a&gt; when you get a chance.&lt;/p&gt;
&lt;h3 id=&#34;jamstack-for-emerging-markets&#34;&gt;Jamstack for emerging markets&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.codebeast.dev/&#34;&gt;Christian Nwamba&lt;/a&gt; described some of the challenges of building sites for users in Nigeria (low power devices, spotty connectivity, unreliable power). He shared that 55% of the most visited sites in Nigeria are global companies (Google, Facebook/​Instagram, Netflix, Stack Overflow etc.). Christian reviewed a large, popular banking site in Nigeria and noted its many shortcomings.&lt;/p&gt;
&lt;p&gt;To demonstrate how the bank might do better he built &lt;a href=&#34;https://proud-flower-060c1e01e.azurestaticapps.net/&#34;&gt;an app&lt;/a&gt; for transferring money between friends &amp;amp; family built in the Jamstack style and using serverless functions. The most interesting thing I picked up from this was his method of using serverless functions to protect the app secrets (API keys, etc.). The front end of the application did not need to concern itself with this—​the serverless functions kept the secrets safe and acted as a proxy between the frontend and the backend APIs. Be sure to take a look at &lt;a href=&#34;https://github.com/christiannwamba/quickbank&#34;&gt;Christian’s code&lt;/a&gt; if you are interested.&lt;/p&gt;
&lt;h3 id=&#34;managing-diabetes-with-jamstack&#34;&gt;Managing diabetes with Jamstack&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://jamiebradley.dev/&#34;&gt;Jamie Bradley&lt;/a&gt; taught us about diabetes and the Jamstack app he built to help himself and others manage it. He built &lt;a href=&#34;https://heysugar.health/&#34;&gt;HeySugar&lt;/a&gt; with Gatsby and Sanity, hosted it on Netlify. He’s making it easier for others to deploy their own instances as well.&lt;/p&gt;
&lt;h3 id=&#34;selling-tickets-without-servers-or-frameworks-or-cookies&#34;&gt;Selling tickets without servers. Or frameworks. Or cookies.&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://jvhellemond.nl/&#34;&gt;Jan van Hellemond&lt;/a&gt; has volunteered for years at a very popular conference in Europe (&lt;a href=&#34;https://fronteers.nl/congres&#34;&gt;Fronteers&lt;/a&gt; I think). In previous years tickets sold out in 6 minutes one year, and 30 seconds in another! Their ticket vendor was struggling to handle to the load and this caused them to oversell early bird tickets. Jan built a Jamstack site to sell their tickets and was very pleased with the performance. He used simple, single-purpose vanilla JavaScript components and simple, single-purpose API handlers (serverless functions).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/tickets.png&#34; alt=&#34;Jan presenting his Jamstack ticket selling app&#34;&gt;&lt;/p&gt;
&lt;p&gt;Jan prerendered as much as possible and seeded a relational database with the tickets available for sale. As the tickets were sold, they were marked sold with a database update. Webhooks were used as customers stepped through the checkout flow. Jan joked about deploying to production on a Friday afternoon because of how safe and simple the deployment process was. There were no services to restart, etc. because “it’s just files”. It was cool to see a practical example and that Jan used the basic building blocks of the web (HTML, JavaScript, CSS, old school links) successfully without reaching for a large JavaScript framework.&lt;/p&gt;
&lt;h3 id=&#34;the-business-side-of-the-jamstack&#34;&gt;The business side of the Jamstack&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/_anarossetto_&#34;&gt;Ana Rossetto&lt;/a&gt; shared how her company has been having great success with the Jamstack. Previously, the agency had been building projects for clients with Drupal. She walked through a project she and the team built to encourage people to buy from small, locally-owned businesses. She was impressed with what they were able to create in a very short amount of time.&lt;/p&gt;
&lt;h3 id=&#34;build-plugin-authors-session&#34;&gt;Build plugin authors’ session&lt;/h3&gt;
&lt;p&gt;After the main talks there were several sessions. In the Hopin app, I was able to peek into some of these and the presenters and attendees were chatting (both text chat and video). This was very much like the experience of peeking into conference rooms at a physical venue and choosing whether to stay and participate or move on. After some wandering I chose to attend a session with three Netlify build plugin authors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2020/06/jamstack-conf-virtual-may-2020/subfont.png&#34; alt=&#34;Peter telling us about subfont&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://mntr.dk/&#34;&gt;Peter Müller&lt;/a&gt; built &lt;a href=&#34;https://github.com/Munter/netlify-plugin-subfont&#34;&gt;Subfont&lt;/a&gt; with a friend. He demonstrated how subsetting web fonts (i.e. only loading the characters &amp;amp; glyphs you really need) can dramatically improve frontend performance. He compared the &lt;a href=&#34;https://webpagetest.org/&#34;&gt;WebPageTest&lt;/a&gt; results for Google Fonts with and without Subfont and Subfont was seconds faster! I have subset and locally hosted webfonts in several client projects here at End Point. It takes time and is a manual process. Peter’s plugin makes this excellent performance improvement relatively painless.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://darn.es/&#34;&gt;David Darnes&lt;/a&gt; demoed his build plugin to &lt;a href=&#34;https://github.com/daviddarnes/netlify-plugin-ghost-markdown&#34;&gt;turn Ghost content into Markdown files&lt;/a&gt;. Very interesting and it seemed flexible enough to work with other tools as well.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/bahmutov&#34;&gt;Gleb Bahmutov&lt;/a&gt; presented the build plugin he created to run &lt;a href=&#34;https://www.cypress.io/&#34;&gt;Cypress&lt;/a&gt; tests as part of your Netlify build process. It was amazing to see how simple it was (single devDependency and single line in the netlify.toml config file).&lt;/p&gt;
&lt;h3 id=&#34;videos-from-the-conference&#34;&gt;Videos from the conference&lt;/h3&gt;
&lt;p&gt;Netlify has already put all of the &lt;a href=&#34;https://www.youtube.com/playlist?list=PL58Wk5g77lF8jzqp_1cViDf-WilJsAvqT&#34;&gt;Jamstack Conf Virtual 2020 talks&lt;/a&gt; on YouTube so head over there and check those out if you’d like to. Thanks very much to the team at Netlify for organizing the conf, all of the speakers, vendors and attendees!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Winning with CSS Grid and Autoprefixer</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/11/winning-with-css-grid-and-autoprefixer/"/>
      <id>https://www.endpointdev.com/blog/2019/11/winning-with-css-grid-and-autoprefixer/</id>
      <published>2019-11-04T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/11/winning-with-css-grid-and-autoprefixer/grid.jpg&#34; alt=&#34;Aerial view of St. Vitus Cathedral, Prague&#34;&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&#34;https://unsplash.com/photos/BWtyq5fn6Ng&#34;&gt;Stijn te Strake&lt;/a&gt; on &lt;a href=&#34;https://unsplash.com/&#34;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;using-css-grid-today&#34;&gt;Using CSS Grid Today&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://caniuse.com/#search=css%20grid&#34;&gt;Support for CSS Grid&lt;/a&gt; is excellent (over 90% globally! 💯). I have been using it in a variety of client projects for the past few years with great success. The combination of CSS Grid and Flexbox has made layout on the web much simpler, more fun and less frustrating compared to the &lt;del&gt;hacks&lt;/del&gt; techniques which were used for CSS layout in the past. Definitely give it a try if you haven’t already done so.&lt;/p&gt;
&lt;p&gt;IE10 and IE11 support an earlier version of the CSS Grid spec and with help from Autoprefixer we can reap the benefits of CSS Grid in those old browsers with a little bit of extra work. I’ve long been a huge fan and happy user of &lt;a href=&#34;https://github.com/postcss/autoprefixer&#34;&gt;Autoprefixer&lt;/a&gt;. It’s a &lt;a href=&#34;https://postcss.org/&#34;&gt;PostCSS&lt;/a&gt; plugin that examines your CSS and augments it with &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix&#34;&gt;vendor prefixes&lt;/a&gt; and alternative syntaxes. Although vendor prefixes (e.g. &lt;code&gt;-webkit&lt;/code&gt;, &lt;code&gt;-moz&lt;/code&gt;, &lt;code&gt;-o&lt;/code&gt;, etc.) are much less common these days, there are a few still in use.&lt;/p&gt;
&lt;h3 id=&#34;css-grid-basics&#34;&gt;CSS Grid Basics&lt;/h3&gt;
&lt;p&gt;With CSS Grid the basic idea is to define the grid, i.e. the rows and columns that make it up, and then go about placing elements on the grid. Think of a website layout with a masthead, navigation, hero image, main content sidebar, and footer as an example. Your grid styles can specify where each of these elements should be displayed on the grid: how many rows or columns they span, etc. In addition to this method of explicitly placing elements on the grid, &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Auto-placement_in_CSS_Grid_Layout&#34;&gt;auto-placement&lt;/a&gt; places elements on the grid for you  automatically.&lt;/p&gt;
&lt;h3 id=&#34;autoprefixer--css-grid&#34;&gt;Autoprefixer + CSS Grid&lt;/h3&gt;
&lt;p&gt;I recently learned how to use &lt;a href=&#34;https://github.com/postcss/autoprefixer#control-comments&#34;&gt;control comments in Autoprefixer&lt;/a&gt; to get fine-grained control over the way it operates on and enhances my CSS Grid styles. Rather than specifying a single (global) behavior via config options, control comments let you tell Autoprefixer how you would like it to process individual blocks of CSS code. For the scenario where I was explicitly placing elements on my grid I used the following control comment in my CSS file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* autoprefixer grid: no-autoplace */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This allowed me to lay out the elements and Autoprefixer generated the &lt;code&gt;-ms-grid&lt;/code&gt; styles required to make my modern CSS Grid styles work in IE 10 and IE 11.&lt;/p&gt;
&lt;p&gt;In another scenario I &lt;em&gt;&lt;strong&gt;did&lt;/strong&gt;&lt;/em&gt; want the auto-placement support and enabled it with the following control comment in a different block of the same CSS file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* autoprefixer grid: autoplace */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This was for a group of uniformly sized tile elements that I wanted to lay out in a grid that adapted as the viewport size varied. E.g.: from 4 tiles per row, to 3 tiles, to 2 and finally to 1 tile per row for the smallest viewports.&lt;/p&gt;
&lt;p&gt;In both cases I was pleasantly surprised that my CSS Grid styles worked in modern browsers &lt;strong&gt;and&lt;/strong&gt; also in IE 11 and 10! I added some fallback styles using flexbox for those browsers which do not yet support CSS Grid to ensure the content was accessible there as well.&lt;/p&gt;
&lt;h3 id=&#34;test-your-autoprefixd-grid-styles&#34;&gt;Test Your Autoprefix’d Grid Styles&lt;/h3&gt;
&lt;p&gt;Please note the Autoprefixer docs warn its grid support may not work in &lt;em&gt;all&lt;/em&gt; cases and must be tested. For my purposes this worked you great but make sure to test because your mileage may vary.&lt;/p&gt;
&lt;h3 id=&#34;learning-more&#34;&gt;Learning More&lt;/h3&gt;
&lt;p&gt;If you’d like to learn more about CSS Grid I would recommend checking out &lt;a href=&#34;https://jensimmons.com/&#34;&gt;Jen Simmons’&lt;/a&gt; &lt;a href=&#34;https://www.youtube.com/playlist?list=PLbSquHt1VCf0b43dfLKTrCriXdlZcmgoi&#34;&gt;CSS Grid Basics&lt;/a&gt; series on YouTube and the &lt;a href=&#34;https://gridbyexample.com/&#34;&gt;Grid by Example&lt;/a&gt; site by &lt;a href=&#34;https://rachelandrew.co.uk/&#34;&gt;Rachel Andrew&lt;/a&gt;. To learn more about Autoprefixer, check out &lt;a href=&#34;https://github.com/postcss/autoprefixer&#34;&gt;the docs&lt;/a&gt; at GitHub or you can &lt;a href=&#34;https://autoprefixer.github.io/&#34;&gt;try it out interactively&lt;/a&gt;.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>React: Style Tips</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2019/09/react-style-tips/"/>
      <id>https://www.endpointdev.com/blog/2019/09/react-style-tips/</id>
      <published>2019-09-28T00:00:00+00:00</published>
      <author>
        <name>Zed Jensen</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img src=&#34;/blog/2019/09/react-style-tips/image-0.jpg&#34; alt=&#34;Icon design&#34; /&gt;&lt;br&gt;Photo by &lt;a href=&#34;https://unsplash.com/photos/_zKxPsGOGKg&#34;&gt;Harpal Singh&lt;/a&gt; on Unsplash&lt;/p&gt;
&lt;p&gt;I’ve worked on a couple of large React projects over the last few years. In my experience, one of the trickiest parts of getting a React project up and running is figuring out how you want to visually style your application in the browser, so I’ll share in this post some of the ways I’ve styled my projects.&lt;/p&gt;
&lt;h3 id=&#34;css-modules&#34;&gt;CSS Modules&lt;/h3&gt;
&lt;p&gt;Libraries like Material-UI (which I’ll discuss next) do a lot of the work of styling for you. However, sometimes you’ll still need to define styles unique to your project, and the most common way is with CSS.&lt;/p&gt;
&lt;p&gt;For projects created with &lt;a href=&#34;https://github.com/facebook/create-react-app&#34;&gt;create-react-app&lt;/a&gt;, any CSS you include in a React project isn’t scoped. This means that if you define a class &lt;code&gt;tall&lt;/code&gt; in one component that has a height of 40 pixels and a class &lt;code&gt;tall&lt;/code&gt; in another component with a height of 80 pixels, one of your rules will overwrite the other—whichever makes it into the compiled CSS file last. However, webpack allows you to use CSS modules, which restrict your CSS rules to components that explicitly import them. It took me a long time to figure out how to use them due to lack of relevant documentation, but eventually I discovered a very easy way to do it.&lt;/p&gt;
&lt;p&gt;If your file structure looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.css&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s as simple as renaming your CSS file like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;- app/
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  |-App.module.css&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using the suffix &lt;code&gt;.module.css&lt;/code&gt; tells create-react-app that the rules within should be scoped only for where they’re imported. They can be used like other styles by importing and passing the classes like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import styles from &amp;#39;./App.module.css&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export default function Component(props) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  return &amp;lt;div className={styles.myClass} /&amp;gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;material-ui-and-similar-libraries&#34;&gt;Material-UI and similar libraries&lt;/h3&gt;
&lt;p&gt;There are many different design philosophies for web, but probably the most popular is Google’s &lt;a href=&#34;https://material.io/design/&#34;&gt;Material Design&lt;/a&gt;. Material Design lays out some rules that help keep a user interface uncluttered, intuitive, and pleasant to use. However, jumping into the guidelines on Google’s website can be very intimidating. In addition, manually defining CSS for your web application is a lot of work. There are several different libraries that offer solutions to this, my favorite being &lt;a href=&#34;https://material-ui.com/&#34;&gt;Material-UI&lt;/a&gt;. Material-UI provides a set of components that you can reuse to put your application together.&lt;/p&gt;
&lt;p&gt;Here’s a simple example showing different styles of text fields:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;import&lt;/span&gt; TextField from &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;@material-ui/core/TextField&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; TextFieldDemo(props) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  render() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;form&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;TextField
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          label=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          value={values.name}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          onChange={handleChange(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;TextField
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          label=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          value={values.name}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          onChange={handleChange(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          variant=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;outlined&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;TextField
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          label=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Name&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          value={values.name}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          onChange={handleChange(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;)}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          variant=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;filled&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;/form&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And here’s what that looks like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;/blog/2019/09/react-style-tips/image-1.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;
&lt;h3 id=&#34;vanilla-css-with-material-ui&#34;&gt;Vanilla CSS with Material-UI&lt;/h3&gt;
&lt;p&gt;It’s also important to note that Material-UI’s preferred way of defining additional styles is using &lt;a href=&#34;https://cssinjs.org/&#34;&gt;CSSinJS&lt;/a&gt; rather than plain CSS. Given the following CSS:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;button&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: --theme-spacing
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;input&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;none&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You would instead use the following JSS object:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  button: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    margin: theme.spacing(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  input: {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    display: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;none&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Using the styles in your project is mostly the same after that, but I won’t go into detail about that here. CSSinJS has some advantages (which you can read about in the &lt;a href=&#34;https://material-ui.com/styles/basics/&#34;&gt;Material-UI documentation&lt;/a&gt; as well as on the &lt;a href=&#34;https://cssinjs.org&#34;&gt;CSSinJS website&lt;/a&gt;), but I prefer vanilla CSS. It’s not immediately obvious from their site, but you can still use vanilla CSS as well as CSS modules with Material-UI, and setting it up is pretty simple.&lt;/p&gt;
&lt;p&gt;First, you need to make sure that your CSS is injected before styles included with Material-UI. There are two steps to making this work: first, you define an injection point for your CSS by adding an element to your index.html at the injection point:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;noscript id=&amp;#34;jss-insertion-point&amp;#34; /&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, you wrap the entire application in the &lt;code&gt;StylesProvider&lt;/code&gt; component with a prop named &lt;code&gt;injectFirst&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;import { StylesProvider } from &amp;#39;@material-ui/styles&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;class App extends Component {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  render() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    return (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;StylesProvider injectFirst&amp;gt;...&amp;lt;/StylesProvider&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    );
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, your imported CSS will take predence over the styles provided by Material-UI, so you can still use vanilla CSS if you like!&lt;/p&gt;
&lt;h3 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;These methods have worked great for me, but they’re certainly not the only way to do things. Leave a comment if you’ve found a library you like, or have an approach you recommend!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSSConf US 2016 — Day One</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/10/cssconf-us-2016-day-one/"/>
      <id>https://www.endpointdev.com/blog/2016/10/cssconf-us-2016-day-one/</id>
      <published>2016-10-07T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;img alt=&#34;IMG 6042&#34; border=&#34;0&#34; height=&#34;450&#34; src=&#34;/blog/2016/10/cssconf-us-2016-day-one/image-0.jpeg&#34; style=&#34;display:block; margin-left:auto; margin-right:auto;&#34; title=&#34;IMG_6042.JPG&#34; width=&#34;600&#34;/&gt;  Boston Common&lt;/p&gt;
&lt;p&gt;I attended CSSConf US 2016 last week in Boston, MA. Having been to the &lt;a href=&#34;/blog/2013/06/css-conf-2013-when-bootstrap-attacks/&#34;&gt;2013&lt;/a&gt; and 2014 (&lt;a href=&#34;/blog/2014/05/cssconf-us-2014-part-one/&#34;&gt;part one&lt;/a&gt;, &lt;a href=&#34;/blog/2014/06/css-conf-us-2014-part-two/&#34;&gt;part two&lt;/a&gt;) events in Florida then missing it in NYC last year, I was looking forward to seeing what it would be like in a new location. It was fun to see some familiar faces including &lt;a href=&#34;https://twitter.com/eirikurn&#34;&gt;Eiríkur&lt;/a&gt; (congrats on organizing a very successful &lt;a href=&#34;https://2016.jsconf.is/&#34;&gt;JSConf Iceland&lt;/a&gt; conference earlier this year!) and to meet many new folks in the CSS community. &lt;a href=&#34;http://itsmisscs.me/&#34;&gt;Claudina Sarahe&lt;/a&gt; was our MC for two days of talks and she did a great job. After each talk she took a few minutes to interview the speaker—​asking them questions from the audience and some of her own. The chats were candid and interesting on their own and gave the next speaker time to set up.&lt;/p&gt;
&lt;p&gt;Below are my notes and some observations on the talks from Day One. Be sure to check out the &lt;a href=&#34;https://2016.cssconf.com/#videos&#34;&gt;videos, slides and transcripts&lt;/a&gt; at the CSSConf site. Many of the videos are there now and they are adding more as they become available.&lt;/p&gt;
&lt;h3 id=&#34;sarah-drasner--creativity-in-programming-for-fun-and-profit&#34;&gt;Sarah Drasner — Creativity in Programming for Fun and Profit&lt;/h3&gt;
&lt;p&gt;Sarah started off the day with an inspiring keynote about creativity. She explained how writing code is a creative endeavor by showing us several drastically different solutions to the classic FizzBuzz problem in computer science. She shared some stats and survey results which documented excellent, tangible results companies saw when they invested in R&amp;amp;D and fostering creativity. Sarah demoed some really cool creative projects she had built—​many of them just for fun. She encouraged us to work on creative projects on the side to enter into &lt;a href=&#34;https://en.wikipedia.org/wiki/Flow_(psychology)&#34;&gt;flow&lt;/a&gt; while designing, coding and building things. Time devoted to purely creative and fun projects can makes less interesting day-to-day tasks more bearable. It was amazing to see some of the animation work she’s done and her passion for art and programming was palpable throughout the talk.&lt;/p&gt;
&lt;h3 id=&#34;brian-jordan--no-bugs-in-sight-continuous-visual-tesing-at-codeorg&#34;&gt;Brian Jordan — No Bugs in Sight: Continuous Visual Tesing at Code.org&lt;/h3&gt;
&lt;p&gt;Brian works for &lt;a href=&#34;https://code.org/&#34;&gt;code.org&lt;/a&gt; which is the organization behind the Hour of Code and other initiatives promoting computer science education in schools. His work on apps that teach kids to code is used on a vast variety of hardware (tablets, old underpowered school computers etc.). Testing became a challenge early for them so Brian began to incorporate testing with &lt;a href=&#34;http://www.seleniumhq.org/&#34;&gt;Selenium&lt;/a&gt; into their development workflow. They use &lt;a href=&#34;https://cucumber.io/&#34;&gt;Cucumber&lt;/a&gt; to write their tests. They use &lt;a href=&#34;https://saucelabs.com/&#34;&gt;Sauce Labs&lt;/a&gt; to run the tests and &lt;a href=&#34;https://circleci.com/&#34;&gt;circleCI&lt;/a&gt; to integrate it with their source code control system. When code is committed, the tests are run which ensures broken code does not get merged in. They also use &lt;a href=&#34;https://applitools.com/&#34;&gt;applitools eyes&lt;/a&gt; for visual diffing which looked very interesting. They keep a wiki of the larger and more interesting issues that it catches to help everyone remember them (and sometimes recall why they still need to keep a particular test). Brian showed us several screenshots of visual problems caught by their system including one that was a single pixel showing up in a strange (unwanted) location on the screen.&lt;/p&gt;
&lt;h3 id=&#34;jessica-lord--nativize-is-the-new-normalize&#34;&gt;Jessica Lord — Nativize is the new Normalize&lt;/h3&gt;
&lt;p&gt;Jessica works at GitHub on the &lt;a href=&#34;http://electron.atom.io/&#34;&gt;Electron project&lt;/a&gt;. Her talk was about Electron and how you can use it to build cross-platform (Windows/Linux/Mac) desktop apps using web technologies. Electron is used to power &lt;a href=&#34;https://atom.io/&#34;&gt;Atom&lt;/a&gt;, Slack and &lt;a href=&#34;http://electron.atom.io/apps/&#34;&gt;many other interesting apps&lt;/a&gt;. It uses &lt;a href=&#34;https://developers.google.com/v8/&#34;&gt;V8&lt;/a&gt; as its JavaScript runtime which allows you to use Node.js in your apps. Chromium is used for the all the DOM and rendering bits. She showed off the Electron example app and talked about some tips and tricks to building apps with Electron. Jessica stressed that you have to think about apps differently than web sites. You want your app to feel like an app not a website. She pointed out several good resources for learning more about it. Electron can also be used to build menubar apps for OS X.&lt;/p&gt;
&lt;h3 id=&#34;jen-kramer--css4-grid-true-layout-finally-arrives&#34;&gt;Jen Kramer — CSS4 Grid: True Layout Finally Arrives&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://www.jenkramer.org/&#34;&gt;Jen&lt;/a&gt; is a professor at &lt;a href=&#34;https://developers.google.com/v8/&#34;&gt;Harvard&lt;/a&gt; teaching web development. She talked about CSS grid and how it will make laying out sites much better than the current hacks techniques we have been using up to this point (tables, floats, flexbox). She explained how &lt;a href=&#34;https://css-tricks.com/snippets/css/a-guide-to-flexbox/&#34;&gt;flexbox&lt;/a&gt; was designed to only work in a single dimension (grids need to work in two for both rows &amp;amp; columns) and showed some example layouts built with CSS grid. Jen’s examples showed how many CSS design challenges (e.g.: equal height columns) are easily solved with grid. The only thing holding it back is browser support. Today it’s available in Chrome and Firefox behind a configuration flag. Jen was really funny and engaging and drew everyone in with her presentation skills and passion for web development in general (grid too!).&lt;/p&gt;
&lt;h3 id=&#34;pete-hunt--component-based-style-reuse&#34;&gt;Pete Hunt — Component-Based Style Reuse&lt;/h3&gt;
&lt;p&gt;Pete talked about &lt;a href=&#34;https://facebook.github.io/react/&#34;&gt;React&lt;/a&gt; and how it can be used to create components (e.g.: a piece of UI that can be re-used in different contexts). He shared how &lt;a href=&#34;https://github.com/stubbornella/oocss/wiki&#34;&gt;OOCSS&lt;/a&gt; was a foundational concept and inspiration to him and walked through the process of building a React component that implemented an OOCSS “media block” component. Having previously worked at FaceBook, Pete discussed the issues that arise when developing many UI components at scale—​especially CSS class conflicts and the resulting style pollution. Pete used &lt;a href=&#34;https://github.com/smyte/jsxstyle&#34;&gt;jsxstyle&lt;/a&gt; (developed by his current team at Smyte) in his React component to keep the styles scoped to the component and avoid using descendent selectors. It was very interesting talk and I recommend watching the &lt;a href=&#34;https://2016.cssconf.com/#videos&#34;&gt;video of Pete’s talk&lt;/a&gt; to get the full effect.&lt;/p&gt;
&lt;h3 id=&#34;keith-j-grant--stop-thinking-in-pixels&#34;&gt;Keith J. Grant — Stop Thinking in Pixels&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://keithjgrant.com/&#34;&gt;Keith&lt;/a&gt; works for the &lt;a href=&#34;https://theice.com/&#34;&gt;company behind the NYSE website&lt;/a&gt;. He thoroughly explained how to effectively use em and rem units for font-size and other properties and how he recommends avoiding using pixels for font sizes altogether. Keith showed many examples using rem to set the font size for a container element and then use ems for all of its children. This had the benefit of flexibility and made is possible to adjust the sizes of all of the child elements by simply changing the size on the parent/container. He covered several formulas which can be used to determine the em values you will need for approximate pixel sizes. He shared &lt;a href=&#34;http://type-scale.com/&#34;&gt;type-scale.com&lt;/a&gt; as a web app that can help with these calculations. Once you understand the formulas, you can add mixins in Sass to perform the calculations for you. Near the end of his talk Keith showed us an example using rems for the parent, ems for the child elements and then combining calc() with viewport units (vh, vw) to smoothly scale the size of a component as the viewport changes. This was really neat to see and avoided the clunky switch between sizes that happens when the viewport changes between media queries. With the technique Keith demonstrated, the scaling was completely fluid—​very impressive. Keith wrapped up by explaining that these techniques require a little work up front and often educating other developers on the team but the benefits are immediate.&lt;/p&gt;
&lt;h3 id=&#34;will-boyd--silky-smooth-animation-with-css&#34;&gt;Will Boyd — Silky Smooth Animation with CSS&lt;/h3&gt;
&lt;p&gt;Will talked about the deep dive he took into how browsers handle rendering and animation. He demoed how we can look into the process for our own performance debugging with tools like Chrome DevTools. To illustrate some of the performance wins Will had discovered in his own projects, he loaded up an animation he’d built for the talk and compared the performance before and after he used CSS properties that could be handled by the GPU. The performance improvement using transform, filter and opacity (all hardware-accelerated and rendered by the GPU) was drastic and impressive.&lt;/p&gt;
&lt;h3 id=&#34;lea-verou--css-variables-varsubtitle&#34;&gt;Lea Verou — CSS Variables var(&amp;ndash;subtitle);&lt;/h3&gt;
&lt;p&gt;Lea’s talk was about CSS variables (aka custom properties). I admit to being surprised when I looked it up recently and found that they were already &lt;a href=&#34;http://caniuse.com/#feat=css-variables&#34;&gt;quite widely supported&lt;/a&gt;. The syntax looks little odd at first but it made sense when Lea explained it was intentional that they look different than preprocessor variables. I found it interesting that CSS variables are expected to be used alongside preprocessor variables rather than replacing them. Lea explained how they work, how they can be accessed by JavaScript and demonstrated several things CSS variables can do that preprocessor variables can not! Make sure to check out the &lt;a href=&#34;https://2016.cssconf.com/#videos&#34;&gt;video of her talk&lt;/a&gt; when you get the chance.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Zurb Foundation 5: Applying Styles Conditionally Based on Viewport Size</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/02/zurb-foundation-5-applying-styles/"/>
      <id>https://www.endpointdev.com/blog/2016/02/zurb-foundation-5-applying-styles/</id>
      <published>2016-02-08T00:00:00+00:00</published>
      <author>
        <name>Patrick Lewis</name>
      </author>
      <content type="html">
        &lt;p&gt;The &lt;a href=&#34;https://get.foundation/sites/docs-v5/&#34;&gt;Zurb Foundation 5&lt;/a&gt; front-end framework provides many convenient features such as the ability to control the visibility of HTML elements for different browser window sizes using CSS classes. Foundation CSS classes like “show-for-small-only” and “hide-for-large-up” (full list at &lt;a href=&#34;https://get.foundation/sites/docs-v5/components/visibility.html&#34;&gt;https://get.foundation/sites/docs-v5/components/visibility.html&lt;/a&gt;) make it easy to add mobile-specific content to your page or prevent certain page elements from being displayed on mobile devices.&lt;/p&gt;
&lt;p&gt;Having an easy way to show/hide elements based on viewport size is nice, but what if you want to style an element differently based on the size of the browser that’s viewing the page? Foundation has you covered there, too, though the method is less obvious. It’s possible to use Foundation’s media query SCSS variables when writing your own custom styles in order to apply different styling rules for different viewport sizes.&lt;/p&gt;
&lt;p&gt;For example, if you have an element that you want to offset with a margin in a large window but be flush with the left edge of a small window, you can use the Foundation media query variables to apply a styling override that’s specific to small windows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-scss&#34; data-lang=&#34;scss&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;#element&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#369&#34;&gt;margin-left&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;@media&lt;/span&gt; &lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;&lt;span style=&#34;color:#369&#34;&gt;$small-only&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#369&#34;&gt;margin-left&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will apply a specific set of styling to the element for small viewports and a different set for medium and larger viewports (with the definitions for “small”, “medium”, etc. corresponding to the same values used by Foundation’s visibility classes like “show-for-small-only” which were mentioned at the start of this post).&lt;/p&gt;
&lt;p&gt;It wasn’t immediately obvious to me how to apply conditional styling using Foundation’s own definitions of small, medium, etc. viewport sizes but luckily the variable definitions provided by the SCSS framework make it easy to do so.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Full Screen Gallery with Supersized and video slides</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2016/01/full-screen-gallery-with-supersized-and/"/>
      <id>https://www.endpointdev.com/blog/2016/01/full-screen-gallery-with-supersized-and/</id>
      <published>2016-01-26T00:00:00+00:00</published>
      <author>
        <name>Marina Lohova</name>
      </author>
      <content type="html">
        &lt;p&gt;I was recently looking to build a full screen image and video gallery for our client &lt;a href=&#34;https://mission-blue.org/&#34;&gt;Mission Blue&lt;/a&gt;. Something similar to the Google Maps interface you can see in the screenshot below:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;    &lt;a href=&#34;/blog/2016/01/full-screen-gallery-with-supersized-and/image-0-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;       &lt;img border=&#34;0&#34; src=&#34;/blog/2016/01/full-screen-gallery-with-supersized-and/image-0.png&#34; width=&#34;600&#34;/&gt;     &lt;/a&gt;   &lt;/div&gt;
&lt;p&gt;After scouring the Internet to find a suitable jQuery plugin I finally decided on &lt;a href=&#34;https://web.archive.org/web/20170629183603/http://buildinternet.com/2009/05/supersized-20-full-screen-imagebackground-slideshow-jquery-plugin-w-transitions-and-controls/&#34;&gt;Supersized, Full screen background slideshow plugin for jQuery&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After downloading the library, include it on the page:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;href&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/wp-content/plugins/wp-supersized/theme/supersized.shutter.css?ver=4.2.2&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;supersized_theme_css-css&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;media&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;all&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;rel&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;link&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/wp-includes/js/jquery/ui/effect.min.js?ver=1.11.4&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/wp-content/plugins/wp-supersized/js/jquery.easing.min.js?ver=1.3&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/wp-content/plugins/wp-supersized/js/jquery.easing.compatibility.js?ver=1.0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;/wp-content/plugins/wp-supersized/js/jquery.animate-enhanced.min.js?ver=0.75&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;text/javascript&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;/wp-content/plugins/wp-supersized/js/supersized.3.2.7.min.js?ver=3.2.7&amp;#39;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;basic-functionality&#34;&gt;Basic functionality&lt;/h3&gt;
&lt;p&gt;Let’s create a variable that will hold all the images in the slideshow:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; images = [];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;images.push({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;IMAGE&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  image: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;img1.jpg&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  title: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;Image 1&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  thumb: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;img1_thumb.jpg&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  url: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;https://www.endpointdev.com&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;images.push({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  type: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;YOUTUBE&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  image: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;screenshot1.jpg&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  title: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;YouTube slide&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  videoid: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;abc12345678&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  thumb: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;screenshot1_thumb.jpg&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  url: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;https://www.youtube.com/watch?v=abc12345678&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let’s initialize Supersized:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jQuery.supersized({
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  slideshow: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  autoplay: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  min_width: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  min_height: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  vertical_center: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  horizontal_center: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fit_always: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fit_portrait: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  fit_landscape: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  slide_links: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;blank&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  thumb_links: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  thumbnail_navigation: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  slides: images,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  mouse_scrub: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;customizing-the-toolbar&#34;&gt;Customizing the toolbar&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;thumb-tray&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;load-item&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;thumb-back&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;thumb-forward&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;slidecaption&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;customizing-the-screen-image-size&#34;&gt;Customizing the screen image size&lt;/h3&gt;
&lt;p&gt;I didn’t want to have the full screen image as it was a little overwhelming for the user. I wanted the black bars just like in the Google interface. Supersized allows for easy customization. This CSS did the trick:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;supersized&lt;/span&gt;, #&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;supersized&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;70&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;!important&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;left&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;!important&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;right&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;!important&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;top&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;!important&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;:&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;auto&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;introducing-video-youtube-slides&#34;&gt;Introducing video (YouTube) slides&lt;/h3&gt;
&lt;p&gt;First, I added the Youtube API:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/javascript&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;https://www.youtube.com/iframe_api&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then I added a couple of CSS styles:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;supersized&lt;/span&gt; .&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;player&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;auto&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;block&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, I went into the Supersized library source and modified it. To allow for the video slides to appear, I added the new condition and the slide type &amp;lsquo;YOUTUBE&amp;rsquo;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;base._renderSlide = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(loadPrev, options) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; linkTarget = base.options.new_window ? &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; target=&amp;#34;_blank&amp;#34;&amp;#39;&lt;/span&gt; : &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; imageLink = (base.options.slides[loadPrev].url) ? &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;href=&amp;#39;&amp;#34;&lt;/span&gt; + base.options.slides[loadPrev].url + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#39;&amp;#34;&lt;/span&gt; : &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; slidePrev = base.el + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39; li:eq(&amp;#39;&lt;/span&gt; + loadPrev + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; imgPrev = $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;img src=&amp;#34;&amp;#39;&lt;/span&gt; + base.options.slides[loadPrev].image + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#34;/&amp;gt;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (base.options.slides[loadPrev].type == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;YOUTUBE&amp;#39;&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imgPrev.load(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; video = $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;div class=&amp;#34;player&amp;#34; id=&amp;#34;player&amp;#39;&lt;/span&gt;+ base.options.slides[loadPrev].videoid + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;#34;&amp;gt;&amp;lt;/div&amp;gt;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      video.appendTo(slidePrev);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; player = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;new&lt;/span&gt; YT.Player(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;player&amp;#39;&lt;/span&gt; + base.options.slides[loadPrev].videoid, {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        height: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;390&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        width: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;640&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        videoId: base.options.slides[loadPrev].videoid
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });&lt;span style=&#34;color:#888&#34;&gt;// End Load
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imgPrev.appendTo(slidePrev).wrap(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;a &amp;#39;&lt;/span&gt; + imageLink + linkTarget + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;gt;&amp;lt;/a&amp;gt;&amp;#39;&lt;/span&gt;).parent().parent().addClass(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;image-loading &amp;#39;&lt;/span&gt; + options[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;class&amp;#39;&lt;/span&gt;]);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    imgPrev.load(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      $(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;).data(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;origWidth&amp;#39;&lt;/span&gt;, $(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;).width()).data(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;origHeight&amp;#39;&lt;/span&gt;, $(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;).height());
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      base.resizeNow();&lt;span style=&#34;color:#888&#34;&gt;// Resize background image
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    });&lt;span style=&#34;color:#888&#34;&gt;// End Load
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;final-result&#34;&gt;Final Result&lt;/h3&gt;
&lt;p&gt;This is how gallery looks with the customizations:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;  &lt;a href=&#34;/blog/2016/01/full-screen-gallery-with-supersized-and/image-1-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;     &lt;img border=&#34;0&#34; src=&#34;/blog/2016/01/full-screen-gallery-with-supersized-and/image-1.png&#34; width=&#34;600&#34;/&gt;   &lt;/a&gt; &lt;/div&gt;
&lt;p&gt;This is what a video slide looks like:&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;  &lt;a href=&#34;/blog/2016/01/full-screen-gallery-with-supersized-and/image-2-big.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34;&gt;     &lt;img border=&#34;0&#34; src=&#34;/blog/2016/01/full-screen-gallery-with-supersized-and/image-2.png&#34;/&gt;   &lt;/a&gt; &lt;/div&gt;
&lt;p&gt;Hope you found this writeup useful!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Old Dog &amp; New Tricks — Giving Interchange a New Look with Bootstrap</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/09/old-dog-new-tricks-giving-interchange/"/>
      <id>https://www.endpointdev.com/blog/2015/09/old-dog-new-tricks-giving-interchange/</id>
      <published>2015-09-02T00:00:00+00:00</published>
      <author>
        <name>Greg Hanson</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;introduction&#34;&gt;Introduction&lt;/h3&gt;
&lt;p&gt;So your &lt;a href=&#34;http://www.icdevgroup.org&#34;&gt;Interchange&lt;/a&gt; based website looks like it walked out of a disco&amp;hellip; but you spent a fortune getting the back end working with all those custom applications&amp;hellip;. what to do?&lt;/p&gt;
&lt;p&gt;Interchange is currently being used in numerous very complex implementations. Trying to adapt another platform to replace Interchange is a formidable task, and in many cases the “problem” that users are trying to “solve” by replacing Interchange, can be remedied by a relatively simple face lift to the front end. One of the main attractions to Interchange in the past was its ability to scale from a small mom &amp;amp; pop eCommerce application, to a mid level support system for a larger company and its related back end systems. Once the connection to those back end systems has been created, and for as long as you use those related systems, Interchange will continue to be the most economic choice for the job. But that leaves the front end, the one that your customers see and use (with their phones and tablets) that becomes the most immediate target for “modernization”.&lt;/p&gt;
&lt;p&gt;Granted, there are new and alternate ways of accessing and presenting data and views to users, but many of those alternatives are also accessible and inter-operable with Interchange. So while there are several topics that can be investigated at length, we will focus first on a popular front end framework that can help Interchange present a modern responsive theme to the end users. That framework is &lt;a href=&#34;http://getbootstrap.com/&#34;&gt;Bootstrap&lt;/a&gt;. Bootstrap is a good basic start for breathing new life into your Interchange application. Bootstrap uses a reasonably generic approach to HTML, CSS, and JavaScript frameworking. This blends nicely with the Interchange application approach: providing a basic, repeatable, broad based and well supported foundation that can then be crafted into whatever the developer and their client may need.&lt;/p&gt;
&lt;p&gt;My intent in this post, is to give you links to the tools available to implement Bootstrap into your Interchange application, and in subsequent posts explain our development process which may help you in how you use the tools.  Like any development, there are many ways to accomplish various tasks, and knowing why certain things were done, can help.&lt;/p&gt;
&lt;p&gt;Alternatively, you may simply want to just download the “strap” catalog, and get started. At the time of this writing, Josh Lavin has been reviewing and refining the package, and the most recent version can be found at his Github account: &lt;a href=&#34;https://github.com/jdigory/strap&#34;&gt;Bootstrap template for Interchange&lt;/a&gt;. It will soon become the standard catalog template in Interchange. So, if you are not really interested in why and how this template was developed, feel free to go to the git repository in the link, clone a copy and get busy!  The &lt;a href=&#34;https://github.com/jdigory/strap/blob/master/README.md&#34;&gt;README&lt;/a&gt; is very informative, and if you are an Interchange developer you probably won’t have much trouble implementing this.&lt;/p&gt;
&lt;p&gt;If you are interested in some of the major changes that we made to the old “standard” templating approach, and how you can apply those changes to an existing catalog without having to start from scratch, stay tuned in for my next post.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Angular Responsive Layout Directive</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2015/01/angular-responsive-layout-directive/"/>
      <id>https://www.endpointdev.com/blog/2015/01/angular-responsive-layout-directive/</id>
      <published>2015-01-13T00:00:00+00:00</published>
      <author>
        <name>Marina Lohova</name>
      </author>
      <content type="html">
        &lt;p&gt;To all of you window.onResize aficionados, I dedicate this blog post because today we will be doing a lot of dynamic resizing in JavaScript. All of it will be done completely and effortlessly with my one-page long Angular directive.&lt;/p&gt;
&lt;p&gt;Why do I need to attach an expensive onResize handler to my already overloaded page, you ask. The answer is very simple. Our app layout is pixel-perfect. Each element has the predefined width and margins. Yet, the app needs to look good on all kind of devices, from regular PC to tablet to iPhone. That’s why I created the following Angular directive in /scripts/directives/tsResize.js:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;angular.module(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;angularApp&amp;#39;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.directive(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;tsResize&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;($window) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(scope, element) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; w = angular.element($window);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   scope.getWindowDimensions = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;h&amp;#39;&lt;/span&gt;: $window.innerHeight,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;: $window.innerWidth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   scope.$watch(scope.getWindowDimensions,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;              &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; (newValue, oldValue) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     scope.windowHeight = newValue.h;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     scope.windowWidth = newValue.w;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     scope.mainContainerStyle = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (newValue.w &amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;890&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         val = newValue.w/&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;890&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-o-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-ms-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;transform-origin&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;left -10px&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform-origin&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;left -10px&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     scope.topBarStyle = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (newValue.w &amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;890&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         val = newValue.w/&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;890&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-o-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-ms-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;transform-origin&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;0 2px 0&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform-origin&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;0 2px 0&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   w.bind(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;resize&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     scope.$apply();
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see all the magic is done with transform:scale CSS attribute on the two of my main page components: the navigation and the contents container.&lt;/p&gt;
&lt;p&gt;They styles are cross-browser.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-o-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-ms-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It’s important to set transform-origin, or the elements will be weirdly positioned on the page.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;transform-origin&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;0 top&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform-origin&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;0 top&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The style calculations are attached to the changes of window dimensions.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scope.getWindowDimensions = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; () {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;h&amp;#39;&lt;/span&gt;: $window.innerHeight,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;: $window.innerWidth
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scope.$watch(scope.getWindowDimensions,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;             &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt; (newValue, oldValue) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Few other things. My layout was sliced to the fixed width of 890px, that’s why I took 890 as the pivotal point of my scale ratio formula. You should take the default width of the layout as the base of your calculation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; (newValue.w &amp;gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;890&lt;/span&gt;) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {};
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  val = newValue.w/&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;890&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;-webkit-transform&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;scale(&amp;#39;&lt;/span&gt; + val + &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;)&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With the directive in place it’s time to plug it in:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;src&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;scripts/directives/tsResize.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;script&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;nav&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-style&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;topBarStyle()&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ts-resize&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;nav&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-style&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;mainContainerStyle()&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ng-view&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;ts-resize&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be sure to use style “display:block” or “display:inline-block” and “position:relative” for all the inside components of the scaled elements with the default display. Otherwise they do not obey the scaling enforcement and grow way too long prompting a scrollbar.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;main-container&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;inner-block&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;position:relative; display:inline-block&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It all worked nicely and I was able to enjoy the smoothly resizing layout.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Simplifying mobile development with Ionic Framework</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/11/simplifying-mobile-development-with/"/>
      <id>https://www.endpointdev.com/blog/2014/11/simplifying-mobile-development-with/</id>
      <published>2014-11-06T00:00:00+00:00</published>
      <author>
        <name>Kamil Ciemniewski</name>
      </author>
      <content type="html">
        &lt;p&gt;My high school math teacher used to say that mathematicians are the laziest people on Earth. Why? Because they always look for clever ways to simplify their work.&lt;/p&gt;
&lt;p&gt;If you stop and think about it, all that technology is, is just simplification. It’s taking the infinitely complex world and turning it into something sterile and simple. It’s all about producing simple models with a limited number of elements and processes.&lt;/p&gt;
&lt;p&gt;Today I’d like to walk you through creation of a mobile app that could be used on iOS, Android or Windows Phone. We’ll use a very cool set of technologies that allow us to switch from using multiple languages and frameworks (Objective-C for iOS, Java for Android and C# for Windows Phone) to just using HTML, CSS and JavaScript.&lt;/p&gt;
&lt;p&gt;Let’s start turning complex into simple!&lt;/p&gt;
&lt;h3 id=&#34;phonegap-and-ionic-framework&#34;&gt;PhoneGap and Ionic Framework&lt;/h3&gt;
&lt;h4 id=&#34;creating-the-project&#34;&gt;Creating the project&lt;/h4&gt;
&lt;p&gt;In order to be able to start playing along, you need to get yourself a set of toys. Assuming that you’ve got NodeJS and Npm installed already, all you have to do is:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ npm install -g cordova ionic&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now you should be able to create the project’s scaffold. We’ll be creating a simple app that will list all the latest cartoons from &lt;a href=&#34;https://xkcd.com&#34;&gt;the xkcd blog&lt;/a&gt;. Let’s call it Cartoonic.&lt;/p&gt;
&lt;p&gt;Ionic comes with a handy tool called ‘ionic’. It allows you to create a new project as well as perform some automated project-structure-management tasks. The project creation task accepts a ‘skeleton’ name that drives an initial layout of the app. Possible options are: ‘blank’, ‘tabs’ and ‘sidemenu’.&lt;/p&gt;
&lt;p&gt;We’ll be creating an app from scratch so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ionic start Cartoonic blank&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The framework gives you an option of whether you want to use Sass or just plain old Css. To turn Sass on for the project run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ &lt;span style=&#34;color:#038&#34;&gt;cd&lt;/span&gt; Cartoonic &amp;amp;&amp;amp; ionic setup sass&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All went well, but now let’s see if it &lt;em&gt;works&lt;/em&gt; well. For this, Ionic gives you an ability to test your app in the browser, as if it were a screen of your mobile device. To run the app in the browser now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ionic serve&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2014/11/simplifying-mobile-development-with/image-0.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34; target=&#34;_blank&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/11/simplifying-mobile-development-with/image-0.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;h4 id=&#34;working-with-the-app-layout&#34;&gt;Working with the app layout&lt;/h4&gt;
&lt;p&gt;We need to let all users know what a cool name we’ve chosen for our app. The default one provided by the scaffold wouldn’t work well. Also we’d like the color of the header to be blue instead of the default white.&lt;/p&gt;
&lt;p&gt;In order to do so you can take a look at the CSS documentation for different aspects of the UI:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://ionicframework.com/docs/components/#header&#34;&gt;https://ionicframework.com/docs/components/#header&lt;/a&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;@@ -21,8 +21,8 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;&lt;/span&gt;     &amp;lt;ion-pane&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      &amp;lt;ion-header-bar class=&amp;#34;bar-stable&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-        &amp;lt;h1 class=&amp;#34;title&amp;#34;&amp;gt;Ionic Blank Starter&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      &amp;lt;ion-header-bar class=&amp;#34;bar-positive&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        &amp;lt;h1 class=&amp;#34;title&amp;#34;&amp;gt;Cartoonic&amp;lt;/h1&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;       &amp;lt;/ion-header-bar&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &amp;lt;ion-content&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &amp;lt;/ion-content&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2014/11/simplifying-mobile-development-with/image-1.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34; target=&#34;_blank&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/11/simplifying-mobile-development-with/image-1.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;So far so good, now let’s play with the list of cartoons:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/scss/ionic.app.scss
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/scss/ionic.app.scss
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+.cartoon {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  text-align: center;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.2);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  width: 96%;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  margin-left: 2%;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  margin-top: 2%;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  margin-bottom: 2%;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  img {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    width: 90%;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+}
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        &amp;lt;ion-list&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;item-divider&amp;#34;&amp;gt;Where Do Birds Go&amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+            &amp;lt;img src=&amp;#34;http://imgs.xkcd.com/comics/where_do_birds_go.png&amp;#34; alt=&amp;#34;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;item-divider&amp;#34;&amp;gt;Lightsaber&amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+            &amp;lt;img src=&amp;#34;http://imgs.xkcd.com/comics/lightsaber.png&amp;#34; alt=&amp;#34;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        &amp;lt;/ion-list&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;       &amp;lt;/ion-content&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2014/11/simplifying-mobile-development-with/image-2.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34; target=&#34;_blank&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/11/simplifying-mobile-development-with/image-2.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Alright, we’ve got the list that’s looking quite nice. The data behind is static, but for now we just wanted to make sure the look&amp;amp;feel is good.&lt;/p&gt;
&lt;h4 id=&#34;using-angularjs-to-manage-the-app&#34;&gt;Using AngularJS to manage the app&lt;/h4&gt;
&lt;p&gt;Ionic is built around the fantastic AngularJS framework. That’s our means of developing the logic behind. We need to make the list of cartoons use real data from the Xckd blog RSS feed. We also need to enable tapping on images to see the picture in the browser (so it can be zoomed in).&lt;/p&gt;
&lt;p&gt;Let’s start with making the UI use dynamically bound data that we can operate on with JavaScript. In order to do so, we need to add a controller for our view. We also need to specify the data binding between the markup we’ve created previously and the variable in the controller that we intend to use as our data store.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     &amp;lt;script src=&amp;#34;js/app.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;lt;script src=&amp;#34;js/controllers.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;   &amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  &amp;lt;body ng-app=&amp;#34;starter&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  &amp;lt;body ng-app=&amp;#34;starter&amp;#34; ng-controller=&amp;#34;CartoonsCtrl&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(...)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &amp;lt;ion-content&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &amp;lt;ion-list&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-          &amp;lt;ion-item class=&amp;#34;item-divider&amp;#34;&amp;gt;Where Do Birds Go&amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-            &amp;lt;img src=&amp;#34;http://imgs.xkcd.com/comics/where_do_birds_go.png&amp;#34; alt=&amp;#34;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-          &amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-          &amp;lt;ion-item class=&amp;#34;item-divider&amp;#34;&amp;gt;Lightsaber&amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-            &amp;lt;img src=&amp;#34;http://imgs.xkcd.com/comics/lightsaber.png&amp;#34; alt=&amp;#34;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;item-divider&amp;#34; ng-repeat-start=&amp;#34;cartoon in cartoons&amp;#34;&amp;gt;{{ cartoon.title }}&amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34; ng-repeat-end&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+            &amp;lt;img ng-src=&amp;#34;{{ cartoon.href }}&amp;#34; alt=&amp;#34;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;           &amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &amp;lt;/ion-list&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &amp;lt;/ion-content&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/js/app.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/js/app.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-angular.module(&amp;#39;starter&amp;#39;, [&amp;#39;ionic&amp;#39;])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+angular.module(&amp;#39;starter&amp;#39;, [&amp;#39;ionic&amp;#39;, &amp;#39;starter.controllers&amp;#39;])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/js/controllers.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+angular.module(&amp;#39;starter.controllers&amp;#39;, [])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+.controller(&amp;#39;CartoonsCtrl&amp;#39;, function($scope) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  $scope.cartoons = [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      href: &amp;#34;http://imgs.xkcd.com/comics/where_do_birds_go.png&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      id: 1434,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      title: &amp;#34;Where Do Birds Go&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      href: &amp;#34;http://imgs.xkcd.com/comics/lightsaber.png&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      id: 1433,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      title: &amp;#34;Lightsaber&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  ];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can notice that “ng-controller” directive has been added to the body element. It points at the newly created controller, which we’re loading with a script tag and making available to the rest of the app by including its module (starter.controllers) in the ‘starter’ module’s dependencies list.&lt;/p&gt;
&lt;p&gt;Let’s implement opening the picture upon the tap:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;       &amp;lt;ion-content&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &amp;lt;ion-list&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &amp;lt;ion-item class=&amp;#34;item-divider&amp;#34; ng-repeat-start=&amp;#34;cartoon in cartoons&amp;#34;&amp;gt;{{ cartoon.title }}&amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34; ng-repeat-end&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          &amp;lt;ion-item class=&amp;#34;cartoon&amp;#34; ng-repeat-end ng-click=&amp;#34;openCartoon(cartoon)&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;             &amp;lt;img ng-src=&amp;#34;{{ cartoon.href }}&amp;#34; alt=&amp;#34;&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;           &amp;lt;/ion-item&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &amp;lt;/ion-list&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/js/controllers.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/js/controllers.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;@@ -13,4 +13,8 @@ angular.module(&amp;#39;starter.controllers&amp;#39;, [])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;&lt;/span&gt;       title: &amp;#34;Lightsaber&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   ];
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  $scope.openCartoon = function(cartoon) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    window.open(cartoon.href, &amp;#39;_blank&amp;#39;, &amp;#39;location=no&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That was simple wasn’t it? We’ve just added the ng-click directive making the click/tap event bound to the openCartoon function from the scope. This function in turn is using window.open passing ‘_blank’ as target. Et voilà!&lt;/p&gt;
&lt;p&gt;Now, let’s implement loading images from the real feed:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-diff&#34; data-lang=&#34;diff&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/index.html
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;     &amp;lt;script src=&amp;#34;cordova.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;lt;script type=&amp;#34;text/javascript&amp;#34; src=&amp;#34;https://www.google.com/jsapi&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;lt;script type=&amp;#34;text/javascript&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      google.load(&amp;#34;feeds&amp;#34;, &amp;#34;1&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;lt;!-- your app&amp;#39;s js --&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;lt;script src=&amp;#34;js/app.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &amp;lt;script src=&amp;#34;js/controllers.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    &amp;lt;script src=&amp;#34;js/services.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;   &amp;lt;/head&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &amp;lt;body ng-app=&amp;#34;starter&amp;#34; ng-controller=&amp;#34;CartoonsCtrl&amp;#34;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/js/app.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/js/app.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-angular.module(&amp;#39;starter&amp;#39;, [&amp;#39;ionic&amp;#39;, &amp;#39;starter.controllers&amp;#39;])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+angular.module(&amp;#39;starter&amp;#39;, [&amp;#39;ionic&amp;#39;, &amp;#39;starter.controllers&amp;#39;, &amp;#39;starter.services&amp;#39;])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- a/www/js/controllers.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/js/controllers.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-angular.module(&amp;#39;starter.controllers&amp;#39;, [])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+angular.module(&amp;#39;starter.controllers&amp;#39;, [&amp;#39;starter.services&amp;#39;])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-.controller(&amp;#39;CartoonsCtrl&amp;#39;, function($scope) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  $scope.cartoons = [
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      href: &amp;#34;http://imgs.xkcd.com/comics/where_do_birds_go.png&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      id: 1434,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      title: &amp;#34;Where Do Birds Go&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      href: &amp;#34;http://imgs.xkcd.com/comics/lightsaber.png&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      id: 1433,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-      title: &amp;#34;Lightsaber&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;-  ];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+.controller(&amp;#39;CartoonsCtrl&amp;#39;, function($scope, cartoons) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  $scope.cartoons = [];
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   $scope.openCartoon = function(cartoon) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     window.open(cartoon.href, &amp;#39;_blank&amp;#39;, &amp;#39;location=no&amp;#39;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   };
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  $scope.$watch(function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    return cartoons.list;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  }, function(list) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    $scope.cartoons = list;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt; });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;--- /dev/null
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#fdd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+++ b/www/js/services.js
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#666&#34;&gt;@@ -0,0 +1,26 @@
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#666&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+angular.module(&amp;#39;starter.services&amp;#39;, [])
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+.factory(&amp;#39;cartoons&amp;#39;, function($rootScope) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  var self = {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    list: [],
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    url: &amp;#34;http://xkcd.com/rss.xml&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    fetch: function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      var feed = new google.feeds.Feed(self.url);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      feed.load(function(result) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        $rootScope.$apply(function() {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          if(result.status.code == 200) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+            self.list = result.feed.entries.map(function(entry) {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+              return {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                href: entry.content.match(/src=&amp;#34;[^&amp;#34;]*/g)[0].substring(5, 100),
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+                title: entry.title
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+              }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+            });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+          }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+        });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+      });
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+    }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  self.fetch();
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+  return self;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#000;background-color:#dfd&#34;&gt;+});
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Okay, a couple of comments here. You may wonder why have we loaded Google APIs? That’s because if we were to try to load the xml that comes from the blog’s feed, we would inevitably fail because of the “&lt;a href=&#34;https://en.wikipedia.org/wiki/Same-origin_policy&#34;&gt;Same Origin Policy&lt;/a&gt;”. Basically, the Ajax request would not complete successfully and there’s nothing we can do locally about it.&lt;/p&gt;
&lt;p&gt;Luckily, Google has created a service we can use as a middleman between our in-browser JavaScript code and blog’s web server. Long story made short: when you load the feed with Google’s Feed API - the data’s there and it’s also already parsed.&lt;/p&gt;
&lt;p&gt;We’re also adding a custom service here. The service fetches the entries upon its initialization. And because the controller’s depending on this service - we’re guaranteed to get the data as soon as the controller is initialized. The controller is also using the $watch function to make sure it has the most recent copy of the entries list.&lt;/p&gt;
&lt;div class=&#34;separator&#34; style=&#34;clear: both; text-align: center;&#34;&gt;&lt;a href=&#34;/blog/2014/11/simplifying-mobile-development-with/image-3.png&#34; imageanchor=&#34;1&#34; style=&#34;margin-left: 1em; margin-right: 1em;&#34; target=&#34;_blank&#34;&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2014/11/simplifying-mobile-development-with/image-3.png&#34;/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://ionicframework.com/docs/&#34;&gt;Ionic docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://developers.google.com/feed/v1/&#34;&gt;Google Feed API docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Same-origin_policy&#34;&gt;Same Origin Policy on Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://xkcd.com&#34;&gt;The xkcd blog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSS table-cells ::before and ::after</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/11/css-table-cells-before-and-after/"/>
      <id>https://www.endpointdev.com/blog/2014/11/css-table-cells-before-and-after/</id>
      <published>2014-11-05T00:00:00+00:00</published>
      <author>
        <name>Kent Krenrich</name>
      </author>
      <content type="html">
        &lt;p&gt;When laying out HTML forms, instead of using a table (re: tables-are-only-for-tabular-data et al), I’ve had good results making use of the table family of values for the CSS display property. I find it a reliable way to ensure items line up in a wide range of situations, a change in the size of labels or a resize of the browser’s window for example.&lt;/p&gt;
&lt;p&gt;Something simple like the following has worked well for me on several occasions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;table&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;table&lt;/span&gt;&amp;gt;* {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table-row&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;table&lt;/span&gt;&amp;gt;*&amp;gt;* {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table-cell&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Occasionally though, I’ve wanted to leave a column empty for one reason or another. To accomplish this I found myself including empty HTML tags like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;form&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;table&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;A Cell&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;A Cell&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;A Cell&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;form&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The empty elements function well enough but they feel a little out of place. Recently I came up with a solution I like better. By using the CSS ::after and ::before selectors, you can insert an arbitrary element that can take the place of a missing cell. The following CSS rule can be used to replace the empty div above.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;table&lt;/span&gt;&amp;gt;*:&lt;span style=&#34;color:#555&#34;&gt;nth-child&lt;/span&gt;(&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;2&lt;/span&gt;)::&lt;span style=&#34;color:#555&#34;&gt;before&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;content&lt;/span&gt;: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;table-cell&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The nth-child(2) selector can be tailored to your given situation. You could replace it with something like a specific CSS class that you assign to the rows that you want to include empty columns.&lt;/p&gt;
&lt;p&gt;Making use of CSS selectors instead of extra HTML elements can help you respect the separation of your document content from your document presentation. If at a later date, you decide you want to switch to a layout that doesn’t resemble a table, you can simply update the CSS rules to achieve a different look.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Laziness is a virtue</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/06/laziness-is-virtue/"/>
      <id>https://www.endpointdev.com/blog/2014/06/laziness-is-virtue/</id>
      <published>2014-06-23T00:00:00+00:00</published>
      <author>
        <name>Jeff Boes</name>
      </author>
      <content type="html">
        &lt;p&gt;Laziness &lt;em&gt;is a &lt;a href=&#34;http://threevirtues.com/&#34;&gt;virtue&lt;/a&gt;.&lt;/em&gt; Blessed Saint Larry told me so. And yet I am of little faith &amp;hellip;&lt;/p&gt;
&lt;p&gt;Here I was, banging my head on the keyboard, trying to solve a vertical alignment issue. (The following is a bit simplified for presentation here.)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;floaty&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt; Item 1&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt; Item 2&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;sticky&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;blah blah blah
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &amp;lt;ul&amp;gt; element was supposed to float to the right of the cell, and its individual &amp;lt;li&amp;gt; elements also floated, so that the list would fill up from right to left as more items were added:&lt;/p&gt;
&lt;p&gt;One item:&lt;/p&gt;
&lt;div style=&#34;width: 50%; height: 40px&#34;&gt;
&lt;ul style=&#34;list-style-type: none&#34;&gt;
&lt;li style=&#34;border: 1px solid white; height: 20px; text-align: center; width: 40px; float: right&#34;&gt;1&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Two items:&lt;/p&gt;
&lt;div style=&#34;width: 50%; height: 40px&#34;&gt;
&lt;ul style=&#34;list-style-type: none&#34;&gt;
&lt;li style=&#34;border: 1px solid white; height: 20px; text-align: center; width: 40px; float: right&#34;&gt;1&lt;/li&gt;
&lt;li style=&#34;border: 1px solid white; height: 20px; text-align: center; width: 40px; float: right&#34;&gt;2&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Three items:&lt;/p&gt;
&lt;div style=&#34;width: 50%; height: 40px&#34;&gt;
&lt;ul style=&#34;list-style-type: none&#34;&gt;
&lt;li style=&#34;border: 1px solid white; height: 20px; text-align: center; width: 40px; float: right&#34;&gt;1&lt;/li&gt;
&lt;li style=&#34;border: 1px solid white; height: 20px; text-align: center; width: 40px; float: right&#34;&gt;2&lt;/li&gt;
&lt;li style=&#34;border: 1px solid white; height: 20px; text-align: center; width: 40px; float: right&#34;&gt;3&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;br/&gt;
&lt;p&gt;etc., while the “sticky” div was supposed to stay on the left. The challenge was when the div got too tall, or the number of list items caused it to wrap around to a new row; the vertical alignment to keep everything nice and centered is probably achievable in CSS, but I decided to be lazy:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;vertical-align: middle&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;sticky&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;blah blah blah
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;style&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;vertical-align: middle&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;floaty&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt; Item 1&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt; Item 2&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;li&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;ul&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;td&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Duh. Seriously. Table cells do a bang-up job of vertical alignment under the worst of conditions. And I’m already in the middle of a table, so the work here was just a matter of adding the appropriate “colspans” elsewhere to account for my column’s bifurcation.&lt;/p&gt;
&lt;p&gt;P.S.: I love the word “bifurcate” and work it in to conversation when I can.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSS Conf US 2014 — Part Two</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/06/css-conf-us-2014-part-two/"/>
      <id>https://www.endpointdev.com/blog/2014/06/css-conf-us-2014-part-two/</id>
      <published>2014-06-04T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;more-thoughts-on-getting-vertical-testing-and-icon-fonts&#34;&gt;More Thoughts on Getting Vertical, Testing and Icon Fonts&lt;/h3&gt;
&lt;p&gt;Without further ado I’ve written up another batch of my notes about three more great talks at CSS Conf US in Amelia Island, Florida last week.&lt;/p&gt;
&lt;h3 id=&#34;antoine-butler--embrace-the-vertical&#34;&gt;Antoine Butler — Embrace the Vertical&lt;/h3&gt;
&lt;p&gt;Antoine shared his observation that vertical media queries are available to CSS developers but not
often used. With the &lt;a href=&#34;https://opensignal.com/reports/fragmentation-2013/&#34;&gt;vast array&lt;/a&gt;
of devices accessing the web today vertical media queries can be a useful tool to adapt your content effectively. Antoine walked us through a couple examples of how he applied this technique in a couple of his projects. The first was a prototype of WikiPedia. While they have gone with a separated mobile site (e.g. en.m.wikipedia.org/), he started with the HTML from the desktop site and applied some vertical media queries to make the content much more digestible. Take a look at &lt;a href=&#34;https://codepen.io/aebsr/pen/BapraL&#34;&gt;his code&lt;/a&gt; to see how it works.&lt;/p&gt;
&lt;p&gt;The second example Antoine demonstrated was for the navigation at &lt;a href=&#34;http://www.vw.com/&#34;&gt;Volkswagen&lt;/a&gt;. The client wanted to display an unlimited number of items in the secondary navigation. Once again Antoine applied vertical media queries to handle the varying number of navigation elements based on the device height. Check out his &lt;a href=&#34;https://codepen.io/aebsr/pen/MWpjoM&#34;&gt;adaptive sticky vertical navigation code&lt;/a&gt; for a closer look.&lt;/p&gt;
&lt;p&gt;Slides from this talk are available here: &lt;a href=&#34;https://speakerdeck.com/aebsr/embrace-the-vertical&#34;&gt;Embrace the Vertical&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;christophe-burgmer--if-your-css-is-happy-and-you-know-it&#34;&gt;Christophe Burgmer — If your CSS is happy and you know it&amp;hellip;&lt;/h3&gt;
&lt;p&gt;This was a really interesting talk about testing your CSS visually with a tool Christophe has been developing called &lt;a href=&#34;http://cburgmer.github.io/csscritic/&#34;&gt;CSS Critic&lt;/a&gt;. Christophe covered some of the existing CSS/HTML testing tools like &lt;a href=&#34;http://docs.seleniumhq.org/&#34;&gt;Selenium&lt;/a&gt; and found that while they worked well they didn’t meet his needs entirely. He wanted a way to visually diff the changes that were made and to be able to write tests for his UI code. For example, when the “accepted” version of the page changed visually, he wanted to be notified and decide whether or not to accept the proposed change.&lt;/p&gt;
&lt;p&gt;Christophe demoed the tool for us and it was really cool to see a visual diff in the browser. For a change that was introduced, screenshots of the old, new and difference were displayed. The user then has the ability to accept / OK the change or reject it. You can view the tool in action on the &lt;a href=&#34;http://cburgmer.github.io/csscritic/&#34;&gt;CSS Critic&lt;/a&gt; site. Under the hood, CSS Critic uses some other nifty projects including &lt;a href=&#34;https://github.com/BBC-News/wraith&#34;&gt;Wraith&lt;/a&gt;, &lt;a href=&#34;https://github.com/Huddle/PhantomCSS&#34;&gt;PhantomCSS&lt;/a&gt;, &lt;a href=&#34;http://casperjs.org/&#34;&gt;CasperJS&lt;/a&gt; and &lt;a href=&#34;https://web.archive.org/web/20160728015647/http://hardy.io/&#34;&gt;Hardy&lt;/a&gt;. Christophe also mentioned &lt;a href=&#34;http://csste.st/&#34;&gt;csste.st&lt;/a&gt; as a site which curates information on all of these topics and projects.&lt;/p&gt;
&lt;p&gt;Slides from this talk are available here: &lt;a href=&#34;http://cburgmer.github.io/csscritic/cssconf2014/#/step-1&#34;&gt;If you CSS is happy and you know it&amp;hellip;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;zach-leatherman--bulletproof-icon-fonts&#34;&gt;Zach Leatherman — Bulletproof Icon Fonts&lt;/h3&gt;
&lt;p&gt;Zach wrote a &lt;a href=&#34;https://filamentgroup.com/lab/bulletproof_icon_fonts.html&#34;&gt;great article&lt;/a&gt; on Bulletproof Accessible Icon Fonts earlier this year and his talk was along similar lines. He chronicled some of the challenges and pitfalls worth knowing about in order to support icon fonts in your sites and applications. Browser support varies a great deal and Zach cited John Holt Ripley’s &lt;a href=&#34;https://web.archive.org/web/20161125011236/http://unicode.johnholtripley.co.uk:80/all/&#34;&gt;Unify&lt;/a&gt; unicode support charts as a helpful reference. He works on the &lt;a href=&#34;https://github.com/filamentgroup/a-font-garde&#34;&gt;a-font-garde&lt;/a&gt; project which documents best (er. bulletproof) practices for working with icon fonts today.&lt;/p&gt;
&lt;h3 id=&#34;stay-tuned&#34;&gt;Stay Tuned&lt;/h3&gt;
&lt;p&gt;Watch for one more post later this week with the last batch of talks from the conf!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSSConf US 2014 — Part One</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2014/05/cssconf-us-2014-part-one/"/>
      <id>https://www.endpointdev.com/blog/2014/05/cssconf-us-2014-part-one/</id>
      <published>2014-05-28T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;geeks-in-paradise&#34;&gt;Geeks in Paradise&lt;/h3&gt;
&lt;img alt=&#34;IMG 2414&#34; border=&#34;0&#34; height=&#34;450&#34; src=&#34;/blog/2014/05/cssconf-us-2014-part-one/image-0.jpeg&#34; title=&#34;IMG_2414.jpg&#34; width=&#34;600&#34;/&gt;
&lt;p&gt;Today I was very lucky to once again attend &lt;a href=&#34;https://2014.cssconf.com/&#34;&gt;CSSConf US&lt;/a&gt; here in &lt;a href=&#34;https://maps.app.goo.gl/VCRCDbanvNCzCS3a8&#34;&gt;Amelia Island, Florida&lt;/a&gt;. &lt;a href=&#34;http://www.stubbornella.org/content/&#34;&gt;Nicole Sullivan&lt;/a&gt; and crew did an excellent job of organizing and curating a wide range of talks specifically geared toward CSS developers. Although I work daily on many aspects of the web stack, I feel like I’m one of the (seemingly) rare few who actually enjoy writing CSS so it was a real treat to spend the day with many like-minded folks.&lt;/p&gt;
&lt;h3 id=&#34;styleguide-driven-development&#34;&gt;Styleguide Driven Development&lt;/h3&gt;
&lt;p&gt;Nicole Sullivan started things off with her talk on Style Guide Driven Development (SGDD). She talked about the process and challenges she and the team at &lt;a href=&#34;https://pivotal.io/labs&#34;&gt;Pivotal Labs&lt;/a&gt; went through when they redesigned the &lt;a href=&#34;https://docs.cloudfoundry.org/devguide/&#34;&gt;Cloud Foundry Developer Console&lt;/a&gt; and how they overcame many of them with the SGDD approach. The idea behind SGDD is to catalog all of the reusable components used in a web project so developers use what’s already there rather than reinventing the wheel for each new feature. The components are displayed in the style guide next to examples of the view code and CSS which makes up each component. The benefits of this approach include enabling a short feedback loop for project managers and designers and encouraging developers who may not be CSS experts to follow the “blessed” path to build components that are consistent and cohesive with the design. In Nicole’s project they were also able to significantly reduce the amount of unused CSS and layouts once they had broken down the app into reusable components.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://trulia.github.io/hologram/&#34;&gt;Hologram&lt;/a&gt; is an interesting tool to help with the creation of style guides which Nicole shared and is definitely worth checking out.&lt;/p&gt;
&lt;h3 id=&#34;sara-soueidan--styling-and-animating-scalable-vector-graphics-with-css&#34;&gt;Sara Soueidan — Styling and Animating Scalable Vector Graphics with CSS&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://sarasoueidan.com/&#34;&gt;Sara&lt;/a&gt; talked to us about using &lt;a href=&#34;https://en.wikipedia.org/wiki/Scalable_Vector_Graphics&#34;&gt;SVG&lt;/a&gt; with CSS and included some really neat demos. Adobe Illustrator, &lt;a href=&#34;https://inkscape.org/en/&#34;&gt;Inkscape&lt;/a&gt; and &lt;a href=&#34;https://bohemiancoding.com/sketch/&#34;&gt;Sketch 3&lt;/a&gt; are the commonly used tools used to create SVG images. Once you have your SVG image you can use the &lt;a href=&#34;https://web.archive.org/web/20150218125407/http://petercollingridge.appspot.com/svg-editor&#34;&gt;SVG Editor&lt;/a&gt; by Peter Collingridge or &lt;a href=&#34;https://github.com/svg/svgo&#34;&gt;SVGO&lt;/a&gt; (node.js based tool) to clean up and optimize the SVG code. After the cleanup and optimization you can replace the generic CSS class names from your SVG creation app with more semantic CSS class names.&lt;/p&gt;
&lt;p&gt;There are a variety of ways to include SVG on a page and Sara went over the pros and cons of each. The method that seemed most interesting to me was to use an &lt;code&gt;&amp;lt;object&amp;gt;&lt;/code&gt; tag which allowed for a fallback image for browsers that do not support SVG. Sara mapped out the subset of CSS selectors which can be used to target SVG elements, how to “responsify” SVGs and to animate SVG paths. Be sure to check out &lt;a href=&#34;https://docs.google.com/presentation/d/1Iuvf3saPCJepVJBDNNDSmSsA0_rwtRYehSmmSSLYFVQ/present#slide=id.p&#34;&gt;her slides&lt;/a&gt; from the talk.&lt;/p&gt;
&lt;h3 id=&#34;lea-verou--the-chroma-zone-engineering-color-on-the-web&#34;&gt;Lea Verou — The Chroma Zone: Engineering Color on the Web&lt;/h3&gt;
&lt;p&gt;Lea’s talk was about color on the web. She detailed the history of how color has been handled up to this point, how it works today and some of the interesting color-related CSS features which are coming in the future. She demonstrated how each of the color spaces have a geographical representation (e.g. RGB can be represented as a cube and HSL as a double-cone) which I found neat. RGB is very unintuitive when it comes to choosing colors. HSL is much more intuitive but has some challenges of its own. The new and shiny CSS color features Lea talked about included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;filters&lt;/li&gt;
&lt;li&gt;blending modes&lt;/li&gt;
&lt;li&gt;CSS variables&lt;/li&gt;
&lt;li&gt;gray()&lt;/li&gt;
&lt;li&gt;color() including tint, shade and other adjusters&lt;/li&gt;
&lt;li&gt;the #rgba and #rrggbbaa notation&lt;/li&gt;
&lt;li&gt;hwb()&lt;/li&gt;
&lt;li&gt;named hues and &lt;angle&gt; in hsl()&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of these new features can be used already via libs like &lt;a href=&#34;https://www.bourbon.io/&#34;&gt;Bourbon&lt;/a&gt; and &lt;a href=&#34;http://www.myth.io/&#34;&gt;Myth&lt;/a&gt;. Check out the &lt;a href=&#34;http://leaverou.github.io/chroma-zone/&#34;&gt;Chroma Zone: Engineering Color on the Web&lt;/a&gt; slides to learn more.&lt;/p&gt;
&lt;h3 id=&#34;c&#34;&gt;C$$&lt;/h3&gt;
&lt;p&gt;I will write up more of the talks soon but wanted to thank &lt;a href=&#34;https://web.archive.org/web/20140207090237/http://madeby.jennschiffer.com/&#34;&gt;Jenn Schiffer&lt;/a&gt; for keeping us all laughing throughout the day in her role as MC and topping it off with a hilarious, satirical talk of her own. Thanks also to &lt;a href=&#34;https://alexsexton.com/&#34;&gt;Alex&lt;/a&gt; and &lt;a href=&#34;http://ajpiano.com/&#34;&gt;Adam&lt;/a&gt; for curating the music and looking after the sound.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Fixed Navigation Bar: HTML, CSS, and JavaScript Breakdown</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/09/fixed-navigation-bar-html-css-and/"/>
      <id>https://www.endpointdev.com/blog/2013/09/fixed-navigation-bar-html-css-and/</id>
      <published>2013-09-02T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;Something that I’ve seen frequently these days on content rich sites are fixed navigation bars, or small abbreviated header in the form of a horizontal bar at the top of the screen that shows after a user has scrolled below the header. Here’s an example:&lt;/p&gt;
&lt;p&gt;&lt;img border=&#34;0&#34; src=&#34;/blog/2013/09/fixed-navigation-bar-html-css-and/image-0.png&#34; width=&#34;740px;&#34;/&gt;&lt;br&gt;
A live example of an abbreviated fixed navigation bar at the top of the articles at &lt;a href=&#34;http://abcnews.go.com/&#34;&gt;ABCNews.com&lt;/a&gt;. The background has a grey opaque layer for demonstration purposes only.&lt;/p&gt;
&lt;p&gt;I recently implemented this functionality for &lt;a href=&#34;http://cyber.law.harvard.edu/research/h2o&#34;&gt;H2O&lt;/a&gt;, and I’ll go through the tools needed to do this.&lt;/p&gt;
&lt;h3 id=&#34;html-markup&#34;&gt;HTML Markup&lt;/h3&gt;
&lt;p&gt;First thing’s first, you need the HTML markup for this. The only tricky thing here is that the horizontal bar must be outside of any wrapping dividers on the page that are confining the content to a set width. For example, if your content is limited to 900 pixels in width, the horizontal bar markup must be outside that constraint. Here’s what the HTML might look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;id&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;fixed_bar&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt; &lt;span style=&#34;color:#369&#34;&gt;class&lt;/span&gt;=&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;wrapper&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Links &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;&amp;amp;&lt;/span&gt; content here.
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note that in the above HTML, the “wrapper” div may be constraining the content width to match the remaining content, such as in the example above. This HTML may go at the beginning or end of the page HTML. I prefer to see it at the top of the page HTML. Another note is that other HTML elements may be used in place of the div, but I chose the div above because it defaults to a block element (an element where the CSS display default value is block).Finally, one more note here is that HTML5 elements can be used in place of the div as well (section or nav might make sense) if the site is HTML5 compliant.&lt;/p&gt;
&lt;h3 id=&#34;css-settings&#34;&gt;CSS Settings&lt;/h3&gt;
&lt;p&gt;The secret to this interactive feature lies in the CSS settings. Here’s what the CSS for my example code above might look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;body&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;padding&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;fixed_bar&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;%&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;position&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;fixed&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;z-index&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;//exceed&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;z-index&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;of&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;other&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;elements&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;on&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;the&lt;/span&gt; &lt;span style=&#34;color:#a61717;background-color:#e3d2d2&#34;&gt;page&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;none&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;transparent&lt;/span&gt; &lt;span style=&#34;color:#038&#34;&gt;url&lt;/span&gt;(&lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;/images/fixed_bar.png&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;bottom&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;repeat-x&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;top&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;wrapper&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;width&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;900&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;margin&lt;/span&gt;: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;auto&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here are the important bits of the CSS above:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The fixed positioning setting is what keeps the bar in one place as the user scrolls up and down (line 7).&lt;/li&gt;
&lt;li&gt;The body must have margin and padding settings at 0px to ensure that the fixed bar is flush against the top of the screen (line 2 &amp;amp; 3).&lt;/li&gt;
&lt;li&gt;The fixed bar spans the width of the browser, but in this case, the .wrapper element is constrained to 900 pixels wide (line 14).&lt;/li&gt;
&lt;li&gt;The default state of the #fixed_bar element is none, which is hidden upon page load (line 9).&lt;/li&gt;
&lt;li&gt;The background of the #fixed_bar can be a small image with a gradient to transparency, such as in the example above (line 10).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;scroll-event-listener&#34;&gt;Scroll Event Listener&lt;/h3&gt;
&lt;p&gt;Finally, after the HTML and CSS markup is good to go, here’s what the interactive JavaScript (via jQuery) might look like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; offset = &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;; &lt;span style=&#34;color:#888&#34;&gt;// some offset value for which when the header becomes hidden
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;jQuery(&lt;span style=&#34;color:#038&#34;&gt;window&lt;/span&gt;).scroll(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;() { &lt;span style=&#34;color:#888&#34;&gt;//also an option: jQuery .on(&amp;#39;scroll&amp;#39;) method
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt;(jQuery(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#fixed_bar&amp;#39;&lt;/span&gt;).is(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;:visible&amp;#39;&lt;/span&gt;) &amp;amp;&amp;amp; jQuery(&lt;span style=&#34;color:#038&#34;&gt;window&lt;/span&gt;).scrollTop() &amp;lt; offset) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    jQuery(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#fixed_bar&amp;#39;&lt;/span&gt;).fadeOut(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt;(!jQuery(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#fixed_bar&amp;#39;&lt;/span&gt;).is(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;:visible&amp;#39;&lt;/span&gt;) &amp;amp;&amp;amp; jQuery(&lt;span style=&#34;color:#038&#34;&gt;window&lt;/span&gt;).scrollTop() &amp;gt; offset) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    jQuery(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#fixed_bar&amp;#39;&lt;/span&gt;).fadeIn(&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The jQuery above checks for two scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a) If the #fixed_bar div is visible and the scroll position is less than the offset, fade the #fixed_bar div to a hidden state.&lt;/li&gt;
&lt;li&gt;b) If the #fixed_bar div is not visible and the scroll position is greater than the offset, fade the #fixed_bar div to a visible state.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These two use cases will toggle the visibility of the fixed bar to a hidden and visible state. With these combined elements of HTML, CSS, and jQuery &amp;amp; JavaScript, a nice user interactivity feature adds to the usability of the site by providing valuable links and content as the user scrolls down the page.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>JSConf US 2013 — Day One</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/06/jsconf-us-day-one/"/>
      <id>https://www.endpointdev.com/blog/2013/06/jsconf-us-day-one/</id>
      <published>2013-06-04T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;a href=&#34;https://www.flickr.com/photos/geigercounter/8951325076/&#34; title=&#34;Room With A View by Geiger Counter, on Flickr&#34;&gt;&lt;img alt=&#34;Room With A View&#34; height=&#34;217&#34; src=&#34;/blog/2013/06/jsconf-us-day-one/image-0.jpeg&#34; width=&#34;640&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I attended JSConf in Amelia Island, FL last week. As you can see, the venue was pretty spectacular and the somewhat remote location lent itself very well to the vision set by the conference organizers. Many developers myself included, often find the line between work and play blurring because there is much work to be done, many new open source projects to check out, constant advancements in browser technology, programming languages, you name it. Keeping up with it all is fun but can be challenging at times. While the talks were amazing, the focus and ethos of JSConf as I experienced it was more about people and building on the incredible community we have. I highly recommend attending meetups or conferences in your field if possible.&lt;/p&gt;
&lt;p&gt;Without further ado, I’ve written about some of the talks I attended. Enjoy!&lt;/p&gt;
&lt;h3 id=&#34;day-one&#34;&gt;Day One&lt;/h3&gt;
&lt;h4 id=&#34;experimenting-with-webrtc&#34;&gt;Experimenting With WebRTC&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://remysharp.com/&#34;&gt;Remy Sharp&lt;/a&gt; presented the first talk of the day about his experience building a &lt;a href=&#34;https://experiments.withgoogle.com/collection/chrome&#34;&gt;Google Chrome Experiment&lt;/a&gt; with WebRTC and the peer to peer communication API. The game (&lt;a href=&#34;https://web.archive.org/web/20130816024030/https://headshots.leftlogic.com/&#34;&gt;headshots&lt;/a&gt;), was built to work specifically on Chrome for Android Beta. Because WebRTC is so young, the libraries supporting it (Peer.js, easyRTC, WebRTC.io, SimpleWebRTC) are very young as well and developing quickly. He found that “Libraries are good when you’re fumbling, bad when stuff doesn’t work”. The “newness” of WebRTC ate much more time than he had anticipated. Remi demoed the game and it looked like good fun. If you’re interested in checking out headshots further, the &lt;a href=&#34;https://github.com/leftlogic/headshots&#34;&gt;source code&lt;/a&gt; is up on GitHub.&lt;/p&gt;
&lt;h4 id=&#34;javascript-masterclass&#34;&gt;JavaScript Masterclass&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;https://twitter.com/angelinamagnum&#34;&gt;Angelina Fabbro&lt;/a&gt; gave a talk about levelling up your skills as a developer. She first broke everyone’s heart by telling us “we’re not special” and that nobody is a natural born programmer. She presented some data (studies etc) to support her point and argued that early exposure to the practice of logical thinking and practicing programming can make you seem like a natural.&lt;/p&gt;
&lt;p&gt;She described several ways to know you’re not a beginner:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can use the fundamentals in any language&lt;/li&gt;
&lt;li&gt;You are comfortable writing code from scratch&lt;/li&gt;
&lt;li&gt;You peek inside the libraries you use&lt;/li&gt;
&lt;li&gt;You feel like your code is mediocre and you’re unsure what to do about it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip;and ways to know you’re not an expert:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You don’t quite grok (understand) all the code you read&lt;/li&gt;
&lt;li&gt;You can’t explain what you know&lt;/li&gt;
&lt;li&gt;You aren’t confident debugging&lt;/li&gt;
&lt;li&gt;You rely on references/docs too much&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;“Welcome to the ambiguous zone of intermediate-ness”.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Angelina suggested several ways to improve your skills. Ask “why?” obsessively, teach or speak at an event, work through a suggested curriculum, have opinions, seek mentorship, write in another language for a while etc. One book she specifically recommended was Secrets of the JavaScript Ninja by John Resig.&lt;/p&gt;
&lt;h4 id=&#34;javascript-is-literature-is-javascript&#34;&gt;JavaScript is Literature is JavaScript&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;http://anguscroll.com/&#34;&gt;Angus Croll&lt;/a&gt; from Twitter presented a hilariously entertaining talk in which he refactored some JavaScript functions in the literary styles of Hemingway, Shakespeare, Bolaño, Kerouac, James Joyce and other literary figures. The talk was inspired by a &lt;a href=&#34;http://byfat.xxx/if-hemingway-wrote-javascript&#34;&gt;blog post&lt;/a&gt; he’d written and had the entire conference hall erupting with laughter throughout.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.flickr.com/photos/geigercounter/8950136537/&#34; title=&#34;poolside.js by Geiger Counter, on Flickr&#34;&gt;&lt;img alt=&#34;poolside.js&#34; height=&#34;500&#34; src=&#34;/blog/2013/06/jsconf-us-day-one/image-0.jpeg&#34; width=&#34;375&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&#34;learning-new-words&#34;&gt;Learning New Words&lt;/h4&gt;
&lt;p&gt;&lt;a href=&#34;http://andrewdupont.net/&#34;&gt;Andrew Dupont&lt;/a&gt; continued in the literary, language-oriented vein, giving a talk which drew a parallel between olde english purists who did not want to adopt any “new” words and the differing views surrounding the EcmaScript 6 specification process. Dupont’s talk was very thought-provoking especially in light of the resistance to some proposals in the works (e.g. &lt;a href=&#34;https://web.archive.org/web/20130820143217/http://wiki.ecmascript.org/doku.php?id=harmony:modules&#34;&gt;ES6 modules&lt;/a&gt;). Check out &lt;a href=&#34;https://www.slideshare.net/savetheclocktower/learning-new-words-22244915&#34;&gt;his slides&lt;/a&gt;—​the video will also be published in future.&lt;/p&gt;
&lt;h4 id=&#34;flightjs&#34;&gt;Flight.js&lt;/h4&gt;
&lt;img alt=&#34;Flight twitter&#34; border=&#34;0&#34; height=&#34;258&#34; src=&#34;/blog/2013/06/jsconf-us-day-one/image-2.png&#34; style=&#34;display:block; margin-left:auto; margin-right:auto;&#34; title=&#34;flight-twitter.png&#34; width=&#34;375&#34;/&gt; 
&lt;p&gt;&lt;a href=&#34;https://twitter.com/danwrong&#34;&gt;Dan Webb&lt;/a&gt; spoke about &lt;a href=&#34;https://web.archive.org/web/20130520095336/http://twitter.github.io/flight/&#34;&gt;Flight&lt;/a&gt;, a client-side framework developed by the team at Twitter and released this past January. They have been using it to run lots of twitter.com and most of tweetdeck as well. Webb got a laugh out of the room when he recalled the first comment on Hacker News after &lt;a href=&#34;https://web.archive.org/web/20130518044937/http://engineering.twitter.com/2013/01/introducing-flight-web-application.html&#34;&gt;Flight was announced&lt;/a&gt;: “Why not use &lt;a href=&#34;https://angularjs.org/&#34;&gt;Angular&lt;/a&gt;?”. The motivation behind Flight’s design was to make a “system that’s easy to think about”. This aim was achieved by decoupling components (entirely self-contained).&lt;/p&gt;
&lt;p&gt;A Flight component is just a JavaScript object with a reference to a DOM node. The component can be manipulated, trigger events and listen to events (from other components). Applications are constructed by attaching Flight components to pieces of the DOM. Keeping the components independent in this way makes testing very easy. Complexity can be layered on but does not require any additional mental overhead. Dan suggested that Flight’s design and architecture would work very well with Web Components and &lt;a href=&#34;https://polymer-project.appspot.com/&#34;&gt;Polymer&lt;/a&gt; in future.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSS Conf 2013 — When Bootstrap Attacks!</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/06/css-conf-2013-when-bootstrap-attacks/"/>
      <id>https://www.endpointdev.com/blog/2013/06/css-conf-2013-when-bootstrap-attacks/</id>
      <published>2013-06-03T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;img alt=&#34;Cssconf 2013&#34; border=&#34;0&#34; height=&#34;234&#34; src=&#34;/blog/2013/06/css-conf-2013-when-bootstrap-attacks/image-0.png&#34; style=&#34;display:block; margin-left:auto; margin-right:auto;&#34; title=&#34;cssconf-2013.png&#34; width=&#34;373&#34;/&gt;
&lt;p&gt;I attended the inaugural &lt;a href=&#34;https://web.archive.org/web/20130629170825/http://cssconf.com/speakers.html&#34;&gt;CSS Conf&lt;/a&gt; last week at Amelia Island, Florida. The conference was organized by &lt;a href=&#34;http://www.stubbornella.org/&#34;&gt;Nicole Sullivan&lt;/a&gt;, &lt;a href=&#34;http://brett.stimmerman.com/&#34;&gt;Brett Stimmerman&lt;/a&gt;, &lt;a href=&#34;https://snook.ca/&#34;&gt;Jonathan Snook&lt;/a&gt;, and &lt;a href=&#34;https://www.paulirish.com/&#34;&gt;Paul Irish&lt;/a&gt; and put on with help from a host of volunteers. The talks were presented in a single track style on a wide range of CSS-related topics; there was something interesting for everyone working in this space. I really enjoyed the conference, learned lots and had great discussions with a variety of people hacking on interesting things with CSS. In the coming days I will be blogging about some of the talks I attended and sharing what I learned, so stay tuned!&lt;/p&gt;
&lt;h3 id=&#34;when-bootstrap-attacks&#34;&gt;When Bootstrap Attacks&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;http://www.pamelafox.org/&#34;&gt;Pamela Fox&lt;/a&gt; had the opening slot and spoke about the experiences and challenges she faced when upgrading &lt;a href=&#34;https://getbootstrap.com/2.3.2/&#34;&gt;Bootstrap&lt;/a&gt; to V2 in a large web app (&lt;a href=&#34;https://www.coursera.org/&#34;&gt;Coursera&lt;/a&gt;). What she initially thought would be a quick project turned into a month-long “BOOTSTRAPV2ATHON”. Bootstrap styles were used throughout the project in dozens of PHP, CSS and JavaScript files. The fact that Bootstrap uses generic CSS class names like “alert”, “btn”, error etc made it very difficult to grep through the codebase for them. The Bootstrap classes were also used as hooks by the project’s JavaScript application code.&lt;/p&gt;
&lt;h3 id=&#34;lessons-learned&#34;&gt;Lessons Learned&lt;/h3&gt;
&lt;p&gt;Fox offered some tips for developers facing a similar situation. The first of which was to prefix the Bootstrap CSS classes (e.g. .tbs-alert) in order to decouple Bootstrap from the customizations in your project. Some requests have been made to the Bootstrap team on this front but the issue has not been addressed yet. In the meantime, devs can add a task to their build step (e.g. &lt;a href=&#34;https://gruntjs.com/&#34;&gt;Grunt&lt;/a&gt;, the asset pipeline in Rails etc) to automate the addition of prefixes to each of the CSS classes.&lt;/p&gt;
&lt;p&gt;Another tip is to avoid using Bootstrap CSS classes directly. Instead, use the “extend” functionality in your preprocessor (Sass, Less, Stylus etc) of choice. For example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  .ep-btn {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    @extend .btn
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;amp;:hover {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          @extend .btn:hover
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This way your project can extend the Bootstrap styles but keep your customizations separate and not closely coupled to the framework.&lt;/p&gt;
&lt;p&gt;The same logic should also be applied to the JavaScript in your project. Rather than using the Bootstrap class names as hooks in your JavaScript code, use a prefix (e.g. js-btn) or use HTML5 data attributes. Separating the hooks used for CSS styles from those used in JavaScript is very helpful when upgrading or swapping out a client-side framework like Bootstrap.&lt;/p&gt;
&lt;h3 id=&#34;test-all-of-the-things&#34;&gt;Test All Of The Things&lt;/h3&gt;
&lt;p&gt;Pamela wrapped up the talk by explaining how testing front end code would ease the pain of upgrading a library next time. There are many testing libraries available today which address some of these concerns. She mentioned &lt;a href=&#34;https://mochajs.org/&#34;&gt;mocha&lt;/a&gt;, &lt;a href=&#34;http://www.chaijs.com/&#34;&gt;Chai&lt;/a&gt;, &lt;a href=&#34;https://github.com/jsdom/jsdom&#34;&gt;jsdom&lt;/a&gt; and &lt;a href=&#34;https://docs.seleniumhq.org/&#34;&gt;Selenium&lt;/a&gt; which all look very helpful. In addition to testing front end code she offered up the idea of “diffing your front end” in a visual way. This concept was very interesting to someone who ensures designs are consistent across a wide array of browsers and devices on a daily basis.
&lt;img alt=&#34;Diff your front end&#34; border=&#34;0&#34; height=&#34;341&#34; src=&#34;/blog/2013/06/css-conf-2013-when-bootstrap-attacks/image-1.png&#34; style=&#34;display:block; margin-left:auto; margin-right:auto;&#34; title=&#34;diff-your-front-end.png&#34; width=&#34;559&#34;/&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/python-needle/needle&#34;&gt;Needle&lt;/a&gt; is a tool which allows you to do this &lt;em&gt;automatically&lt;/em&gt;. Once you develop a test case, you can run Needle to view a visual diff of your CSS changes. I think this is an excellent idea. Pamela also noted that the combination of &lt;a href=&#34;https://support.mozilla.org/en-US/questions/940991&#34;&gt;Firefox screenshots&lt;/a&gt; and &lt;a href=&#34;https://www.kaleidoscopeapp.com/&#34;&gt;Kaleidoscope&lt;/a&gt; could be used manually in much the same way.&lt;/p&gt;
&lt;p&gt;Many thanks to &lt;a href=&#34;https://twitter.com/pamelafox&#34;&gt;Pamela&lt;/a&gt; for sharing this! The slides for this talk can be viewed &lt;a href=&#34;http://slides.com/pamelafox/when-bootstrap-attacks#/&#34;&gt;here&lt;/a&gt; and the talk was recorded so the video will also be available sometime soon.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Ghost Table Cells in IE9</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/02/ghost-table-cells-in-ie9/"/>
      <id>https://www.endpointdev.com/blog/2013/02/ghost-table-cells-in-ie9/</id>
      <published>2013-02-08T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;h3 id=&#34;whats-this-about-ghosts&#34;&gt;What’s this about ghosts?&lt;/h3&gt;
&lt;p&gt;I recently came across an arcane layout issue in my work on a redesigned client site. The problem was specific to Internet Explorer 9 (IE9). The related CSS styles had been well tested and rendered consistently across a variety of browsers including IE7 and 8. Everything was fine and dandy until some new content was introduced into the page for a &amp;ldquo;Quickview&amp;rdquo; feature. While all of the other browsers continued to behave and render the page correctly, the layout would break in random and confusing ways in IE9.&lt;/p&gt;
&lt;p&gt;The following screenshots compare the correct layout with an example of the broken layout in IE9.&lt;/p&gt;
&lt;h3 id=&#34;correct-grid-layout&#34;&gt;Correct grid layout:&lt;/h3&gt;
&lt;img alt=&#34;Correct grid&#34; border=&#34;0&#34; height=&#34;323&#34; src=&#34;/blog/2013/02/ghost-table-cells-in-ie9/image-0.png&#34; title=&#34;correct-grid.png&#34; /&gt;
&lt;h3 id=&#34;broken-layout-in-ie9&#34;&gt;Broken layout in IE9:&lt;/h3&gt;
&lt;img alt=&#34;IE9 ghost cells&#34; border=&#34;0&#34; height=&#34;325&#34; src=&#34;/blog/2013/02/ghost-table-cells-in-ie9/image-1.png&#34; title=&#34;IE9-ghost-cells.png&#34; /&gt;
&lt;h3 id=&#34;the-stage&#34;&gt;The Stage&lt;/h3&gt;
&lt;p&gt;The following is a list of the factors at work on the page in question:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Internet Explorer 9&lt;/li&gt;
&lt;li&gt;Browser mode: IE9, Document mode: IE9 standards&lt;/li&gt;
&lt;li&gt;Some content manipulation performed via JavaScript (and jQuery in this case)&lt;/li&gt;
&lt;li&gt;Lots of table cells&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;debugging&#34;&gt;Debugging&lt;/h3&gt;
&lt;p&gt;The page included a list of products. The first “page” of twelve results was shown initially while JavaScript split the rest of the list into several additional pages. Once this JavaScript pagination function was complete, users could cycle through products in bite-sized pieces.&lt;/p&gt;
&lt;p&gt;My first thought was that the issue may be related to CSS or JavaScript. I tested and debugged the styles thoroughly, tweaked styles and edited the underlying HTML structure to see if that might resolve the problem. I also tested the JavaScript and compared the original HTML with the parts which had been paginated via JavaScript. No dice.&lt;/p&gt;
&lt;p&gt;When changes improved the paginated HTML, the bug appeared in the initial HTML. Other changes resolved the issue in the original HTML but it appeared in the paginated HTML.&lt;/p&gt;
&lt;p&gt;I inspected the table with the Chrome Developer Tools console and also with the Developer Tools in IE9. There did not appear to be any differences between the rows which rendered properly and those which were skewed.&lt;/p&gt;
&lt;h3 id=&#34;bugging-out&#34;&gt;Bugging Out&lt;/h3&gt;
&lt;p&gt;At this point I began to research the issue and discovered it was a bug in the IE9 browser. A Microsoft forum post described the issue and included responses from Microsoft stating that it will not be fixed. It also included a sample application which demonstrated the issue. I tested and verified that the problem has been addressed and fixed in Internet Explorer 10, thankfully.&lt;/p&gt;
&lt;p&gt;This explained the many, seemingly random ways I had seen the grid break. At times the cells were squished and pushed to the left. This was because the ghost cell had been added at the end of a row. Other times the cells were shifted to the right (as seen in the screenshot above). In this case, the ghost cell had been added to the middle of a row.&lt;/p&gt;
&lt;h3 id=&#34;the-fix&#34;&gt;The Fix&lt;/h3&gt;
&lt;p&gt;Further digging revealed the the issue was related to whitespace between table cells. The solution was fairly simple: use a regular expression to remove all whitespace between the table elements:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;#problem-table&amp;#39;&lt;/span&gt;).html(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(i, el) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; el.replace(&lt;span style=&#34;color:#080;background-color:#fff0ff&#34;&gt;/&amp;gt;\s+&amp;lt;/g&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;gt;&amp;lt;&amp;#39;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With all of the whitespace removed from the affected &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;, IE9 rendered the page correctly.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>CSS sprites: The easy way?</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/01/css-sprites-easy-way/"/>
      <id>https://www.endpointdev.com/blog/2013/01/css-sprites-easy-way/</id>
      <published>2013-01-21T00:00:00+00:00</published>
      <author>
        <name>Richard Templet</name>
      </author>
      <content type="html">
        &lt;p&gt;I’ve always been interested in the use of CSS sprites to speed up page load times. I haven’t had a real chance to use them yet but my initial reaction was that sprites would be quite painful to maintain. In my mind, you would have to load up the sprite into Gimp or Photoshop, add the new image and then create the css with the right coordinates to display the image. Being a guy with very little image editing skills, I felt that managing multiple images frequently would be quite time consuming. Recently, I was dealing with some page load times for a client and the use of sprites for the product listing pages came up as an option to speed them up. I knew the client wouldn’t have time to create sprites for this so I went searching for a command line tool that would allow me to create sprites. I was quite happy when I stumbled upon &lt;a href=&#34;https://glue.readthedocs.org/en/latest/index.html&#34;&gt;Glue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Glue is free program that will take a directory of images and create a png sprite and a css file with the associated CSS classes. It has a ton of useful options. A few of the ones I thought were handy was being able to prefix the path to the image with a url instead of a relative path, being able to downgrade the png format to png8 to make the file sizes much smaller and being able to specify the start of the name of the class with something to help with being able to use them on a dynamic page.&lt;/p&gt;
&lt;p&gt;The most basic use of the command is as follows:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;glue blog output&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this example, blog is the directory where the images live that you want Glue to create a sprite of and output is the directory where it will generate the blog.png and blog.css file.&lt;/p&gt;
&lt;p&gt;The output css file looks like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;/* glue: 0.2.9.1 hash: f9c9d6aa5b */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sprite-blog-product2&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sprite-blog-product1&lt;/span&gt;{&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-image&lt;/span&gt;:&lt;span style=&#34;color:#038&#34;&gt;url&lt;/span&gt;(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;blog.png&amp;#39;&lt;/span&gt;);&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-repeat&lt;/span&gt;:&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;no-repeat&lt;/span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sprite-blog-product2&lt;/span&gt;{&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-position&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;width&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;159&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;height&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;sprite-blog-product1&lt;/span&gt;{&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-position&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;-159&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;width&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;height&lt;/span&gt;:&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;168&lt;/span&gt;&lt;span style=&#34;color:#888;font-weight:bold&#34;&gt;px&lt;/span&gt;;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The naming convention by default is sprite-$input_directory-$filename.  You can override this with a few options. The version number and hash are used by Glue to ensure it doesn’t rebuild the sprite if none of the source images have changed.  With these settings, I believe this could be a great program to run as a nightly routine to rebuild the sprites.  This is the explanation from the documentation:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;By default glue store some metadata inside the generated sprites in order to not
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rebuild it again if the source images and settings are the same. Glue set two different
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;keys, glue with the version number the sprite was build and hash, generated using the 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source images data, name and all the relevant sprite settings like padding, margin 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;etc...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I’m still tinkering with all the different options and thinking about how to include the use of this program in our work flow for this client.  I’ll make sure to write a follow up with more information as I learn more.&lt;/p&gt;
&lt;p&gt;If you have a different command line tool which helps manage sprites, don’t hesitate to leave a comment and let me know!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Keeping Your Apps Neat &amp; Tidy With RequireJS</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/05/keeping-your-apps-neat-tidy-with/"/>
      <id>https://www.endpointdev.com/blog/2012/05/keeping-your-apps-neat-tidy-with/</id>
      <published>2012-05-17T00:00:00+00:00</published>
      <author>
        <name>Greg Davidson</name>
      </author>
      <content type="html">
        &lt;p&gt;&lt;a href=&#34;http://requirejs.org/&#34;&gt;RequireJS&lt;/a&gt; is a very handy tool for loading files and modules in JavaScript. A short time ago I used it to add a feature to &lt;a href=&#34;http://www.whiskeymilitia.com/&#34;&gt;Whiskey Militia&lt;/a&gt; that promoted a new section of the site. By developing the feature as a RequireJS module, I was able to keep all of its JavaScript, HTML and CSS files neatly organized. Another benefit to this approach was the ability to turn the new feature “on” or “off” on the site by editing a single line of code. In this post I’ll run through a similar example to demonstrate how you could use RequireJS to improve your next project.&lt;/p&gt;
&lt;h3 id=&#34;file-structure&#34;&gt;File Structure&lt;/h3&gt;
&lt;p&gt;The following is the file structure I used for this project:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── index.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── scripts
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── main.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── my
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   ├── module.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   ├── styles.css
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    │   └── template.html
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── require-jquery.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ├── requirejs.mustache.js
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    └── text.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The dependencies included RequireJS bundled together with &lt;a href=&#34;https://jquery.com/&#34;&gt;jQuery&lt;/a&gt;, &lt;a href=&#34;https://github.com/janl/mustache.js/&#34;&gt;mustache.js&lt;/a&gt; for templates and the RequireJS &lt;a href=&#34;http://requirejs.org/docs/download.html#text&#34;&gt;text plugin&lt;/a&gt; to include my HTML template file.&lt;/p&gt;
&lt;h3 id=&#34;configuration&#34;&gt;Configuration&lt;/h3&gt;
&lt;p&gt;RequireJS is included in the page with a script tag and the data-main attribute is used to specify additional files to load. In this case “scripts/main” tells RequireJS to load the main.js file that resides in the scripts directory. Require will load the specified files asynchronously. This is what index.html looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;html&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;head&amp;gt;&amp;lt;br/&amp;gt;    &amp;lt;title&amp;gt;RequireJS Example&amp;lt;/title&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;body&amp;gt;&amp;lt;br/&amp;gt;    &amp;lt;h1&amp;gt;RequireJS Example&amp;lt;/h1&amp;gt;&amp;lt;br/&amp;gt;    &amp;lt;!-- This is a special version of jQuery with RequireJS built-in --&amp;gt;&amp;lt;br/&amp;gt;    &amp;lt;script data-main=&amp;#34;scripts/main&amp;#34; src=&amp;#34;scripts/require-jquery.js&amp;#34;&amp;gt;&amp;lt;/script&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;br/&amp;gt;&amp;lt;/html&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I was a little skeptical of this approach working on older versions of Internet Explorer so I tested it quickly with IE6 and confirmed that it did indeed work just fine.&lt;/p&gt;
&lt;h3 id=&#34;creating-a-module&#34;&gt;Creating a Module&lt;/h3&gt;
&lt;p&gt;With this in place, we can create our module. The module definition begins with an array of dependencies:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;define([
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;require&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;jquery&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;requirejs.mustache&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text!my/template.html&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  ],&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This module depends on require, jQuery, mustache, and our mustache template. Next is the function declaration where our module’s code will live. The arguments specified allow us to map variable names to the dependencies listed earlier:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(require, $, mustache, html) { ... }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case we’re mapping the $ to jQuery, mustache to requirejs.mustache and, html to our template file.&lt;/p&gt;
&lt;p&gt;Inside the module we’re using Require’s .toUrl() function to grab a URL for our stylesheet. While it is possible to load CSS files asynchronously just like the other dependencies, there are some issues that arise that &lt;a href=&#34;http://requirejs.org/docs/faq-advanced.html#css&#34;&gt;are specific to CSS files&lt;/a&gt;. For our purposes it will be safer to just add a &lt;link&gt; element to the document like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; cssUrl = require.toUrl(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;./styles.css&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;head&amp;#39;&lt;/span&gt;).append($(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;&amp;lt;link/&amp;gt;&amp;#39;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { rel: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt;, media: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;all&amp;#34;&lt;/span&gt;, type: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;text/css&amp;#34;&lt;/span&gt;, href: cssUrl }));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, we define a view with some data for our Mustache template and render it.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; view = {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    products: [
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Apples&amp;#34;&lt;/span&gt;, price: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.29&lt;/span&gt;, unit: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;lb&amp;#39;&lt;/span&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Oranges&amp;#34;&lt;/span&gt;, price: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1.49&lt;/span&gt;, unit: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;lb&amp;#39;&lt;/span&gt;},
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { name: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;Kiwis&amp;#34;&lt;/span&gt;, price: &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0.33&lt;/span&gt;, unit: &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;each&amp;#39;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    ],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    soldByPound: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;(){
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;unit&amp;#39;&lt;/span&gt;] === &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;lb&amp;#39;&lt;/span&gt;) ? &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt; : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    soldByEach: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; (&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;this&lt;/span&gt;[&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;unit&amp;#39;&lt;/span&gt;] === &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;each&amp;#39;&lt;/span&gt;) ? &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;true&lt;/span&gt; : &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;false&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// render the Mustache template
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;var&lt;/span&gt; output = mustache.render(html, view);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#888&#34;&gt;// append to the HTML document
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;  $(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;body&amp;#39;&lt;/span&gt;).append(output);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;the-template&#34;&gt;The Template&lt;/h3&gt;
&lt;p&gt;I really like this approach because it allows me to keep my HTML, CSS and JavaScript separate and also lets me write my templates in HTML instead of long, messy JavaScript strings. This is what our template looks like:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;ul class=&amp;#34;hot-products&amp;#34;&amp;gt;&amp;lt;br/&amp;gt;  {{#products}}&amp;lt;br/&amp;gt;  &amp;lt;li class=&amp;#34;product&amp;#34;&amp;gt;&amp;lt;br/&amp;gt;    {{name}}: ${{price}} {{#soldByEach}}each{{/soldByEach}}{{#soldByPound}}per lb{{/soldByPound}}&amp;lt;br/&amp;gt;  &amp;lt;/li&amp;gt;&amp;lt;br/&amp;gt;  {{/products}}&amp;lt;br/&amp;gt;&amp;lt;/ul&amp;gt;&amp;lt;br/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;including-the-module&#34;&gt;Including the Module&lt;/h3&gt;
&lt;p&gt;To include our new module in the page, we simply add it to our main.js file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require([&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;jquery&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;my/module&amp;#34;&lt;/span&gt;], &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;($, module) {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;// jQuery and my/module have been loaded.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#888&#34;&gt;&lt;/span&gt;    $(&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;function&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When we view our page, we see that the template was was rendered and appended to the document:&lt;/p&gt;
&lt;img alt=&#34;Require rendered&#34; border=&#34;0&#34; height=&#34;370&#34; src=&#34;/blog/2012/05/keeping-your-apps-neat-tidy-with/image-0.png&#34; title=&#34;require-rendered.png&#34; width=&#34;600&#34;/&gt;
&lt;h3 id=&#34;optimizing-your-code-with-the-rjs-optimizer&#34;&gt;Optimizing Your Code With The r.js Optimizer&lt;/h3&gt;
&lt;p&gt;One disadvantage of keeping everything separate and using modules in this way is that it adds to the number of HTTP requests on the page. We can combat this by using the the &lt;a href=&#34;http://requirejs.org/docs/optimization.html&#34;&gt;RequireJS Optimizer&lt;/a&gt;. The r.js script can be used a part of a build process and runs on both &lt;a href=&#34;https://nodejs.org/en/&#34;&gt;node.js&lt;/a&gt; and &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino&#34;&gt;Rhino&lt;/a&gt;. The Optimizer script can minify some or all of your dependencies with &lt;a href=&#34;https://github.com/mishoo/UglifyJS&#34;&gt;UglifyJS&lt;/a&gt; or Google’s &lt;a href=&#34;https://developers.google.com/closure/compiler/&#34;&gt;Closure Compiler&lt;/a&gt; and will concatenate everything into a single JavaScript file to improve performance. By following the documentation I was able to create a simple build script for my project and build the project with the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-plain&#34; data-lang=&#34;plain&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;node ../../r.js -o app.build.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This executes the app.build.js script with Node. We can compare the development and built versions of the project with the Network tab in Chrome’s excellent &lt;a href=&#34;https://developers.google.com/web/tools/chrome-devtools/&#34;&gt;Developer Tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Development Version:&lt;/p&gt;
&lt;img alt=&#34;Webapp devel&#34; border=&#34;0&#34; height=&#34;357&#34; src=&#34;/blog/2012/05/keeping-your-apps-neat-tidy-with/image-1.png&#34; title=&#34;webapp-devel.png&#34; width=&#34;600&#34;/&gt;
&lt;p&gt;Optimized with the RequireJS r.js optmizer:&lt;/p&gt;
&lt;img alt=&#34;Webapp built&#34; border=&#34;0&#34; height=&#34;356&#34; src=&#34;/blog/2012/05/keeping-your-apps-neat-tidy-with/image-2.png&#34; title=&#34;webapp-built.png&#34; width=&#34;600&#34;/&gt;
&lt;p&gt;It’s great to be able to go from 8 HTTP requests and 360 KB in development mode to 4 HTTP requests and ~118 KB after by running a simple command with Node! I hope this post has been helpful and that you’ll check out RequireJS on your next project.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Three Things: Rails, JOIN tip, and Responsiveness</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/05/three-things-rails-join-tip-and/"/>
      <id>https://www.endpointdev.com/blog/2012/05/three-things-rails-join-tip-and/</id>
      <published>2012-05-11T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;Here’s another entry in my &lt;em&gt;Three Things&lt;/em&gt; series, where I share a few small tips I’ve picked up lately.&lt;/p&gt;
&lt;h3 id=&#34;1-rails-and-dramas&#34;&gt;1. Rails and Dramas&lt;/h3&gt;
&lt;p&gt;Sometimes I think that since Rails allows you write code efficiently, [a few] members of the Rails community have time to overdramatize incidents that otherwise would go relatively unnoticed :) Someone with a good sense of humor created &lt;a href=&#34;https://web.archive.org/web/20120531143155/http://rubydramas.com/&#34;&gt;this website&lt;/a&gt; to track these dramas. While it’s probably a waste of time to get caught up on the personal aspects of the drama, some of the dramas have interesting technical aspects which are fiercely defended.&lt;/p&gt;
&lt;h3 id=&#34;2-join-with-concat&#34;&gt;2. JOIN with concat&lt;/h3&gt;
&lt;p&gt;Recently I needed to perform a JOIN on a partial string match in MySQL. After some investigation, I found that I had use the CONCAT method in a conditional (in an implicit inner JOIN), which looked like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;SELECT&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;*&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;products&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;p,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;related_items&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;ri&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;WHERE&lt;/span&gt;&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;concat(p.sku,&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;%&amp;#39;&lt;/span&gt;)&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;=&lt;span style=&#34;color:#bbb&#34;&gt; &lt;/span&gt;ri.id&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In modern MVC frameworks with ORMs, databases are typically not designed to include data associations in this manner. However, in this situation, data returned from a third party service in a non-MVC, ORM-less application was only a substring of the original data. There may be alternative ways to perform this type of JOIN, and perhaps my fellow database experts will comment on the post with additional techniques ;)&lt;/p&gt;
&lt;h3 id=&#34;3-responsiveness&#34;&gt;3. Responsiveness&lt;/h3&gt;
&lt;p&gt;Responsive web design is all the rage lately from the increase in mobile web browsing and tablets. &lt;a href=&#34;http://mattkersley.com/responsive/&#34;&gt;Here&lt;/a&gt; is a fun tool that that the ecommerce director at &lt;a href=&#34;https://www.papersource.com/&#34;&gt;Paper Source&lt;/a&gt; pointed out to me recently. The website allows you to render a single URL at various widths for a quick review of the UI.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Firebug in Action: CSS Changes</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2012/03/video-firebug-action/"/>
      <id>https://www.endpointdev.com/blog/2012/03/video-firebug-action/</id>
      <published>2012-03-19T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;When I work with clients, I encourage them to use tools to improve efficiency for web development. Sometimes my clients want styling (CSS) adjustments like font-size, padding, or orientation changes, but they aren’t sure what they want before they’ve seen it applied to real content. I recommend embracing a tool such as &lt;a href=&#34;https://getfirebug.com/&#34;&gt;Firebug&lt;/a&gt; for examining temporary on-page CSS edits. Here’s a quick video that demonstrates Firebug in action as I try out a few adjustments to End Point’s home page.&lt;/p&gt;
&lt;iframe allowfullscreen=&#34;&#34; frameborder=&#34;0&#34; height=&#34;416&#34; mozallowfullscreen=&#34;&#34; src=&#34;https://player.vimeo.com/video/38756187?title=0&amp;byline=0&amp;portrait=0&#34; webkitallowfullscreen=&#34;&#34; style=&#34;width: 100%&#34;&gt;&lt;/iframe&gt;
&lt;p&gt;Some of the changes I test out in the video include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Font-color changes&lt;/li&gt;
&lt;li&gt;Deleting DOM elements&lt;/li&gt;
&lt;li&gt;Padding, margin adjustments&lt;/li&gt;
&lt;li&gt;Background color changes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Firebug offers a lot more functionality but the video covers interactive CSS changes only. Read more about Firebug’s features &lt;a href=&#34;https://getfirebug.com/&#34;&gt;here&lt;/a&gt;. Chrome has similar functionality with the Developer Tools included in the core software. There are similar tools in the other browsers, but I develop in Chrome or Firefox and I’m not familiar with them.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
